This question already has answers here:
Event binding on dynamically created elements?
(23 answers)
Closed 4 years ago.
I am using jquery to pull in JSON and loop through the results to create a collection of items. Namely, Anchors with a few data attributes. I then am watching those items so that on click I can pull the relevant data attributes and... do things with that data. When I hard code in the anchors with the data, everything works great. When I create them dynamically through the JSON I get nothing, and the page refreshes.
jQuery( document ).ready(function() {
$.getJSON("http://glacier.creativefilterdev.com/wp-json/wp/v2/chocolate?categories=42&per_page=100&order=asc", function(result) {
$.each(result, function(i, item) {
if(item.better_featured_image == null){
} else {
$(".white").append("<a class=\"choc-option\" href=\"\" data-text=\"" + item.title.rendered + ", \" data-img=\"" + item.better_featured_image.media_details.sizes.thumbnail.source_url + "\"><img class=\"chocolate\" src=\"" + item.better_featured_image.media_details.sizes.thumbnail.source_url + "\"><br>" + item.title.rendered + "</a>");
}
});
});
jQuery("a[data-text]").click(function(){
if(howMany < countVar) {
howMany += 1;
var imgurl = jQuery(".single").val();
var structure = jQuery('<div class="single" data-text="'+ jQuery(this).attr('data-text') +'"><img src="'+ jQuery(this).attr('data-img') +'"><a class="delete">-</a></div>');
jQuery('.buildbox').append(structure);
jQuery("#alert").css('display', 'none');
} else {
jQuery("#alert").css('display', 'block');
}
return false;
});
});
I apologize as there is code in there that I haven't explained as that is the "stuff" I'm doing with the data from the anchors.
You can do it like this
jQuery( document ).ready(function() {
$.getJSON("http://glacier.creativefilterdev.com/wp-json/wp/v2/chocolate?categories=42&per_page=100&order=asc", function(result) {
$.each(result, function(i, item) {
if(item.better_featured_image == null){
} else {
$(".white").append("<a class=\"choc-option\" href='' data-text=\"" + item.title.rendered + ", \" data-img=\"" + item.better_featured_image.media_details.sizes.thumbnail.source_url + "\"><img class=\"chocolate\" src=\"" + item.better_featured_image.media_details.sizes.thumbnail.source_url + "\"><br>" + item.title.rendered + "</a>");
}
});
});
$('body').on('click', 'a[data-text]', function(e) {
e.preventDefault();
alert('test');
if(howMany < countVar) {
howMany += 1;
var imgurl = jQuery(".single").val();
var structure = jQuery('<div class="single" data-text="'+ jQuery(this).attr('data-text') +'"><img src="'+ jQuery(this).attr('data-img') +'"><a class="delete">-</a></div>');
jQuery('.buildbox').append(structure);
jQuery("#alert").css('display', 'none');
} else {
jQuery("#alert").css('display', 'block');
}
return false;
});
});
Related
below is the js code for wikipedia search project. I am getting infinite for loop even though it had condition to stop repeating the loop. I am stuck in this problem.
$(document).ready(function() {
$('.enter').click(function() {
var srcv = $('#search').val(); //variable get the input value
//statement to check empty input
if (srcv == "") {
alert("enter something to search");
}
else {
$.getJSON('https://en.wikipedia.org/w/api.php?action=opensearch&search=' + srcv + '&format=json&limit=20&callback=?', function(json) {
$('.content').html("<p> <a href ='" + json[3][0] + "'target='_blank'>" + json[1][0] + "</a><br>" + json[2][0] + "</p>");
/*for loop to display the content of the json object*/
for (i = 1; i < 20; i++) {
$('p').append("<p><a href ='" + json[3][i] + "'target='_blank'>" + json[1][i] + "</a>" + json[2][i] + "</p>");
}
});
}
});
});
You are appending to each and every one of <p> in page.
Since your for loop appends even more <p> (and you possibly have a high number of <p> elements in your page beforehand) you overflow your call stack.
You probably wanted to append to a specific <p>. Try giving an id to your selector.
from what i can see in the url you need to do the following:
loop over the terms found and select the link based on the index of the element, chose a single element .contentto append the data not a set of elements p, this will increase the number of duplicated results
$.getJSON('https://en.wikipedia.org/w/api.php?action=opensearch&search='+srcv+'&format=json&limit=20&callback=?', function(json){
$.each(json[1],function(i,v){
$('.content').append("<p><a href ='"+json[2][i]+"'target='_blank'>"+json[0]+"</a>"+v+"</p>");
});
});
see demo: https://jsfiddle.net/x79zzp5a/
Try this
$(document).ready(function() {
$('.enter').click(function() {
var srcv = $('#search').val(); //variable get the input value
//statement to check empty input
if (srcv == "") {
alert("enter something to search");
}
else {
$.getJSON('https://en.wikipedia.org/w/api.php?action=opensearch&search=' + srcv + '&format=json&limit=20&callback=?', function(json) {
$('.content').html("<p> <a href ='" + json[3][0] + "'target='_blank'>" + json[1][0] + "</a><br>" + json[2][0] + "</p>");
/*for loop to display the content of the json object*/
var i = 1;
for (i; i < 20; i++) {
$('p').append("<p><a href ='" + json[3][i] + "'target='_blank'>" + json[1][i] + "</a>" + json[2][i] + "</p>");
}
});
}
});
});
I am extremely new at writing ajax and working with a restful api... so, bear with me.
I have a Laravel 5.2 RESTful API that I am using on the backend, and I'm attempting to simply load a list of categories using Jquery / Ajax. As you click through the categories, each child category loads fine, but I cannot seem to get the "back" button to work (by this, I mean the LI I am generating, not the browser back button). When you click it, it shows the alert - and the data is correct, but that's it. The list doesn't refresh and populate with the appropriate items.
EDIT
There are no errors being thrown to the javascript console either. It just won't populate from the ajax call.
EDIT
I removed the request.abort() right after I made the original post.
EDIT
Here is the JSON returned from the URL api/categories/4 - as an example.
[{"id":6,"parent":4,"name":"sub_subcat4_1","slug":"sub_subcat4_1","description":null,"created_at":null,"updated_at":null},{"id":7,"parent":4,"name":"sub_subcat4_2","slug":"sub_subcat4_2","description":null,"created_at":null,"updated_at":null}]
EDIT
Here is the HTML for the #categories
<div class="row">
<div class="col-sm-12">
<ul id="categories">
</ul>
</div>
The Javascript
<script>
/*
* This loads the default / root categories.
*/
function getRootCategories() {
$.getJSON("api/categories", function(data) {
var categories = [];
$("#categories").html("");
$.each(data, function(key, val) {
$("#categories").append("<li class='subcat' data-id='" + val.id + "' onClick='getSubcats(this);'>" + val.name + '</li>');
});
});
}
/*
* This loads the sub categories if there's any data returned. Otherwise, just leave the user where they are.
*/
function getSubcats(cat) {
var dataID = cat.getAttribute("data-id");
alert(dataID);
if(dataID == "null") {
getRootCategories();
}
else {
$.getJSON("api/categories/" + dataID, function (data) {
if (data.length != 0) {
$("#categories").html("");
var newCats = '';
var parent = '';
$.each(data, function (key, val) {
parent = "<li class='subcat' data-id='" + val.parent + "' onClick='getSubcats(this);'>Back</li>";
newCats += "<li class='subcat' data-id='" + val.id + "' onClick='getSubcats(this);'>" + val.name + '</li>';
});
$("#categories").append(parent + newCats);
}
});
}
}
$(document).ready(function() {
$.ajaxSetup({ cache:false });
getRootCategories();
});
</script>
Ok, I just had my variables all mixed up. I wasn't setting the correct parent id.
The new script looks like this -
<script>
var previous = null;
/*
* This loads the default / root categories.
*/
function getRootCategories() {
$.getJSON("api/categories", function(data) {
var categories = [];
$("#categories").html("");
$.each(data, function(key, val) {
$("#categories").append("<li class='subcat' data-parent='" + val.parent + "' data-id='" + val.id + "' onClick='getSubcats(this);'>" + val.name + '</li>');
previous = val.parent;
});
});
}
/*
* This loads the sub categories if there's any data returned. Otherwise, just leave the user where they are.
*/
function getSubcats(cat) {
var dataID = cat.getAttribute("data-id");
previous = cat.getAttribute("data-parent");
if(dataID == "null") {
getRootCategories();
}
else {
$.getJSON("api/categories/" + dataID, function (data) {
if (data.length != 0) {
$("#categories").html("");
var newCats = '';
var parent = '';
$.each(data, function (key, val) {
parent = "<li class='subcat' data-id='" + previous + "' onClick='getSubcats(this);'>Back</li>";
newCats += "<li class='subcat' data-parent='" + val.parent + "' data-id='" + val.id + "' onClick='getSubcats(this);'>" + val.name + '</li>';
});
$("#categories").append(parent + newCats);
}
})
.fail(function(jqxhr, textStatus, error) {
console.log("Request Failed: " + textStatus + " - " + error);
});
}
}
$(document).ready(function() {
$.ajaxSetup({ cache:false });
getRootCategories();
});
</script>
function demo(){
$('.box').slideToggle('fast');
}
$(document).ready(function(){
$.getJSON( "js/JobOpenings.json", function( data ) {
var glrScrlImg = [];
$.each( data.getJobOpeningsResult, function( key, val ) {
var st = "",id,st2= "",st3="",id;
st +="<h4>" + val.JobTitle + "</h4>";
st3 += "<div class='box'>" + val.JobDetails + "</div>";
$("#newsDetails").append("<li onclick='demo()'>" + st+val.JobSector + "<br>" + st3 + "</li>");
$('.box').hide();
});
});
});
I am reading data from a json file. The div with 'box' class is hidden. Currently this code is displaying all div on click of the li. What changes should I make to display only the div corresponding to the clicked li?
Here what we need to do is to find the .box element within the clicked li, so we need to get a reference to the clicked element.
I would use a delegated jQuery event handler with css to initially hide the element
$(document).ready(function () {
$('#newsDetails').on('click', 'li', function () {
$(this).find('.box').toggleClass('hidden');
})
$.getJSON("js/JobOpenings.json", function (data) {
var glrScrlImg = [];
$.each(data.getJobOpeningsResult, function (key, val) {
var st = "",
id, st2 = "",
st3 = "",
id;
st += "<h4>" + val.JobTitle + "</h4>";
st3 += "<div class='box hidden'>" + val.JobDetails + "</div>";
$("#newsDetails").append("<li>" + st + val.JobSector + "<br>" + st3 + "</li>");
});
});
});
with css
.hidden {
display: none;
}
Pass the control to the function and then based on your control slideToggle its respective .box
function demo(ctrl){
$(ctrl).find('.box').slideToggle('fast');
}
$(document).ready(function(){
$.getJSON( "js/JobOpenings.json", function( data ) {
var glrScrlImg = [];
$.each( data.getJobOpeningsResult, function( key, val ) {
var st = "",id,st2= "",st3="",id;
st +="<h4>" + val.JobTitle + "</h4>";
st3 += "<div class='box'>" + val.JobDetails + "</div>";
$("#newsDetails").append("<li onclick='demo(this)'>" + st+val.JobSector + "<br>" + st3 + "</li>");
$('.box').hide();
});
});
});
Or add a class to li and attach an event handler like below instead of writing inline onclick as below:
$("#newsDetails").append("<li class="someclass"'>" + st+val.JobSector + "<br>" + st3 + "</li>");
and then instead of function demo() write this
$('#newsDetails').on('click','.someclass',function(){
$(this).find('.box').slideToggle('fast');
});
UPDATE
Method 1:
function demo(ctrl){
$('#newsDetails').find('li.box').hide('fast'); //hide all the .box
$(ctrl).find('.box').slideToggle('fast');
}
Method 2:
$('#newsDetails').on('click','.someclass',function(){
$('#newsDetails').find('li.box').hide('fast'); //hide all the .box
$(this).find('.box').slideToggle('fast');
});
UPDATE 2:
Method 1:
function demo(ctrl){
$('#newsDetails').find('li.box').not($(ctrl).find('.box')).hide('fast'); //hide all the .box
$(ctrl).find('.box').slideToggle('fast');
}
Method 2:
$('#newsDetails').on('click','.someclass',function(){
$('#newsDetails').find('li.box').not($(ctrl).find('.box')).hide('fast'); //hide all the .box except this
$(this).find('.box').slideToggle('fast');
});
You should structure your html (which is missing from the question!) so that the div and li are "connected" in some way (maybe the div is child of li, or they have same class, ecc).
Right now the line
$('.box').slideToggle('fast');
is applied to all element with class '.box' in your page. You want to be more selective there, that's where the way you structure the html comes into play.
Here's an example: http://jsfiddle.net/owe0faLs/1/
I have two DIVs, #placeholder AND #imageLoad. When the user clicks on a particular thumb its larger version (thumb2) should then appear in #imageLoad DIV.
Here is the jQuery that needs to be fixed:
$.getJSON('jsonFile.json', function(data) {
var output="<ul>";
for (var i in data.items) {
output+="<li><img src=images/items/" + data.items[i].thumb + ".jpg></li>";
}
output+="</ul>";
document.getElementById("placeholder").innerHTML=output;
});
//This is wrong!! Not working..
$('li').on({
mouseenter: function() {
document.getElementById("imageLoad").innerHTML="<img src=images/items/" +
data.items[i].thumb2 + ".jpg>";
}
});
Here is the external JSON file below (jsonFile.json):
{"items":[
{
"id":"1",
"thumb":"01_sm",
"thumb2":"01_md"
},
{
"id":"2",
"thumb":"02_sm",
"thumb2":"02_md"
}
]}
$.getJSON('jsonFile.json', function(data) {
var output="<ul>";
for (var i = 0; i < data.items.length; i++) {
output += "<li><img thumb2='" + data.items[i].thumb2 + "' src='images/items/" + data.items[i].thumb + ".jpg'></li>";
}
output += "</ul>";
$("#placeholder").html(output);
$('li').on({
mouseenter: function() {
$("#imageLoad").html("<img src='images/items/" + $(this).find('img').attr('thumb2') + ".jpg'>");
}
});
});
Your variable data is declared only within the callback function of your getJSON call and hence it is not available in the other methods/ event handlers. Store it to a global variable when you get it. Like Below:
var globalData;
$.getJSON('jsonFile.json', function(data) {
globalData = data;
var output="<ul>";
for (var i in data.items) {
output+="<li id=\"listItem" + i + "\"><img src=images/items/" + data.items[i].thumb + ".jpg></li>";
}
output+="</ul>";
document.getElementById("placeholder").innerHTML=output;
});
//This is wrong!! Not working..
$('li').on({
mouseenter: function() {
var index = parseInt($(this).attr('id').substring(8));
document.getElementById("imageLoad").innerHTML="<img src=images/items/" +
globalData.items[index].thumb2 + ".jpg>";
}
});
Firstly, $.getJSON is asynchronous, so the binding of mouseenter following the async function will not work as the li elements does not exist when you attach the event handler. Secondly, store the second image source in a data attribute on each li element, and just retrieve that data attribute in the mouseenter function:
$.getJSON('jsonFile.json', function(data) {
var out = $("<ul />");
for (var i in data.items) {
$('<li />', {
src: 'images/items/' + data.items[i].thumb + '.jpg'
}).data('big', data.items[i].thumb2).appendTo(out);
}
$("#placeholder").html(out);
});
$('#placeholder').on('mouseenter', 'li', function() {
var bigImg = $('<img />', {
src: 'images/items/' + $(this).data('big') + '.jpg'
});
$("#imageLoad").html(bigImg);
});
This is my jQuery part that makes my menu for my pages.
function fetchmenus() {
$.getJSON('sys/classes/fetch.php?proccess=1', function(status) {
// get line status
$.each(status, function(i, item) {
if (item.id == "1") {
active = "class='active'";
lastpageid = item.href;
}
else {
active = "class='nonactive'";
}
$('<li id="' + item.href + '" ' + active + '>' + item.menuTitle + '<span class="menuspan" id="' + item.href + '"></span></li>').appendTo('#menuarea ul#mainmenu');
});
});
}
What I want to do is get the item.menuTitle in the <a but before the <span>.
Currently I do it on this way:
$('ul#mainmenu li').live('click', function(event) {
//alert(this.id);
$("li#" + lastpageid).removeClass();
fetchpage(this.id);
$("#largemenutop").html($(this).text());
$("li#" + this.id).addClass("active");
lastpageid = this.id;
});;
Is there a better way to do this?
Nice solution Herman, though it can be reduced to something like this:
JS
$('li a').contents().filter(function() {
return this.nodeType == 3;
}).text();
HTML
<li>Apple<span>hi</span> Juice</li>
Will return Apple Juice
Fiddle: http://jsfiddle.net/49sHa/1/
Yes, you can select only the text contents of the element, like this:
var text = '';
$('a').contents().each(function(){
if(this.nodeType === 3){
text += this.wholeText;
}
});
$("#largemenutop").html(text);