Click Function for Dynamic Content from JSON Array - json

I have a PHP file that serves up a JSON array populated from a MySQL database and is loaded into the DOM. This data is loaded via jQuery getJSON() method into the #navContent divide of the HTML document. This functions as planed.
At the very-bottom of the HTML doc, I have a click function that targets the #navItem div that was dynamically loaded into the DOM but this does not fire. I am assuming the <li ID = 'navItem'... isnt kept when the data is dynamically populated..??
What do I have wrong? For now, I just want all the divides that were dynamically created into the #navContent div to click thru to a URL.
<html>
. . .
<head>
. . .
<script type="text/javascript">
var ajaxLoader = '';
var container = "navItem";
var appendE = "navContent";
var dns = 'http://192.168.1.34';
var navContent = '/andaero/php/regulatory_list.php';
var bodyContent = '/wiki/index.php/Airworthiness_Directive #content';
<!-- ================ When Ready Do This ============================ -->
<!-- **************************************************************** -->
$(document).ready(function(){
loadNav(dns + navContent, container, appendE);//<- This gets loaded into the navContent<div
loadPage(dns + bodyContent, "bodyContent");
});
. . .
</script>
<body>
. . .
<div id="navScrollContainer" class="navContentPosition">
<div id="navContent" >
<li id="navItem" style="display: none;">
<h1 class="navH1"></h1>
<h2 class="navH2"></h2>
<p class="navP"></p>
<hr class="navHR" />
</li>
</div>
</div>
. . .
</body>
<!-- ================ Functions ===================================== -->
<!-- **************************************************************** -->
<script type="text/javascript">
/* --------------- Handle Pg Loading ----------------- */
function loadPage(url, pageName) {
$("#" + pageName).load(url, function(response){
// transition("#" + pageName, "fade", false);
});
};
function loadNav(url, container, appendE) {
$.getJSON(url, function(data){
$.each(data.items, function(){
var newItem = $('#' + container).clone();
// Now fill in the fields with the data
newItem.find("h1").text(this.label);
newItem.find("h2").text(this.title);
newItem.find("p").text(this.description);
// And add the new list item to the page
newItem.children().appendTo('#' + appendE)
});
$('#navHeaderTitle').text(data.key);
//transition("#" + pageName, "show");
});
$('#navItem').click(function(e){ //<-- THIS IS BROKE!! HELP!!
e.preventDefault();
$('#bodyContent').load('www.google.com');
});
};
</scrip>
</html>
============ EDIT ================
I tried everything that was sugested with no prevail. I ended up using the code Shyju answered with but one modification to get it to work: As per the docs,
.on( events [, selector] [, data], handler(eventObject) ), I changed [,data] from the tag ID to just the tag type. ie: a. This function now since I wrapped the whole with the tag. See bellow:
Changed HTML to:
<div id="navScrollContainer" class="navContentPosition">
<div id="navContent" >
<li id="navItem" style="display: none;">
<a> //<-- ADDED THIS TAG WRAPPER!!
<h1 class="navH1"></h1>
<h2 class="navH2"></h2>
<p class="navP"></p>
<hr class="navHR" />
</a>
</li>
</div>
</div
Changed the Function to (Note that .on() allows a click event on any TAG element--even new ones--since the event is handled by the ever-present previous element after it bubbles to there.:
$('#navContent').on('click', 'a', function(e){//<--CHANGED DATA TO 'a'
e.preventDefault();
$('#bodyContent').load('http://www.google.com');
});

for dynamic content, you should use jquery on.
http://api.jquery.com/on/
So your code should look like this
$("#navScrollContainer").on("click","#navItem").click(function(e){
e.preventDefault();
$('#bodyContent').load('www.google.com');
});
But i guess you should not use the id selector for click event, because ids will (And should) be unique for an element. So when you load new content, the id will be different i believe. Probably you can use class name which is common for all those elements to be clicked.
on method is availabe from jQuery 1.7 version only. If you are using a previous version, you should use live as Niyaz mentioned.
http://api.jquery.com/live/

Instead of:
$('#navItem').click(function(){});
try using:
$('#navItem').live('click', function(){}); // jQuery older than 1.7
or
$('#navItem').on('click', function(){}); // jQuery 1.7 or newer

It would appear so that all your nav elements are created with the same ID. This
$('#navItem').click(function(e){ //<-- THIS IS BROKE!! HELP!!
will apply to only one of them I suppose. Try adding some sort of counter to the ID when you are cloning:
var newItem = $('#' + container).clone();
newItem.attr("id","something_unique_in_here");

Related

Modal Bootstrap refreshing data FullCalendar

So I can see the info of a user in a FullCalendar that is opened in a modal but when I try to open another the modal it doesn`t refresh. I tried all the solutions I found here on Stackoverflow but it didn't work. If I refresh the page then it works if I click in a diferent id.
Code where I bring the id of user to my function cale():
<button id="cal" onclick="cale('.$row["idutilizador"].') class="btn" data-toggle="modal" href="#calendario"><i class="fa fa-calendar"></i></button>
My calendar modal Bootstrap:
<div class="modal fade" id="calendario" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-xl" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Calendario</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
<br />
<h2 align="center">Calendario</h2>
<br />
<div class="container">
<div id="calendar"></div>
</div>
</div>
</div>
</div>
</div>
My function that loads the information from database with the id I got when I click:
function cale(uti){
var calendar = $('#calendar').fullCalendar({
editable:true,
header:{
left:'prev,next today',
center:'title',
right:'month,agendaWeek,agendaDay'
},
events: {
url:'../Components/calendar/load.php',
type: 'POST',
data: function() {
return {
id: uti
};
}
},
...
Your code currently reinitialises the calendar every time you click a button. You should only initialise the calendar once, and then change the data it displays. To do that, you need to first remove the previous event source, add the new one, and then get the new events.
A suggestion: convention is that POST is for changing data (eg making a purchase, updating a record), while GET is for reading data. Here your event source is just loading event data to display, that really should be a GET request. Changing that also makes the code a bit simpler. I've changed to GET here, if you want to do this you need to change your PHP to respond to GET instead of POST.
Another suggestion: AFAICT you are using multiple non-unique HTML IDs on the same page. Your code suggests that the button is inside a loop, so you have buttons for multiple users, but your buttons all have the same ID:
<button id="cal" ...
The code you've shown does not use that ID, but if you try to, it won't work. IDs must be unique, if they are not and you try to use them, only the first one will work.
Another suggestion: it is generally considered best to separate your JS and your HTML, so instead of using inline onclick, use a separate event handler. You'll need to add the user ID to the button somehow, maybe with a data attribute:
<button data-id="' . $row["idutilizador"] . '" ...
And then instead of onclick() on that button, add an event handler in your JS:
$('button').on('click', function(e) {
// Prevent any default action the button click might normally
// do, eg submit a form or something.
e.preventDefault();
// Find the ID of the clicked button
var userID = $(this).data('id');
// Now call the calendar function with that ID
cale(userID);
});
The code below implementes all these suggestions.
UPDATE As per comments you're using FullCalendar v3, so here's a working v3 solution (click Run to see it in action). I've also converted the previous v5 solution into a working snippet, see below.
FullCalendar v3 solution
// The base URL where your events are. I'm using npoint JSON
// bins from https://www.npoint.io/, yours would be:
// var sourceURL = '../Components/calendar/load.php';
var sourceURL = 'https://api.npoint.io/';
// The current source (none initially)
var currentSource;
// The calendar
var calendar = $('#calendar').fullCalendar({
defaultDate: '2022-01-15',
editable:true,
header:{
left:'prev,next today',
center:'title',
right:'month,agendaWeek,agendaDay'
},
// no events initially
});
// Handle button clicks
$('button').on('click', function(e) {
// Prevent any default action the button click might normally
// do, eg submit a form or something.
e.preventDefault();
// Find the ID of the clicked button
var userID = $(this).data('id');
// Now call the calendar function with that ID
cale(userID);
});
// Update sources
function cale(uti) {
// First remove the current source. First time through
// there is no source, but that does not matter.
// v3: https://fullcalendar.io/docs/v3/removeEventSource
calendar.fullCalendar('removeEventSource', currentSource);
// Set up the URL to the new source. I'm using npoint JSON
// bins from https://www.npoint.io/, so this URL format is
// different to yours, you would use:
// currentSource = sourceURL + '?id=' + uti
currentSource = sourceURL + uti;
// Now add the new source. Note this will use a GET request
// to retrieve events. The new events will be immediately
// fetched and displayed.
// v3: https://fullcalendar.io/docs/v3/addEventSource
calendar.fullCalendar('addEventSource', currentSource);
}
hr {
margin: 20px 0;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/fullcalendar/3.4.0/fullcalendar.min.js"></script>
Click to select a source:
<button data-id="965e830c3e8ab78990c5">Source 1</button>
<button data-id="5c8901e5173d5eab3ad6">Source 2</button>
<hr>
<div id="calendar"></div>
FullCalendar v5 solution
And here's the original v5 solution, as a working snippet, click Run to see it working.
// The base URL where your events are. I'm using npoint JSON
// bins from https://www.npoint.io/, yours would be:
// var sourceURL = '../Components/calendar/load.php';
var sourceURL = 'https://api.npoint.io/';
// The current source (none initially)
var currentSource;
// The calendar
var calendarEl = document.getElementById('calendar');
var calendar = new FullCalendar.Calendar(calendarEl, {
initialDate: '2022-01-15',
editable:true,
// no events initially
});
calendar.render();
// Handle button clicks
$('button').on('click', function(e) {
// Prevent any default action the button click might normally
// do, eg submit a form or something.
e.preventDefault();
// Find the ID of the clicked button
var userID = $(this).data('id');
// Now call the calendar function with that ID
cale(userID);
});
// Update sources
function cale(uti) {
// First get all the current event sources
// v5: https://fullcalendar.io/docs/Calendar-getEventSources
var sources = calendar.getEventSources();
// Now remove those event sources. Note the first time through there
// are none.
// v5: https://fullcalendar.io/docs/EventSource-remove
for (const source of sources) {
source.remove();
}
// Set up the URL to the new source. I'm using npoint JSON
// bins from https://www.npoint.io/, so this URL format is
// different to yours, you would use:
// currentSource = sourceURL + '?id=' + uti
currentSource = sourceURL + uti;
// Now add your new source. Note this will use a GET request to
// retrieve events. The new events will be immediately fetched
// and displayed.
// v5: https://fullcalendar.io/docs/Calendar-addEventSource
calendar.addEventSource(currentSource);
}
hr {
margin: 20px 0;
}
<link href="https://cdn.jsdelivr.net/npm/fullcalendar#5.10.1/main.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/fullcalendar#5.10.1/main.min.js"></script>
Click to select a source:
<button data-id="965e830c3e8ab78990c5">Source 1</button>
<button data-id="5c8901e5173d5eab3ad6">Source 2</button>
<hr>
<div id="calendar"></div>
Try to empty first the div
$('#calendar').html('');
obviously first of
var calendar = $('#calendar').fullCalendar({...

Issue with ng-bind-html

I'm trying to create a website using angular-js .I'm using rest api calls for getting data. I'm using ngSanitize as the data from rest call includes html character. Even if i use ng-bind-html in my view the html tags are not removed .What is the mistake in my code.Can anyone help me
var app = angular.module('app',['ngSanitize','ui.bootstrap']);
app.controller("ctrl",['$scope','$http','$location','$uibModal',function($scope,$http,$location,$uibModal,){
//here im making my rest api call and saving the data in to $scope.items;
}]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular-sanitize.js"></script>
<body ng-app="app" ng-controller="ctrl">
<div class="hov" ng-repeat ="item in items">
<br/>
<div>
<hr class="divider" style="overflow:auto;">
<ul>
<li style="font-family: Arial, Helvetica, sans-serif;font-weight:900px;">
<h3>Name<span style="color:#0899CC;" ng-model="id2" ng-bind-html="item.name"></span></h3>
</li>
<li>
<h4>Description: <span ng-bind-html="item.description"></span></h4>
</li>
</ul>
</div>
</div>
</body>
So you want to allow HTML tags or deny them ?
If you want the html to be escaped in the data coming from your server, just use ng-bind. It will replace < with < and > with > thus showing the HTML tags instead of computing them.
If you want to completely remove any HTML tags
Try this filter
filter('htmlToPlaintext', function() {
return function(text) {
return text ? String(text).replace(/<[^>]+>/gm, '') : '';
};
}
);
then in your HTML :
<h3>Name<span style="color:#0899CC;" ng-model="id2" ng-bind-html="item.name | htmlToPlaintext"></span></h3>
If you trust the source and want to compute the HTML it send you
You can use this filter
app.filter('trusted', function($sce){
return function(html){
return $sce.trustAsHtml(html)
}
});
then in your HTML :
<h3>Name<span style="color:#0899CC;" ng-model="id2" ng-bind-html="item.name | trusted"></span></h3>
And
<h4>Description: <span ng-bind-html="item.description | trusted"></span></h4>
I have the same problem before some time , then i created a filter for this problem, You can use this filter to do sanitize your html code:
app.filter("sanitize", ['$sce', function($sce) {
return function(htmlCode) {
return $sce.trustAsHtml(htmlCode);
}
}]);
in html you can use like this:
<div ng-bind-html="businesses.oldTimings | sanitize"></div>
businesses.oldTimings is $scope variable having description of strings or having strings with html tags , $scope.businesses.oldTimings is the part of particular controller that you are using for that html.
see in the snapshot:
you can use limitHtml filter to do the same:
app.filter('limitHtml', function() {
return function(text, limit) {
var changedString = String(text).replace(/<[^>]+>/gm, ' ');
var length = changedString.length;
return changedString.length > limit ? changedString.substr(0, limit - 1) : changedString;
}
});
Then you can add bothe filter in your html like that:
<p class="first-free-para" ng-bind-html="special.description| limitHtml : special.description.length | sanitize">
Hope it will work for you.

Adding HTML content to angular material $mdDialog

I have written the following piece of code to display some contents in angular material dialog box. it works fine when i add plain text to textContent . when i add HTML its displays HTML as text. how do i bind HTML to textContent
This Works
Sample Link
$scope.Modal = function () {
$mdDialog.show(
$mdDialog.alert()
.parent(angular.element(document.querySelector('body')))
.clickOutsideToClose(true)
.textContent('sample text')
.ok('Ok')
);
}
This Doesn't Works
Sample Link
$scope.Modal = function () {
$mdDialog.show(
$mdDialog.alert()
.parent(angular.element(document.querySelector('body')))
.clickOutsideToClose(true)
.textContent('<div class="test"><p>Sample text</p></div>')
.ok('Ok')
);
}
Thanks in advance
You need to append to the template,
$mdDialog.show({
parent: angular.element(document.body),
clickOutsideToClose: true,
template: '<md-dialog md-theme="mytheme">' +
' <md-dialog-content>' +
'<div class="test"><p>Sample text</p></div>' +
' <md-button ng-click="closeDialog();">Close</md-button>' +
' </md-dialog-content>' +
'</md-dialog>',
locals: {
},
controller: DialogController
});
DEMO
You can add html in template and just add variable in displayOption. This will work.
Template Code
<script type="text/ng-template" id="confirm-dialog-answer.html">
<md-dialog aria-label="confirm-dialog">
<form>
<md-dialog-content>
<div>
<h2 class="md-title">{{displayOption.title}}</h2>
<p>{{displayOption.content}} <img src="{{displayOption.fruitimg}}"/></p>
<p>{{displayOption.comment}}</p>
</div>
</md-dialog-content>
<div class="md-actions" layout="row">
<a class="md-primary-color dialog-action-btn" ng-click="cancel()">
{{displayOption.cancel}}
</a>
<a class="md-primary-color dialog-action-btn" ng-click="ok()">
{{displayOption.ok}}
</a>
</div>
</form>
</md-dialog>
</script>
Controller Code
$mdDialog.show({
controller: 'DialogController',
templateUrl: 'confirm-dialog-answer.html',
locals: {
displayOption: {
title: "OOPS !!",
content: "You have given correct answer. You earned "+$scope.lastattemptEarnCount,
comment : "Note:- "+$scope.comment,
fruitimg : "img/fruit/"+$scope.fruitname+".png",
ok: "Ok"
}
}
}).then(function () {
alert('Ok clicked');
});
Use template instead of textContent, textContent is used for show plan text in a model. It does not render HTML code
$mdDialog.show({
controller: function ($scope) {
$scope.msg = msg ? msg : 'Loading...';
},
template: 'div class="test"><p>{{msg}}</p></div>',
parent: angular.element(document.body),
clickOutsideToClose: false,
fullscreen: false
});
You can use htmlContent instead of textContent to render HTML. Heres an excerpt from the documentation available at https://material.angularjs.org/latest/#mddialog-alert
$mdDialogPreset#htmlContent(string) - Sets the alert message as HTML.
Requires ngSanitize module to be loaded. HTML is not run through
Angular's compiler.
It seems a bit counter intuitive to use a template when you only need to inject one or two things in. To avoid using a template, you need to include 'ngSanitize' for it to work.
angular.module('myApp',['ngMaterial', 'ngSanitize'])
.controller('btnTest',function($mdDialog,$scope){
var someHTML = "<font>This is a test</font>";
$scope.showConfirm = function(ev) {
// Appending dialog to document.body to cover sidenav in docs app
var confirm = $mdDialog.confirm()
.title('Please confirm the following')
.htmlContent(someHTML)
.ariaLabel('Lucky day')
.targetEvent(ev)
.ok('Please do it!')
.cancel('Sounds like a scam');
//Switch between .htmlContent and .textContent. You will see htmlContent doesn't display dialogbox, textContent does.
$mdDialog.show(confirm).then(function() {
$scope.status = 'Saving Data';
},
function() {
$scope.status = 'You decided to keep your debt.';
});
};
})
Notice the injected HTML:
var someHTML = "<font>This is a test</font>";
I found this example here.
The latest version of Angular Material Design API has predefined function for add HTML content to the alert dialog:
an $mdDialogPreset with the chainable configuration methods:
$mdDialogPreset#title(string) - Sets the alert title.
$mdDialogPreset#textContent(string) - Sets the alert message.
$mdDialogPreset#htmlContent(string) - Sets the alert message as HTML. Requires ngSanitize module to be loaded. HTML is not run through Angular's compiler.
$mdDialogPreset#ok(string) - Sets the alert "Okay" button text.
$mdDialogPreset#theme(string) - Sets the theme of the alert dialog.
$mdDialogPreset#targetEvent(DOMClickEvent=) - A click's event object. When passed in as an option, the location of the click will be used as the starting point for the opening animation of the the dialog.
The link to the documentation: Angular MD API

Hidden fields without a form in MVC

I have a table and no form in one page that I am working with.
Is there any way to persist certain values to that html without creating a form. I will not be submitting from this page in any specific way.
<!DOCTYPE html>
<html>
<head>
<title>Show All Encounters</title>
</head>
<body>
<div class="content-wrapper clear-fix float-left" style="height: 1px; padding: 10px;" id="list1">
#{
Html.Hidden("popId", TempData["POPULATIONID"], new { id = "hidPopID" });
Html.Hidden("popId", TempData["POPNAME"], new { id = "hidpnID" });
Html.Hidden("popId", TempData["ROWNUM"], new { id = "hidrownumID" });
}
<table border="2" id="frTable" class="scroll"></table>
<div id='pager'></div>
</div>
</body>
</html>
<script>
function loadDialog(tag, event, target) {
//debugger;
.load($url)
.dialog({
...
, close: function (event, ui) {
debugger;
//if($url.contains)
var popId = $('#hidPopID').val();
var rows = $('#hidrownumID').val();
location.reload(true);
}
});
$dialog.dialog('open');
};
</script>
that close event is inside of a jquery Modal dialog call btw, so the syntax is technically correct
You could persist the values wherever you want in the DOM but if you want to send them to the server you have a couple of options:
Form with hidden fields (you said you don't want this)
AJAX request that will harvest the values from the DOM
Anchor with the values in the query string
Or simply persist the values on the server. I guess that you are using some data store there which could be used.
UPDATE:
Now that you have shown your code it is clear why it is not working. You do not have any hidden fields (browse at the HTML source code in your browser to see that they are missing). You have just called the Html.Hidden helper on the server but you never outputted the result to the HTML
Now add your hidden fields correctly:
#Html.Hidden("popId", TempData["POPULATIONID"], new { id = "hidPopID" })
#Html.Hidden("popId", TempData["POPNAME"], new { id = "hidpnID" })
#Html.Hidden("popId", TempData["ROWNUM"], new { id = "hidrownumID" })

jquery tree select all child checkboxes

I am creating a json tree with checkbox using jquery. Here is my code:
<body>
<div id="regionTree">
</div>
<script type="text/javascript" src="http://code.jquery.com/jquery-1.7.1.min.js">
</script>
<script>
$(function(){
var json = [{"ID":1,"Name":"r1","Child":[{"ID":1,"Name":"c1"},{"ID":2,"Name":"c2"}]},{"ID":1,"Name":"r2","Child":[{"ID":1,"Name":"c1"},{"ID":2,"Name":"c2"}]}];
//debugger;
var treeString = '';
treeString+='<ul>';
$(json).each(function(key, value) {
treeString+='<li>';
treeString+='<label><input type="checkbox" class="parent"/>'+value.Name+'</label><br/>';
//alert(value.Name);
if(value.Child != undefined && value.Child.length > 0)
{
treeString+='<ul>';
$(value.Child).each(function(key,value){
treeString+='<li>';
treeString+='<label><input type="checkbox" class="child"/>'+value.Name+'</label><br/>';
treeString+='</li>';
//alert(value.Name);
});
treeString+='</ul>';
}
treeString+='</li>';
});
treeString+='</ul>';
$('#regionTree').append(treeString);
//------
$('.parent').live('click', function(){
debugger;
console.log($(this).find('.child').size());
$(this).parent().children(':checkbox').prop("checked", true);
});
});
</script>
</body>
If you copy paste it and open up in FF/Chrome you can see the checkbox tree. I wanted to select all child elements of a node if parent is selected. But for some reason i am not able to get all child checkboxe for a node.
Please help.
$(this).parent().children(':checkbox').prop("checked", true);
the checkbox's parent is the label, not the li.
try:
$(this).closest('li').find(':checkbox').prop("checked", true);
You can use any ready plugin to create a tree with checkboxes form a JSON source. For example:
https://github.com/AlexLibs/niTree