I have a function to load and place images into an empty div (it's some kind of scrolling menu done by me) and to place images one behind another I use append function. All is going well until the upload to the server. The order of the pictures seems to be failed like the append() is not placing them one behind another.
loadContent = function(i){
var tytul = "#phot" + i;
var photurl = "../photos/" + activegal + "/" + i + ".JPG";
$.ajax({
url:photurl,
type:'HEAD',
error: function()
{
},
success: function()
{
newid = "photo"+i;
var img = $("<img />").attr({
src: photurl,
width:"120",
height:"90",
id: newid,
'class': "photon"
});
$(img).appendTo("#scrollbar");
counter++;
//$.delay(2);
});
};
<div id="scrollbar">
</div>
it seems you are trying to do a get on the images in an ajax call through a loop counter and then add these image elements to the <div> element, however ajax calls being asynchronous , the appendTo() of image#1 might be called after appendTo of image#2 depending on when each of the ajax calls returns (which in turn might depend on the size of the image, network traffic etc.).
The only way to ensure the elements are in order of server checks is by making the ajax calls synchronous by setting:
async: false
Related
I have a small MVC5/C# Web application. In short, users will select a location from a dropdown ("#UnitList"). This fires the jquery event, to populate the next dropdown ("#CheckItem") with a list of contacts associated to the location selected.
Being very inexperienced in Jscript and Jquery, I am lost.
Additionally, on the same event, I need to populate an element (hidden text box).
In order to fill the hidden elements, I use this code
$(function () {
$("[name='UnitList']").change(function () {
$("#DeliveryUnitID").val($(this).val());
});
});
To run the Jquery that populates the second dropdown:
$(document).ready(function() {
$("#UnitList").change(function() {
var batchId = $(this).val();
var urlForModesl = getURLBase() + "ICS_Requisitions/Details";
urlForModesl = urlForModesl + "/" + batchId;
var modelsHtml = "";
$('#CheckItem')
.find('option')
.remove()
.end()
.append('<option value="Select Contact"></option>')
.val('Contact')
$.ajax({
type: 'get',
url: urlForModesl,
contentType: 'application/json',
dataType: 'json',
success: function(jsonData) {
$.each(jsonData, function(key, value) {
modelsHtml += "<option value='" + value.LoginID + "'>" + value.ContactName + "</option>";
});
$("#CheckItem").html(modelsHtml);
$("#DeliveryUnitID").val($(this).val())
},
error: function(XMLHttpRequest, textStatus, errorThrown) {}
});
});
});
I am aware that I have two functions with the same name "$("#UnitList").change(function ()" and that this is very bad and causing conflicts. This is what I am trying to resolve.
I have tried to simply add the element update within the Jquery code, but that did not work.
I placed the following code
$("#DeliveryUnitID").val($(this).val())
Inside the Jquery, right after:
$("#CheckItem").html(modelsHtml);
But that does not work. The hidden elements are still empty.
I tried creating a function called foo, with the element update, and call that function from at the end of the jquery.
foo();
<script>
function foo() {
$("#DeliveryUnitID").val($(this).val());
}
That also left the element #DeliveryUnitID empty.
I know that I can't have two functions with the same name, but that's the only way I can get it working where the query populates the drop down, and then the hidden element is populated too. BUT . . . that's bad coding AND, for about 5% of the users, it fails.
I can't quite figure out how to make both happen with one onchange event.
It's been a while since I've used jQuery, so here's what I'm seeing:
On change Event:
Get the value of the #UnitList <select> (potential bug: these aren't being stored anywhere)
Clear the options
Re-populate with new ones from AJAX Request
Try to get value of new options (still within initial AJAX request, which might also be a bug? Like I said, it's been a while since I've used jQuery).
It looks like you might have a state-management issue?
Potential fixes:
Store values of first dropdown before you clear them.
Use the stored value to populate #DeliveryUnitID after the AJAX request
Use some if statements or remove the event listener to not constantly be running your code on change event once you get the data you need...unless you need it to be running constantly.
To me, it would seem beneficial (from a code pov and maybe also a UX perspective) to programmatically build a second dropdown to keep things clearer, but that might be overkill for what you're trying to accomplish.
I have a script that does 2 main things in a sequence:
It pulls data from an XML file through a GET request, and it appends the result into the DOM.
I have this "MacyJS" script which basically puts the content within a nicely calculated grid (a bit like Masonry).
My issue is that the first part is taking quite some time (I don't mind, it's meant for my own private use) to get the result and append it to the DOM. So that the "MacyJS" already ran before, and thus not rendering properly the HTML in a nice grid.
You can see I tried to put a delay for MacyJS, but of course this is not precise and doesn't always work in time, since the GET/append sometimes takes more than 1.5s.
How can I automatically run "MacyJS" only once the DOM has fully been updated with the new HTML/content ?
Thanks a lot for your help.
Code below for reference:
$(document).ready(function(){
// THE FIRST SCRIPT
var x=20;
$.get("my xml file here", function(data) {
var $xml = $(data);
$xml.find("item").each(function(i, val) {
var $this = $(this),
item = {
description: $this.find("description").text(),
guid: $this.find("guid").text()
};
$('#grid').append($('<div class="parsed appear"><a target="_blank" href="' +item.guid +'">' +item.description +'</a></div>'));
return i<(x-1);
});
});
// THE SECOND SCRIPT
setTimeout(function(){
var macy = Macy({
container: '#grid',
margin: 20,
columns: 4,
});
}, 1500);
});
I'm attempting a make random quote machine with a tweet button to tweet the quote.
The random quote is coming up just fine.
The code..
var forismaticAPI = 'http://api.forismatic.com/api/1.0/?method=getQuote&format=jsonp&lang=en&jsonp=?';
$(document).ready(function() {
var template = function(data) {
$('#quotearea').empty();
$('#quotearea').append('<blockquote id="quote">' + data.quoteText + '</blockquote>' + '<p id="author"> — ' + data.quoteAuthor + '</p>');
$('#quotearea').show();
};
var dataAppend = function() {
$.getJSON(forismaticAPI, template);
};
}
My next task is to get the quote content to be tweeted. So once the window loads completely i want to get the innerHTML of #quote which contains the quote. So i write a window.onload function like this..
window.onload = function(){
var quote = document.getElementById('quote');
console.log(quote.innerHTML);
}
But I'm getting an error Uncaught TypeError: Cannot read property 'innerHTML' of null(…).. Since there is small delay in loading the quote, the window load function returns a null. How to get the innerHTML of a div only when the content is loaded and ready?
Your #quote element is created after the window.onload event, because it's only created on the return of your ajax call. Move the code from onload to success of the ajax call, as BlueBoy suggested in comments. In your case, the success function is the one you named template.
You can access your element immediately after creating it:
var template = function(data) {
$('#quotearea').empty();
$('#quotearea').append('<blockquote id="quote">' + data.quoteText
+ '</blockquote>' + '<p id="author"> — ' + data.quoteAuthor + '</p>');
$('#quotearea').show();
console.log(document.getElementById('quote'));
};
You can't call the innerHTML method on DOM elements that do not exist yet. So the first moment you can run your function is after the append() call, which is creating a DOM element with and id of quote.
Without testing it, my guess is that onload is firing before the document ready. So you may want to 1) set a flag when the content has been written, Then 2) check in the second function, if null schedule it to run again in 100 ms using setTimeout().
use the html function?
var code = $('#quotearea').html();
If I am here asking it is because we are stuck on something that we do not know how to solve. I must admit, we already searched in StackOverflow and search engines about a solution.. but we didn't manage to implement it / solve the problem.
I am trying to create a JavaScript function that:
detects in my html page all the occurrences of an html tag: <alias>
replaces its content with the result of an Ajax call (sending the
content of the tag to the Ajax.php page) + localStorage management
at the end unwraps it from <alias> tag and leaves the content returned from ajax call
the only problem is that in both cases it skips some iterations.
We have made some researches and it seems that the "problem" is that Ajax is asynchronous, so it does not wait for the response before going on with the process. We even saw that "async: false" is not a good solution.
I leave the part of my script that is interested with some brief descriptions
// includes an icon in the page to display the correct change
function multilingual(msg,i) {
// code
}
// function to make an ajax call or a "cache call" if value is in localStorage for a variable
function sendRequest(o) {
console.log(o.variab+': running sendRequest function');
// check if value for that variable is stored and if stored for more than 1 hour
if(window.localStorage && window.localStorage.getItem(o.variab) && window.localStorage.getItem(o.variab+'_exp') > +new Date - 60*60*1000) {
console.log(o.variab+': value from localStorage');
// replace <alias> content with cached value
var cached = window.localStorage.getItem(o.variab);
elements[o.counter].innerHTML = cached;
// including icon for multilingual post
console.log(o.variab+': calling multilingual function');
multilingual(window.localStorage.getItem(o.variab),o.counter);
} else {
console.log(o.variab+': starting ajax call');
// not stored yet or older than a month
console.log('variable='+o.variab+'&api_key='+o.api_key+'&lang='+o.language);
$.ajax({
type: 'POST',
url: my_ajax_url,
data: 'variable='+o.variab+'&api_key='+o.api_key+'&lang='+o.language,
success: function(msg){
// ajax call, storing new value and expiration + replace <alias> inner html with new value
window.localStorage.setItem(o.variab, msg);
var content = window.localStorage.getItem(o.variab);
window.localStorage.setItem(o.variab+'_exp', +new Date);
console.log(o.variab+': replacement from ajax call');
elements[o.counter].innerHTML = content;
// including icon for multilingual post
console.log(o.variab+': calling multilingual function');
multilingual(msg,o.counter);
},
error: function(msg){
console.warn('an error occured during ajax call');
}
});
}
};
// loop for each <alias> element found
//initial settings
var elements = document.body.getElementsByTagName('alias'),
elem_n = elements.length,
counter = 0;
var i = 0;
for(; i < elem_n;i++) {
var flag = 0;
console.info('var i='+i+' - Now working on '+elements[i].innerHTML);
sendRequest({
variab : elements[i].innerHTML,
api_key : settings.api_key,
language : default_lang,
counter : i
});
$(elements[i]).contents().unwrap().parent();
console.log(elements[i].innerHTML+': wrap removed');
}
I hope that some of you may provide me some valid solutions and/or examples, because we are stuck on this problem :(
From our test, when the value is from cache, the 1st/3rd/5th ... values are replaced correctly
when the value is from ajax the 2nd/4th .. values are replaced
Thanks in advance for your help :)
Your elements array is a live NodeList. When you unwrap things in those <alias> tags, the element disappears from the list. So, you're looking at element 0, and you do the ajax call, and then you get rid of the <alias> tag around the contents. At that instant, element[0] becomes what used to be element[1]. However, your loop increments i, so you skip the new element[0].
There's no reason to use .getElementsByTagName() anyway; you're using jQuery, so use it consistently:
var elements = $("alias");
That'll give you a jQuery object that will (mostly) work like an array, so the rest of your code won't have to change much, if at all.
To solve issues like this in the past, I've done something like the code below, you actually send the target along with the function running the AJAX call, and don't use any global variables because those may change as the for loop runs. Try passing in everything you'll use in the parameters of the function, including the target like I've done:
function loadContent(target, info) {
//ajax call
//on success replace target with new data;
}
$('alias').each(function(){
loadContent($(this), info)
});
I'm working on some legacy code in javascript and I have a problem I can't work out.
When the document first loads, a JS function named addDecisionStateDetailsFields() gets invoked. This method generates HTML which it appends to a certain div. The Ctrl C, Ctrl V version is at pastebin.
So when a document first loads, I get the required HTML. But in another case I have to call that same function via AJAX and I did something like:
function editSPDecision(decision){
$('#serviceProcedureAddDecision').css('display', 'none');
jQuery.ajax({
type:'POST',
data: { 'decisionId': decision.id, 'authorizationId': ${authorizationId} },
url:'../editDecision/${id}',
success: function(data,textStatus) {
jQuery('#serviceProcedureEditDecision').html(data);
},
complete: function(XMLHttpRequest,textStatus) {
attachDatePickerClasses();
addDecisionStateDetailsFields("spDecision_approve", "approveDiv", "Approve", "${ReviewerApproveReason.getValueCommaSeperated()}", "${ReviewerApproveReason.getNameCommaSeperated()}");
}
});
}
Here, I've invoked the method addDecisionStateDetailsFields() with the right params. But after the AJAX call completes, I can't get the generated HTML appended to the HTML of the page.
To cross check, I put an alert inside the method and after the AJAX call completes the method in fact gets invoked, only that the generated HTML is not appended to the div. Is there ssomething that I'm missing here?
Inside the addDecisionStateDetailsFields right before
$('#' + masterParentDiv).append(generatedStr);
can you do
alert($('#' + masterParentDiv).length);
That will tell you whether the masterParentDiv is found, if its found you should get back something other than 0.
Not 100% sure about that I am going to say but, change
$('#' + masterParentDiv).append(generatedStr);
to
jQuery('#' + masterParentDiv).append(generatedStr);