Help please, guys.
After an Ajax call, I have a JSON object with two rows (users). I have dynamic id's as I intend to load some content (a form to edit the user details) on the page. My problem is each user row that the FOR loop generates has the same ID. So all of the Ajax generated rows have the same ID, 48 in this case.
Here is the code..
// Get the admin information
var loadAdmin = function() {
$.ajax({
type: 'GET',
id: id,
cache: false,
url: 'scripts/administratorsList.php?id=' + id
}).done(function(data) {
var adminData = JSON.parse(data);
for (var i in adminData) {
var userId = adminData[i].id;
$('#adminList').append('<li class="media"><div class="media-left"><img src="assets/images/placeholder.jpg" class="img-circle" alt=""></div><div class="media-body"><div class="media-heading text-semibold">' + adminData[i].userName + '</div><span class="text-muted">Administrator</span></div><div class="media-right media-middle text-nowrap"><span class="text-muted"><i class="icon-pin-alt text-size-base"></i> ' + adminData[i].userCompany + '</span></div></li>')
// Add the edit form view here
$('#edit' + userId).on('click', function(userId) {
var userId = adminData[i].id;
$('#userConfig').append('Here I will generate the form to edit user ' + userId); // This is where the ID stays the same. I have used .append over .html for debugging purposes. Each row returns an ID of 48
});
}
});
};
Below is the JSON file
[{
"id": "17",
"userName": "Mark Bell",
"userCompany": "Pro Movers",
"userTelephone": "12345678911",
"userEmail": "info#info.uk",
"userPassword": "md5hash",
"userUAC": "6",
"originalUAC": "6",
"userRegistered": "20150826",
"activationKey": "0",
"userLastLoggedIn": "20160302",
"userBranch": "0",
"userAdmin": "0"
}, {
"id": "48",
"userName": "demo",
"userCompany": "Monstermove",
"userTelephone": "12345678912",
"userEmail": "info#info.uk",
"userPassword": "demo",
"userUAC": "6",
"originalUAC": "6",
"userRegistered": "20160305",
"activationKey": "0",
"userLastLoggedIn": "20160305",
"userBranch": "3",
"userAdmin": "3"
}]
Thanks in advance
With Jacub's implementation
for(var i in adminData)
{
var userId = adminData[i].id;
storeValueToRemainSame(userId);
}
function storeValueToRemainSame(userId) {
$('#adminList').append('<li class="media"><div class="media-left"><img src="assets/images/placeholder.jpg" class="img-circle" alt=""></div><div class="media-body"><div class="media-heading text-semibold">' + adminData[i].userName + '</div><span class="text-muted">Administrator</span></div><div class="media-right media-middle text-nowrap"><span class="text-muted"><i class="icon-pin-alt text-size-base"></i> ' + adminData[i].userCompany + '</span></div></li>')
// Add the edit form view here
$('#edit' + userId).on('click', function(userId) {
var userId = adminData[i].id;
$('#userConfig').append('Here I will generate the form to edit user ' + userId); // This is where the ID stays the same. I have used .append over .html for debugging purposes. Each row returns an ID of 48
});
}
The issue here is that you are referencing value outside of the handler which changes, therefore the last value is retained.
for(var i in data) {
var value = i;
$('#someId').on('click', function(){
console.log(value);
});
}
The only written value will be the last one as the reference to it will remain.
Possible solution is for example:
function storeValueAndHandleClickEvent(value){
$('#someId').on('click', function(){
console.log(value);
});
}
for(var i in data) {
storeValueAndHandleClickEvent(i);
}
EDIT: If I use the same code as in the question
for (var i in adminData) {
var userId = adminData[i].id;
storeValueToRemainSame(userId);
}
function storeValueToRemainSame(userId) {
$('#adminList').append('<li class="media"><div class="media-left"><img src="assets/images/placeholder.jpg" class="img-circle" alt=""></div><div class="media-body"><div class="media-heading text-semibold">' + adminData[i].userName + '</div><span class="text-muted">Administrator</span></div><div class="media-right media-middle text-nowrap"><span class="text-muted"><i class="icon-pin-alt text-size-base"></i> ' + adminData[i].userCompany + '</span></div></li>')
// Add the edit form view here
$('#edit' + userId).on('click', function(userId) {
var userId = adminData[i].id;
$('#userConfig').append('Here I will generate the form to edit user ' + userId); // This is where the ID stays the same. I have used .append over .html for debugging purposes. Each row returns an ID of 48
});
}
Try this simple code outside ajax
You will use event delegation an will select the id from the id of the dynamically added dom element
$('ul').on('click','div[id^="edit"]',function() {
var userId = $(this).attr('id').substring(4);
$('#userConfig').append('Here I will generate the form to edit user ' + userId); // This is where the ID stays the same. I have used .append over .html for debugging purposes. Each row returns an ID of 48
});
Related
I got a situation where I would like to read some data off a JSON format, however I am having some issues understanding how I should construct the button dynamically from JSON object.
My scenario is as follows:
$(document).ready(function() {
var socket = io.connect('http://' + document.domain + ':' + location.port);
// listen for mqtt_message events
// when a new message is received, log and append the data to the page
socket.on('mqtt_message', function(data) {
var json = JSON.parse(data['payload']);
var table = $("<table>");
table.append($("<tr><th>Host</th><th>Name</th><th>ID</th><th>"));
for (var i = 0; i < json.length; i++) {
var row = $("<tr><td>" + json[i]["name"] + json[i]["ID"] + "</td></tr>");
table.append(row);
}
table.appendTo($("#container"));
})
});
where
json = {"host":abc,"name":123,"id":345}
I have to make hostname as button and when I click on that button for example here, name "abc", i will get details name and id in table format. I have created table but it is showing whole table not that scenario which I actually want.
I am new to the JavaScript, facing issues here.
1) The JSON data doesn't seem to be an array, you can't loop through it.
2) You have to append the header to a <thead> element.
3) You have to append the table row to a <tbody> element.
All tables should have a <thead> and a <tbody> element, so just add it to your HTML code.
<div id="container">
<table style="display:none">
<thead>
<tr>
<th>Host</th>
<th>Name</th>
<th>ID</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
Then you append your data to these HTML elements, like so. If your data is an object and not an array, just don't loop through it but instead call the properties as is.
var json = [{
host: "Some host IP",
name: "Some name",
id: 345
},
{
host: "Some other host IP",
name: "Some other name",
id: 987
}
];
var $container = $("#container");
var $thead = $("#container table thead");
var $tbody = $("#container table tbody");
var $row = $("#container table tbody tr");
// Loop through items in JSON data..
json.forEach(function(item) {
var $button = $("<button>" + item.host + "</button>");
$container.prepend($button);
// Button click handler..
$button.on("click", function() {
// Replace row HTML..
$row.html('<td>' + item.host + '</td>' + '<td>' + item.name + '</td>' + '<td>' + item.id + '</td>');
// Show table if it's not already visible..
$("#container table").show();
});
});
Full code here:
https://jsfiddle.net/amsv/15h74uy6/
Vanilla JS, ie. without jQuery:
https://jsfiddle.net/amsv/15h74uy6/72/
let json = [
{"host":abc,"name":123,"id":345},
{"host":def,"name":456,"id":345}
]
In your html write
<button *ngFor = 'let item of json' (click)='buttonOnClick($event)'>
{{item.host}}
</button>
Above code will render two buttons for each element in the array
In your ts write
buttonOnClick(event) {
console.log(event) // you will get the corresponding object from the array
}
var sampleData = [{ "host": "abc", "name": 123, "id": 345 }, { "host": "xyz", "name": 456, "id": 678 }]
When data is received you should create button which shows table and set data attribute of button with received data.
for (var i = 0; i < sampleData.length; i++) {
var item = sampleData[i];
var button = $('<button />');
button.text(item.host);
button.data('data', JSON.stringify(item))
button.on('click', function (e) {
e.preventDefault();
showTable(e);
});
$('#buttons').append(button);
}
showTable is like as below
function showTable(e) {
var json = JSON.parse($(e.target).data('data'));
var table = $("<table>");
table.append($("<tr><th>Host</th><th>Name</th><th>ID</th><th>"));
var row = $("<tr><td>" + json["host"] + "</td><td>" + json["name"] + "</td><td>" + json["id"] + "</td></tr>");
table.append(row);
$("#table").html(table);
}
Html is below:
<div id="container">
<div id="buttons">
</div>
<div id="table">
</div>
</div>
I'm making a website with recipes in it and I am loading them from a json file via a Mustache.js template.
My json looks something like this:
{
"recipes":[
{"name": "A", preparationTime: "40min", "servings": "3", "image": "path/to/imageA"},
{"name": "B", preparationTime: "30min", "servings": "2", "image": "path/to/imageB"},
{"name": "C", preparationTime: "20min", "servings": "3", "image": "path/to/imageC"},
{"name": "D", preparationTime: "30min", "servings": "4", "image": "path/to/imageD"}
]
}
my template looks like this:
var recipeTemplate = "" +
"<div class='col-6 recipeUnit'>" +
"<div class='recipeItem row'>" +
"<div class='recipeItem__image col-5'><img src='{{image}}' alt='recipe image'></div>" +
"<div class='recipeItem__description col-7'>" +
"<h3 class='recipeTitle'>{{name}}</h3>" +
"<div class='details'>" +
"<span>{{preparationTime}}</span>" +
"<span>{{servings}}</span>" +
"</div>" +
"<a class='buttonDetails' href='#'>see more</a>" +
"</div>" +
"</div>" +
"</div>";
And my ajax load function looks like this:
$(document).ready(function(){
loadRecipes()
function loadRecipes(){
$.ajax({
type: "GET",
url: "recipes.json",
dataType: "JSON",
cache: false,
success: function(data){
$section.empty();
for(var i = 0; i < data.recipes.length; i++){
var recipe = data.recipes[i];
var html = Mustache.to_html(recipeTemplate, recipe);
$section.append(html);
$button = $(".buttonDetails");
$button.data.recipe = recipe;
};
$button.on("click", function(){
console.log($(this).data.recipe)
return false;
});
});
}
})
I want to be able to store the json per specific recipe into the $button in each recipe displayed on the page. Everything works fine but when I want to console.log the data.recipe property when I click the button I always get the last array item from the json. I have been struggling with this for quite some time now and I don't understand why it's displaying the last item.
Originally I took the idea from telez here:
Best practices for Storing JSON in DOM.
I would appreciate if anyone could explain to me why is this problem happening and how could I fix it.
Because $button = $(".buttonDetails"); matches all the buttons appended to the document up to that point. So basically you iterate over all recipes and set the last receipts data to the all buttons for each recipe. This leaves you with all buttons data set to the last recipe.
The problem is in the line:
$button = $(".buttonDetails");
You get all the buttons and assign a recipe to all of them at once.
To avoid this, you should change your selector so it will search in the current template only.
There's a couple of issues here.
Your reference to $button is being reassign every iteration, so when you click the $button, it points to the last button that was bound.
Because your $button is being reassigned, the data associated with it will also be reassigned.
Please see this fiddle
$(document).ready(function(){
var $section = $('section');
loadRecipes();
function loadRecipes(){
var solution = [];
for(var i = 0; i < data.recipes.length; i++){
var $button;
var recipe = data.recipes[i];
var html = Mustache.to_html(recipeTemplate, recipe);
$section.append(html);
$button = $(".recipeUnit:last .buttonDetails"); // get the last $button every time...
$button.data.recipe = recipe;
// capture each $button and store it in array. By doing so we ensure we don't reasign the button.
solution[i] = $button;
solution[i].data('recipe',recipe);
};
// $button here is going to be the D button, because $button is assigned 4 times.
$button.on("click",function(){
console.log('This is wrong, because the $button variable is repointed on every iteration',$(this).data.recipe);
return false;
});
// here we have really do have 4 different buttons...
solution.map(function($button){
$button.on('click',function(e){
console.log($(this).data().recipe);
});
});
}
})
I've been trying to populate div tables with dummy JSON data but I cannot seem to do it. What I want to do is display certain data depending of the selection in a dropdownbox. Also I need to create new row with a new dropdownbox when an item is selected. Could you give me some advice of what's the best way to do it. I'm able to create something close to what I need in Angular but I need it in pure JavaScript. Thanks in advance!
structure of my div tables
Suppose in data you have json object
var data = [
{
"line": "Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.",
"author": "Brian W. Kernighan",
"num" : ["1","2","3"]
},
{
"line": "Walking on water and developing software from a specification are easy if both are frozen.",
"author": "Edward V Berard",
"num" : ["5","0","15"]
},
{
"line": "It always takes longer than you expect, even when you take into account Hofstadter's Law.",
"author": "Hofstadter's Law",
"num" : ["15","222","301"]
}];
and you want to populate all authors in above json object to table and num into respective dropdown element of table-row. Then following populateHTML() function populate object to table and num into respective dropdown element of table-row as shown in below image .
function populateHTML(data) {
if (typeof(data) == 'object') {
document.write('<table>');
for (var i in data) {
document.write('<tr><td>'+data[i].author+'</td><td><select>');
for(var j in data[i].num){
document.write('<option>' +data[i].num[j]+ '</option>');
}
document.write('</select></td></tr>');
}
document.write('</tr></table>');
} else {
document.write(' => ' + data);
}
}
This can be achieved with the following code: You can also check an example here: http://skillcram.com/JS_DivTable.htm
<script type="text/javascript" >
function populateTable() {
var tableData = {
products : [
{"id": 100,"name":"Laptop", "qty":1,"status": ["Delivered","Damaged","Missing"]},
{"id": 200,"name":"Monitor", "qty":2,"status":["Refused","Partial"]}
]
}
var tableBody = document.getElementsByClassName("divTableBody");
for (i in tableData.products){
tableBody[0].innerHTML += "<div class=\"divTableRow\"> " +
"<div class=\"divTableRowCell\">"+ tableData.products[i].id +" </div> " +
"<div class=\"divTableRowCell\">"+ tableData.products[i].name +" </div> " +
"<div class=\"divTableRowCell\">"+ tableData.products[i].qty +" </div> "+
"<div class=\"divTableRowCell\">"+ getSelectHTMl(tableData.products[i].status) +
" </div> "+
"</div>";
}
}
function getSelectHTMl(status) {
selectHTMlStr = "<select> ";
for (j in status){
selectHTMlStr +=
"<option value=\""+ status[j]+ "\" id=\"itemStatus\" >"+status[j]+ " </option>" ;
}
selectHTMlStr += "</select>" ;
return selectHTMlStr;
}
</script>
I'm working on this project for learning purposes. The tasks for now are very simple:
Populate data from DB using $.getJSON.
Check every 'n' seconds for new data and append it to the list.
Notify user about new data changes.
Here is the example of where I got so far: ( JSBin /Don't forget to run js)
All the issues will be visible when running the example.
Here is the JS code that i have:
$(document).bind('pageinit', function(){
var $myList = $( "#myList" );
var newItems = [];
function loadList(){
$.getJSON("http://jsbin.com/vayeni/2.js",function(data){
$.each(data, function( index, value ) {
newItems.push( "<li><a>" + value.airline + "</a></li>" );
if(data>newItems){
alert('New Entry');
data=newItems;
}
});
$myList.append( newItems.join( "" ) );
$myList.listview( "refresh" );
setTimeout(loadList,1000);
});
}
loadList();
});
Thanks for your help !
Your data comparison is not correct.
You are comapring this:
<li><a>JetBlue</a></li>
<li><a>Continental</a></li>
...
to this:
{
"id": "1",
"airline": "JetBlue",
"number": "222",
"people": "3",
"time": "12:20"
},
{
"id": "2",
"airline": "Continental",
"number": "222",
"people": "5",
"time": "23:21"
},
There will be always inequality.
You should use another approach. For example, if the id field from your JSON array is an unique one you can attach it to each item from the unordered list as an id attribute. For example:
newItems.push( "<li id=\"" + value.id + "\"><a>" + value.airline + "</a></li>" );
This way, at each iteration you can check if the incomming JSON item already exists into your list and add it when there is no match. Eg:
if (!$myList.find('#' + value.id).length) {
newItems.push( "<li id=\" + value.id + \"><a>" + value.airline + "</a></li>" );
}
Finally, you can append the newItems contents directly if there are items inside:
if (newItems.length > 0) {
$myList.append( newItems.join( "" ) );
}
Here is the edited snippet: JSBin
I want create a web application that display a list of items. Suppose I have displayed a list view (say listobject1) of 3 items. when clicked on any of them I get new list view (say listobject2) which its value is according to listobject1. When again I click one of them I get another view. Now when I click back button i want to go back to previous list view i.e. when I'm now on listobject2 and again when back button is pressed I want to show listobject1. Can anybody tell me how I can do this in JavaScript?
Edit
I'm still study about the stuff but I can't solve this problem yet. In order to clarify my problem now, here's my code:
$(document).ready(function() {
$("#result").hide();
$("input[name='indexsearch']").live("click", function() {
$("#result").show();
$("#result").empty();
loading_img();
var $textInput = $("[name='valueLiteral']").val();
$.getJSON("get_onto", {
"input" : $textInput
}, function(json) {
if(json.length > 0 ) {
var arrayPredicate = [];
var arrayObject = [];
var arraySubject = [];
$.each(json, function(index, value) {
arraySubject[index] = value.subject;
arrayPredicate[index] = value.predicate;
if(value.objectGeneral != null) {
arrayObject[index] = value.objectGeneral;
} else {
arrayObject[index] = value.objectLiteral;
}
}
);
var stmt = [];
//concat all related array into string (create triple statement)
$.each(arrayPredicate, function(k,v){
stmt[k] = "<span class='subject' id="+arraySubject[k]+">"
+ arraySubject[k] + "</span> " + " -> " + v + " : "+
//change object from text to be button form
"<button class = 'searchAgain-button' name = 'searchMore' \n\
value = " + arrayObject[k] + ">" + arrayObject[k] + "</button><br> <br>";
});
stmt = stmt.sort();
$.each(stmt, function(k,v){
$("#result").append(v);
});
} else {
var $noresult = "No Result : Please enter a query";
$("#result").append($noresult);
}
});
});
$("button").live("click", function() {
$("#result").show();
$("#result").empty();
loading_img();
var $textInput = $(this).attr("Value");
//var $textInput = "G53SQM";
$.getJSON("get_onto", {
"input" : $textInput
}, function(json) {
if(json.length > 0 ) {
var arrayPredicate = [];
var arrayObject = [];
var arraySubject = [];
$.each(json, function(index, value) {
arraySubject[index] = value.subject;
arrayPredicate[index] = value.predicate;
if(value.objectGeneral != null) {
arrayObject[index] = value.objectGeneral;
} else {
arrayObject[index] = value.objectLiteral;
}
}
);
var stmt = [];
var searchMore = "searchMore";
//concat all related array into string (create triple statement)
$.each(arrayPredicate, function(k,v){
stmt[k] = "<span class='subject' id="+arraySubject[k]+">" + arraySubject[k] + "</span> " + " -> " + v + " : "+ " <button class = 'searchAgain-button' name = " +searchMore + " value = " + arrayObject[k] + ">" + arrayObject[k] + "</button><br><br>";
});
stmt = stmt.sort();
$.each(stmt, function(k,v){
$("#result").append(v);
});
} else {
var $noresult = "No Result : Please enter a query";
$("#result").append($noresult);
}
});
});
At first, user only see one button name "valueLiteral". After user perform 1st search, the result is return in a form of JSON and eventually put in stmt[] to display, which at this state the second button was create as a clickable-result which will automatically take the value of result and do second search if user click the second button.
Now the problem is, I want to add a 3rd HTML button name "back" to make the web display the previous result in stmt[] if user click on the button.
Hope this helps in clarify the problems, I'm still doing a hard work on this stuff since I'm a newbie in JavaScript. Appreciate all helps.
This is what you want almost exactly the way you want it.
You'll have to use history.pushState to push these fake events into the history.
Alternatively, you can use location.hash to store the current object, and update the hash every time you display a new list. Then onhashchange find the hash and display the appropriate list.
See http://jsfiddle.net/cFwME/
var history=[new Array(),new Array()];
history[0].id="#back";
history[1].id="#next";
Array.prototype.last=function(){
return this[this.length-1];
}
$('#list>li:not(:first)').click(function(){
if(!history[0].length || history[0].last().html()!=$('#list').html()){
history[0].push($('#list').clone(true,true));
$(history[0].id).prop('disabled',false);
history[1].length=0;
$(history[1].id).prop('disabled',true);
}
$('#list>li:first').html('This is List '+$(this).index());
});
$('#back').click(getHistory(0));
$('#next').click(getHistory(1));
function getHistory(n){
return function(){
if(!history[n].length){return false;}
history[(n+1)%2].push($('#list').replaceWith(history[n].last()));
history[n].pop();
$(history[(n+1)%2].id).prop('disabled',false);
if(!history[n].length){$(history[n].id).prop('disabled',true);}
}
}
Check out jQuery BBQ - http://benalman.com/projects/jquery-bbq-plugin/