I have so much problem working with dynamic elements in jQuery, that I just need to ask a question. First, a little example from my system:
main.js
$(function () {
renderPlaceList(places);
setupVoting();
}
The two function are in separate files, renderPlace.js is a file, where I am creating a new elements. These elements have class .option and they are then stored in a .places div. So far so good. But then I want to work with these elements in setupVoting():
$('.participants .option').each(function () {
...
})
But this just doesn't seem to be working. When I call the code in browser console, it runs just fine. But if it's run while the site is loading, the jQ selector won't find the elements. Where is the catch?
Thanks for your time and answers :)
EDIT
renderPlaces function
function renderPlaceList(places) {
var htmlMeetingPlace = "";
into = $(".places");
$(places).each(function(_, d){
htmlMeetingPlace +=
"<div class='option' data-meeting_place_id='" + d.id + "'>" +
"</div>";
});
into.fadeOut('slow',function(){
into.html("");
into.append(htmlMeetingPlace);
into.fadeIn('slow');
});
}
Problem is that when renderPlaceList return.. $(".places") is not enought formated.. because is still fadeouting..
You can try
function renderPlaceList(places) {
var htmlMeetingPlace = "";
into = $(".places");
$(places).each(function(_, d){
htmlMeetingPlace +=
"<div class='option' data-meeting_place_id='" + d.id + "'>" +
"</div>";
});
into.fadeOut('slow',function(){
into.html("");
into.append(htmlMeetingPlace);
into.fadeIn('slow');
setupVoting(); //here!
});
}
Related
I'm new to jQuery and JS. How can I rewrite these functions correctly using jQuery? I know it's standard JS which was working fine with the manual HTML markup but I now also need to go through page and find iframes with YouTube src and take ID and then recreate them with the first example markup.
I'm totally stuck. I think I have it more or less, but not sure where to go to now.
Fiddle: https://jsfiddle.net/yurt5bb6/
First example uses my markup:
<div class="video-container">
<div class="video-player" data-id="Cv_2mp3X868"></div>
</div>
Which works as I need, however I think now I need to foreach on load and create that same markup from iframe embeds the functions should be better.
Attempt:
function createThumb(id) {
return '<img class="youtube-thumb" src="//i.ytimg.com/vi/' + id + '/hqdefault.jpg"><div class="play-button"></div>';
}
function createIframe() {
var iframe = $("iframe");
iframe.attr("src", "//www.youtube.com/embed/" + this.parentNode.dataset.id + "?autoplay=1&autohide=2&border=0&wmode=opaque&enablejsapi=1&controls=0&showinfo=0");
iframe.attr("frameborder", "0");
iframe.attr("id", "youtube-iframe");
this.parentNode.replaceChild(iframe, this);
}
$(document).ready(function() {
// build video from default markup
var defaultVideo = $(".video-player");
$(defaultVideo).each(function (index, value){
var p = $('<div></div>');
p.innerHTML = createThumb(v[n].dataset.id);
p.onclick = createIframe;
v[n].appendChild(p);
});
// search for social embeds and recreate to our markup
$('iframe[src*="youtube.com"]').each(function() {
var loadedVideoURL = $('iframe').attr('src').match(/[^/]*$/)[0];
console.log(loadedVideoURL);
});
});
I've tried to clean up the messy mix of native JS and jQuery and made some edits to your fiddle: https://jsfiddle.net/yurt5bb6/2/
Default function:
(function() {
$.each($('.video-player'), function() {
$(this).append(videoThumb($(this).data('id')));
$(this).on('click', videoIframe);
});
$.each($('iframe'), function() {
// Rebuild the given template
var player = $('<div class="video-player">');
// Strip youtube video id for data-id attribute
var id = $(this).attr('src');
id = id.substr(id.lastIndexOf("/")+1);
player.attr('data-id', id);
player.html(videoThumb(id));
player.on('click', videoIframe);
var videoContainer = $('<div class="video-container">');
videoContainer.append(player);
$(this).replaceWith(videoContainer);
});
})();
Iframe render function:
function videoIframe() {
var iframe = $('<iframe>');
iframe.attr("src", "//www.youtube.com/embed/" + $(this).attr('data-id') + "?autoplay=1&autohide=2&border=0&wmode=opaque&enablejsapi=1&controls=0&showinfo=0");
iframe.attr("frameborder", "0");
iframe.addClass("youtube-iframe");
$(this).empty();
$(this).append(iframe);
}
Also changed the CSS, made a class instead of id for youtube-iframe.
Section on my website with a list of fixtures.
When I click on one it loads the fixture information in a modal window - each club might have an image so I want to check if there is an image and if so display it otherwise display a generic image.
Code is below:
$('#fixModal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget) // Button that triggered the modal
var hclub = button.data('hclubid')
imgpath = "/images/clubcrests/"
homecrest = imgpath + hclub + '.jpg'
gencrest = imgpath + 'generic.jpg'
$.get(homecrest)
.done(function() {
homecrestsrc = "<img src='" + homecrest + "'>"
}).fail(function() {
homecrestsrc = "<img src='" + gencrest + "'>"
})
var modal = $(this)
modal.find('.fixmodhomec').html(homecrestsrc)
})
But first time I click on it I get the error:
homecrestsrc is not defined
$.get seems to run after the modal.find.
If I click on it again it displays but always the image it should have from the previous time the button was clicked.
How can I make sure the $.get bit runs first?
$.get is asynchronous - did you read the documentation? modal.find will have run long before the response from the AJAX call has come back.
You need to move your logic inside the callbacks.
$('#fixModal').on('show.bs.modal', function (event) {
var button = $(event.relatedTarget),
hclub = button.data('hclubid'),
modal = $(this),
imgpath = "/images/clubcrests/",
homecrest = imgpath + hclub + '.jpg',
gencrest = imgpath + 'generic.jpg',
homecrestsrc;
$.get(homecrest).done(function () {
homecrestsrc = "<img src='" + homecrest + "'>"
}).fail(function () {
homecrestsrc = "<img src='" + gencrest + "'>"
}).always(function () {
modal.find('.fixmodhomec').html(homecrestsrc);
});
})
This is the confusing part of js/ajax. This code does not wait for an ajax reaponse, but instead jumps strait on to the next command. Meaning it will continue with your last 2 lines of code, and then the response will come thru, and then it will set homecrestsrc for the first time. Whatever you expect to be done AFTER you get a reaponse, you put in done and fail. So put your last or last 2 lines of code inside the done and fail functions.
Sry typing from phone so i cant explain too much, but hope you understand, it takes time to get it bcs this is not so obvious when you start
The other answer kind of covered this... basically, if the code below the get request depends on that result, it needs to be inside the .done() block.
However, I'd also like to point out that having your image displaying depend on the whether a get request fails or not is bad practice. You should instead have your api route return true if that image exists or false if it doesn't. Then you can filter the correct picture in a .success() block.
.fail() should be reserved for debugging only.
I am using this JavaScript popup menu in my ASP.NET Web Forms project: http://jsfiddle.net/o8x59caz/4/
This code is working fine until I call a JavaScript function that contains Ajax code. And this function and the one given in the fiddle has no relation or common tags (or tag classes) between them. But whenever I call this Ajax function, it disables the popup menu and nothing happens when I click on the button that displays this popup menu. But before the control reaches this Ajax function, this popup menu is working fine. I tried to check the browser console but it shows no error or warning. Following is the code of my Ajax function:
var curevaldiv, ecount = 0;
function SaveAll() {
var gifurl = '<data url of gif animation';
var evalDivs = $("div.evld");
if (evalDivs.length > 0) {
evalDivs.html("<img src='" + gifurl + "' alt='Please wait. ' style='height:35px'/> <span style='font-size: medium'>Evaluating...</span>");
var i; var infoids = '';
for (i = 0; i < evalDivs.length; i++) {
curevaldiv = evalDivs[i];
infoids = infoids + curevaldiv.dataset.infoid + ';';
}
SendToServer(3,
{ "InfoIDs": infoids },
null,
function (data) {
if (data.rstat != -1) {
var infoid, infoval;
var infovals = data.rhtml.split(';');
for (var j = 0; j < infovals.length; j++) {
infoid = infovals[j].split(':')[0];
infoval = infovals[j].split(':')[1];
$('#val' + infoid).html("<i class='fa fa-calculator'></i> <span class='counter'>" +
(infoval == "[ERROR]" ? "<font color='red'><small><i class='fa fa-exclamation-circle'></i> ERROR</small></font>" : infoval) +
"</span>");
}
ecount++;
}
else
curevaldiv.innerHTML = "<font color='red'><small><i class='fa fa-exclamation-circle'></i> ERROR</small></font>";
},
function () {
curevaldiv.innerHTML = "<font color='red'><small><i class='fa fa-exclamation-circle'></i> ERROR</small></font>";
});
}
}
SendToServer() is a Utility function created by me to avoid writing common Ajax parameters again and again.
Please help me! This problem is making my head heavy for past three days. :(
Thanks to #eck for suggesting Chrome's Break On feature. It helped me in detecting where the DOM was breaking. I traced the function call sequence and found a function that was making the HTML of the div containing the popup menu's HTML to null and then again resetting it back to the popup menu's HTML. But the plugin was called on previous popup menu's HTML. I removed that code and now it's working fine. :)
I want to use EggImageDropdown, but I have problems with the script.
I embedded it in my testing site and there it works:
http://herzschloss.de/hs/test.php at "Mein Wunschbild".
Now I want to use the same script with the same linked in js-code here:
http://herzschloss.de/Liebesschloss-bestellen at "Mein Wunschbild"
But I get an error.
TypeError: jQuery(...).val(...).EggImageDropdown is not a function
This is the live generated script that didn't work:
function onclick(event) {
var t = jQuery('select[id=dropdown_demo]').val('herz.png').EggImageDropdown('close').EggImageDropdown('update',{src:'hs-motive/herz.png'});t.trigger('change');
}
This is the code:
jQuery('option',element).each(function(i,el){
dropdown.append('<img style="width:100%" onclick="var t=jQuery(\'select[id=' + selectName + ']\').val(\''+ $(el).val() + '\').EggImageDropdown(\'close\').EggImageDropdown(\'update\',{src:\''+ $(el).text() + '\'});t.trigger(\'change\');" src="' + $(el).text() + '"/>');
});
It would be great if you help me!
It's very difficult to embed that much code into an onclick attribute. Better to not do it.
To correct it, create the function directly in the loop instead of creating an attribute.
jQuery('option',element).each(function(i,el){
var img = $('<img>', {style: "width:100%;", src: $(el).text()});
img.click(function() {
var t=jQuery('select[id=' + selectName + ']');
t.val($(el).val()).EggImageDropdown('close')
.EggImageDropdown('update', {src:$(el).text()});
t.trigger('change');
});
dropdown.append(img);
});
Furthermore, looking at your linked site, it appears that the EggImageDropdown function doesn't exist, which means you're not successfully loading the plugin.
I have the following code within an external javascript file.
jQuery(function ($) {
//////////////////////UPCOMING EVENTS JSON SERVER START///////////////////////////
var eventList = $("#eventList"); //cache the element
$.getJSON("/JsonControl/Events.json", function (jsonObj) {
val = "";
for (var i = 0; i < jsonObj.events.length; ++i) {
val += "<p>" + jsonObj.events[i].dateMonth + "/" + jsonObj.events[i].dateNumber +
"/" + jsonObj.events[i].dateYear + " - <span id='EL" + i + "' class='link' " +
"onclick=plotEvent(" + i +")>" + jsonObj.events[i].title + "</span></p>";
}
eventList.html(val);
});
//////////////////////UPCOMING EVENTS JSON SERVER END/////////////////////////////
});
function plotEvent(index)
{
$.ajax({
url: "/JsonControl/Events.json",
dataType: 'json',
async: false,
success: function (jsonObj)
{
var eventBox = window.frameElement;
alert("This alert fires in all browsers, including IE9")
eventBox.onload = function ()
{
alert("This alert doesn't fire in IE9.")
window.frameElement.onload = null; // unset it so it only fires once
eventBox = eventBox.contentDocument || eventBox.contentWindow.document;
eventBox.getElementById("title").innerHTML = (jsonObj.events[index].title);
eventBox.getElementById("content").innerHTML = (jsonObj.events[index].explanation);
eventBox.getElementById("dateHolder").innerHTML = (jsonObj.events[index].dateMonth + "-" + jsonObj.events[index].dateNumber + "-" + jsonObj.events[index].dateYear);
};
eventBox.src="/Event htms/Event.htm";
}
});
}
The page that loads this script is in the iframe itself. A very similar function called in a different external js file, from the main page outside of the iframe (for a different but similar purpose) works in all browsers just fine. The only difference is that with this code I have to target the onload of the iframe from within the iframe, instead of just grabbing the iframe by id. I then attempt to change, the onload of said iframe, for use with the next internal iframe page (which is why I need to preserve the json array index [i] when dynamically writing the first iframe page's innerHTML.
Sorry if that was a bit wordy, and/or confusing, but suffice it to say that with using the above-pasted code, I have no problems... except with IE (tried in IE9). I have tried dozens of examples and supposed solutions, but nothing has worked. Using IE9.
Here's what I mean when I say 'it doesn't work in IE9':
This part of the code within plotEvent() doesn't fire:
eventBox.onload = function ()
{
alert("This alert doesn't fire in IE9.")
window.frameElement.onload = null; // unset it so it only fires once
eventBox = eventBox.contentDocument || eventBox.contentWindow.document;
eventBox.getElementById("title").innerHTML = (jsonObj.events[index].title);
eventBox.getElementById("content").innerHTML = (jsonObj.events[index].explanation);
eventBox.getElementById("dateHolder").innerHTML = (jsonObj.events[index].dateMonth + "-" + jsonObj.events[index].dateNumber + "-" + jsonObj.events[index].dateYear);
};
Is there any solution to this problem, or is this sort of thing why iframes aren't used more often (that is, that IE doesn't fully support them)?
Try eventBox.contentWindow.onload or maybe $(eventBox).load(function)