Are element added by .append() already ready after appended? - javascript

I am building a kind of infinite scroll with jquery, but I am facing a DOM ready problem.
var n = 0;
// When user wants to load more, call this
function load_10_images(){
var g; var images = '';
for(g=1; g<=10; g++){
// Create images
images = '<div id="'+n+'" >'+
'<li id="li'+n+'">'+
'<img id="img'+n+'" src="images/loading.gif" />'+
'</li>'+
'</div>';
// add to html
$("#list").append(images);
// change source
$.ajax({
type: "POST",
url: "data.php",
data: {link_n: n},
success: function(resp) {
$("#img"+n).attr("src", resp);
},
});
// ...
n++;
}
}
My problem is images sources don't change. How to solve this problem ?

Your problem is scope. You create the DIVs and IMG ids with n as you loop through it. But you access the value of n in your ajax callback. So it will attempt to find $("#img"+n).attr("src", resp); with whatever the current value of n is (most likely the final value since it will finish faster than the post returns);

The problem is that since AJAX is async, your variable n inside the success call is equal to the variable n inside the last loop. Add a closure like that :
(function(int){
$.ajax({
type: "POST",
url: "data.php",
data: {link_n: int},
success: function(resp) {
$("#img"+int).attr("src", resp);
},
});
})(n);

As many people have pointed out, you have other issues that are causing the problems that you are seeing, but to answer your actual question, yes, they are available after .append(). Actually, what you find people do, frequently, is actually make the element available before appending it. In your code (since you're using jQuery), you could do that like this:
images = $('<div id="'+n+'" >'+
'<li id="li'+n+'">'+
'<img id="img'+n+'" src="images/loading.gif" />'+
'</li>'+
'</div>');
At that point, the element exists and can be read, modified, etc., but simply has not been added to the DOM yet.

Related

add click event on img with data from a json (twitch api)

the problem I have is that after creating a list with images that come from the preview of specific streams, I would like to be able to click on these images and replace the stream playing with the stream that comes from the image.
In the code below I get the streamers that play GTA V and do GTA RP. With this info, I get the nickname of the players to create the url with the preview image of their stream.
...
function streamData(auth){
$.ajax({
type: 'GET',
url: 'https://api.twitch.tv/helix/search/channels?
query=FailyV&live_only=true', /** gta V id = 32982 */
dataType:'json',
headers: {
"Client-ID": 'id',
"Authorization": "Bearer "+auth
},
success: function(streamList) {
for (let i = 0; i < streamList['data'].length; i++){
if(streamList['data'][i]['game_id'] == 32982){
gtaList.push(streamList['data'][i]['display_name'])
$('#twitch-embed-low').append('<img id="thumbnail'+i+' " src="https://static-cdn.jtvnw.net/previews-ttv/live_user_'+streamList['data'][i]['display_name']+'-300x200.jpg">')
.on("click", function(e){
console.log(gtaList[i])
})
}
}
new Twitch.Embed("twitch-embed-main", {
width: '80%',
height: '80%',
channel: gtaList[0],
autoplay: false,
layout: "video",
// only needed if your site is also embedded on embed.example.com and othersite.example.com
parent: ["embed.example.com", "othersite.example.com"]
});
let test = $('#twitch-embed-low')
console.log(test[0])
},
error: function(data){
info = document.getElementById("info")
info.innerHTML = "ERROR: " + data["responseJSON"]["message"] + ". Make sure your CID and corresponding secret are set in the JavaScript."
}
})
}
...
As you can see, I have tested this
...
$('#twitch-embed-low')
.append('<img id="thumbnail'+i+' " src="https://static-cdn.jtvnw.net/previews-
ttv/live_user_'+streamList['data'][i]['display_name']+'-300x200.jpg">')
.on("click", function(e){console.log(gtaList[i])})
...
but as you can imagine, it doesn't work (as I suspected) and each time I click on an image, it makes the complete loop and so it doesn't put the right stream in reading but systematically the last one and I'm not talking about the performances which are disastrous since it loads each stream 1 by 1.
So the idea is that when you click on the image, it puts the right stream in reading but I don't see how to do that.
There's a couple of improvments you can make. The first one is you are binding the click handler to the parent element and not to the img element, meaning it will be called (n) times (the length of streamList['data']). This is because you bind the click handler multiple times to the same html element. You want to bind this event handler just to the img element.
Secondly, when the event handler is called, it will be referencing the value of i which will always be the last value of i in the loop iteration. If you want to log the value of i at the point when you create the img element, you will need to use a closure to save the state of i, for example:
var img = $('<img id="thumbnail'+i+' " src="https://static-cdn.jtvnw.net/previews-
ttv/live_user_'+streamList['data'][i]['display_name']+'-300x200.jpg">')
.on("click", (function (index) {
return function (e) {
console.log(gtaList[index]);
};
})(i));
$('#twitch-embed-low').append(img)

Preppend a new child div ahead of previous child div's jquery

I am trying to a do a simple media posting project. When new records are added to the database I use ajax to add a new child div to a parent div based on the info in the record. I have it working except for the order that children are added in. Doing a prepend does not place the new div as the first child of the parent div, it puts it as the last child of the specified parent. That's no good when I want new posts displayed on top. Here is the code for the file I'm working on. How do I prepend above previously added children?
$(document).ready(function (){
setInterval(function(){
$.ajax({
type: 'GET',
url: 'JSONFile.php',
data: { get_param: 'value' },
dataType: 'json',
success: function(retrieved){
//$("#MainContent").empty();
$.each(retrieved, function(index, i){
$('#MainContent').append('<br><div class="Post"><h2>' + i.UserName + '</h2><br><p>' + i.Content + '</p></div>');
});
}
});
},3000);
});
Instead of using .append, you can use .prepend, which was made for exactly this purpose:
Insert content, specified by the parameter, to the beginning of each element in the set of matched elements.
So, you can use the code:
$.each(retrieved, function(index, i){
$('#MainContent').prepend('<br><div class="Post"><h2>' + i.UserName + '</h2><br><p>' + i.Content + '</p></div>');
});

Ajax jQuery Multiple Step Form instead of reloading div, just append new content

I wonder if it's possible to do this multistep form on one single page, so not reloading the div with the content received from the php file but append it right below..
This is what I've got so far:
$(document).on('submit', '#reg-form', function(){
var ln = $('#submit').val();
var id = $('#id').val();
var data = 'submit='+ln;
$.ajax({
type: 'GET',
url : 'step.php',
dataType : 'html',
data : data,
success : function(data)
{
$('#reg-form').fadeOut(500).hide(function()
{
$('.result').fadeIn(500).show(function()
{
$('.result'+id).append(data);
});
});
}
});
return false;
});
Also I tried to use different divs, with incremental id's to put every content in it's own div. The Problem is, I'm only getting the "second" step, so it's not going through the whole formular.
I guess it's because the form of the first page is still there and all have the same id.. Can anyone help me out here please?
id of element in document should be unique. Change the duplicate id at html source or using javascript
success : function(data) {
// change duplicate `reg-form` `id` to value
// corresponding to `.length` of elements having `id`
// containing `"reg-form"`
$(data).filter("#reg-form")
.attr("id", "reg-form-" + $("[id*='reg-form']").length);
$("#reg-form").fadeOut(500).hide(function() {
$(".result").fadeIn(500).show(function() {
$(".result" + id).append(data);
});
});
}

jquery prop multiple items?

I'm not sure what I'm doing wrong but for the past 2 hours I've been trying to use prop to change the value of two items in a button. It works for one but not for the other and I have no idea why.
html:
<input type='button' value='Following' id='btnFollow' dataaction="UnFollow" datatype='topic'>
jquery:
$("#btnFollow").prop("value", "Follow");
$("#btnFollow").prop("dataaction", "Follow");
The first item changes(value) but not the second one(dataaction). I have no idea why(other then maybe its too late and my brain is rebelling). According to the documentation I'm doing it correct. I added alerts inbetween each command in case one was failing, but both alerts went off meaning jquery is not crashing or anything when it tries to change the second item. I don't see any spelling mistakes and I tried to daisy chain the commands but still no luck.
Any suggestions?
entire_code:
$(document).ready(function () {
$('#btnFollow').click(function() {
var topic_id = $(this).attr('datatopic');
var action_type = $(this).attr('datatype');
var action_type_action = $(this).attr('dataaction');
alert(action_type_action);
//$("#btnFollow").prop('value', 'Following');
if (action_type_action == 'Follow') {
$("#btnFollow").prop({'value': 'Following', 'dataaction': 'UnFollow'});
//$("#btnFollow").prop("value", "Following");
//$("#btnFollow").prop("dataaction", "UnFollow");
$.ajax({
type: 'POST',
url: '/follow_modification',
async: false,
data: {
topic: topic_id,
action: action_type_action,
follow_type: action_type
}
//complete: function(xmlRequestObject, successString){
// ymmReceiveAjaxResponse(xmlRequestObject, successString);
//}
});
} else if (action_type_action == 'UnFollow') {
$("#btnFollow").prop({'value': 'Follow', 'dataaction': 'Follow'});
//$("#btnFollow").prop("value", "Follow");
//$("#btnFollow").prop("dataaction", "Follow");
$.ajax({
type: 'POST',
url: '/follow_modification',
async: false,
data: {
topic: topic_id,
action: action_type_action,
follow_type: action_type
}
//complete: function(xmlRequestObject, successString){
// ymmReceiveAjaxResponse(xmlRequestObject, successString);
//}
});
}
})
});
Your code works just fine: http://jsfiddle.net/zerkms/Capvk/
Properties generally affect the dynamic state of a DOM element without changing the serialized HTML attribute
http://api.jquery.com/prop/
So that's why you don't see it changed in html, but it is changed in DOM instead. If you want it to be changed in HTML as well - use .attr()
PS: as #ahren mentioned in the comments - it probably makes sense to use .data() and data-xxx properties
PPS: if you set the value using .prop() - you need to get it with .prop() respectively
If there is a need to set multiple properties with single jQuery .prop method,
just try this:
instead
$("#btnFollow").prop("value", "Follow");
$("#btnFollow").prop("dataaction", "Follow");
use
$("#btnFollow").prop({"value": "Follow", "dataaction": "Follow"});
Please use .attr jQuery method.
Please use properly html5 data attribute asenter code here data-action for which you have new jQuery method to access this data attribute with $('#btnFollow').data('action') For more details visit

Jquery find+length/size returns 0

I have some divs created dynamically this way:
//here goes some loop, and everything works fine
$("#result_main_search").append('<div class="singleresult_main_search">
<a href="http://somesite.com/" class="linktosight">'
+ SightsList[i]+ '</a> – ' +
'<img src="/images/balloon.gif" rel="'+ i
+'" class="balloon_img_main_search" /></div>');
After that loop, I try to set href attribute for each link:
$('.singleresult_main_search').each(function() {
$.get("_ajax_get_sight_link.php", {'id':$("img", this).attr('rel')},
function(data) {
alert($(this).find('.linktosight').length);
$(this).find('a').attr('href', data);
alert(data);
});
})
_ajax_get_sight_data.php accepts id, returns link ( alert(data) works fine) .
But alert which tells how much .linktosight elements are in current div always gives 0 (by saying always I mean everytime it finds one of my generated divs). I've tried .size(), $(this).find('a') with the same result. So, how am I to set it to work?
this inside the callback will point to the jqXHR-object and not to the looped elements.
You may create a closure:
$('.singleresult_main_search').each(function() {
var $this=$(this);
//.....
});
..and use it inside the callback:
function(data) {
alert($this.find('.linktosight').length);
});
$.proxy() may also be an option like suggested by Jack Franklin

Categories

Resources