DOM elements are only sporadically created despite being loaded by ajax - javascript

This is a very specific problem and one that makes me particularly confused. The project in short: I'm working on a counseling website that gets data from an API and is loaded with AJAX. I'm now trying to get old, archived chats to be be preloaded and displayed with css on click in a menu.
Here's the problem: It works... but only about 1 in 3 times or after reload of the page. I don't understand how that can be, either it should work or it doesn't.
I checked and the data is always loaded (it has to because the current chat is opened first and always works)
So how can that be?
$.ajax({
type: 'POST',
url: '/vsbt/counselling/archive/',
data: {},
}).done(function(data) {
console.log('ajax /vsbt/counselling/archive/');
console.log(data);
//menu is created
$('#counselling_status').append('<ul class="archivedCounsellings"></ul>');
$('.archivedCounsellings').append('<h2>Archivierte Chats</h2>')
for (var i = 0; i < data.length; i++) {
//menu items are added
var that = data[i].messages[0].title;
$('.archivedCounsellings').append('<li class="' + that + '"><a>' + that + '</a></li>')
$('#vbst_communication_container').prepend($('<div class="counselling inactive ' + that + '" />')
.append($('<h2>' + that + '<h2>')));
//the messages are added with to classes for styling
data[i].messages.forEach(function(message) {
$("div." + that)
.append($('<div />')
.addClass(message.type)
.append($('<p />')
.text(message.message)))
});
//this doesn't work either, you can maybe tell me why, but that's not the issue
$('.counselling').data("status", [i]);
}
$(".archivedCounsellings").append('<li class="aktuell"><a><br>Zur aktuellen Beratung</a></li>');
//click event to toggle the displayed counseling
$('.archivedCounsellings li').click(function() {
$('.counselling').addClass('inactive');
$('div .' + $(this).attr('class')).removeClass('inactive');
//workaround which works, but isn't really acceptable
// no load workaround
// if($('.openCounselling').siblings().length == 0){
// window.location.reload();
// }
// $('.statusDisplay').text($('#job_status_' + $(this).attr('class')).data("status"));
// console.log($('div .' + $(this).attr('data-status')));
});
PS. I'm aware of the typo in 'counselling'
PPS. if you find a mistake that obviously makes it fail that probably happend while copying since, remember, it does work sometimes.

Ok so if anyone ever encounters this problem: I was just explained AJAX a little bit closer and basically AJAX sends out all the requests more or less simultaneously. Whatever happens in the done function happens after that, hence the successful data request.
What I did, was initiate the container for said elements in a different function. So occasionally that one was a little bit slower and there was no place to append my elements to --> no error, just nothing happened.
It's unlikely that anyone will see this, since it's very specific, but maybe this'll help someone, at least i know better now

Related

Get divs from an external file by class name.with jQuery

Sorry if this has been answered before but I searched for hours trying to find how to do what I am trying to do. I know php would probably have an easier solution but php might not an option. Jquery is preferable although pure javascript would be great too.
I'm trying to get divs from an external file by class name. There are multiple divs using the same class name. I want to get all the div of that class put in an array that I can loop through in a later part of the script.
I'm trying keep the contents of the divs of this page synced up to the divs of a page of an external html file that will always be changing. But I'm not sure how best to do this.
I have had good results getting data from csv files into divs in other projects, no problem, but this one has me stymied.
I tried the following (for testing purposes, I was just logging to console). I have confirmed that the external file loads just fine. I can see it load in the Chrome Dev Tools. But the data never really seems to go anywhere after that.
$(document).ready( function() {
var array = [];
var testfunc = $('.test').each(function () {array.push(this.innerHTML);});
$.get('sharedResources/Bio.html', function(testfunc){
console.log(array);
});
});
I tried other variations but they were even messier and the script started pulling from classes of the current page instead of the external file. I could see the innerHTML of the current page showing up in the console log.
I'm sure there is a much better way that I'm not seeing.
I also tried something else I saw suggested online but this didn't works either. This gave me 'contents is undefined' error... not to surprised at that one.
$.ajax('sharedResources/Bio.html').done(function(e) {
$('.test').attr('innerHTML', contents);
});
Sorry if I am not asking this well. I don't often ask anything on these forums.
Thanks!
Assuming the URL is within the same origin, all you really have to do is
$.get('sharedResources/Bio.html', function(html){
var elements = $('<div />', {html: html}).find('.className');
}).fail(console.log);
And note that elements would only be available within that callback functions scope, as it's asynchronous.
Also note the added fail handler, and make sure you open the console and check for errors.
I thought it might be useful to someone else searching for this sort of thing to post what I ended up doing.
I used what I learned from adeneo's great suggestion (above) and was totally able to do what I needed to do. Thanks, adeneo
I needed to take team profile info from a bio page that often changes on the site and reuse & rearrange it on another page which needed to always be synced up.
So here is the code I ended up going with:
$.get('Bios.html', function(html){
var t_name = $('<div />', {html: html}).find('.t_name');
var t_creds = $('<div />', {html: html}).find('.t_creds');
var t_title = $('<div />', {html: html}).find('.t_title');
var t_bio = $('<div />', {html: html}).find('.t_bio');
var t_img = $('<img />', {html: html}).find('.t_img');
var t_imgTn = $('<img />', {html: html}).find('.t_imgTn');
var arrayLength = t_name.length;
for (var i = 0; i < arrayLength; i++) {
$('#name'+[i]).html(t_name[i]);
$('#creds'+[i]).html(t_creds[i]);
$('#title'+[i]).html(t_title[i]);
$('#bio'+[i]).html(t_bio[i]);
$('#bioImg'+[i]).html(t_img[i]);
$('#bioTn'+[i]).html(t_imgTn[i]);
}
}).fail(console.log);
});
It worked like a charm :-)

Ajax method does not fire on initial page load

Note: Please see edit at the bottom after reading this question.
This issue is only happening in IE 11, and only started occurring after a recent Windows update. There were 5 updates, one of which was specific to IE, so I uninstalled that one. However, the issue still exists. Before I consider rolling back the remaining updates, is there something inherently wrong in my code? The following is inside the document ready function:
$('#leftmenu>li').click(function () {
var clickedId = this.id;
$.ajax({
url: "Session/Index/",
cache: false,
success: function (result) {
if (result.length > 0)
{
performListItemAction(clickedId);
}
else
{
window.location.href = 'Home/Index/'
}
}
});
});
And the following is the performListItemAction method (a separate function not in document.ready):
function performListItemAction(item)
{
alert("clicked");
$(".tabui").each(function ()
{
$(this).hide();
});
$(".listitem").each(function ()
{
$(this).css("background", "transparent");
});
$(document.getElementById(item)).css("background-color", "#C8C8C8");
var targetId = $(document.getElementById(item)).data('target');
var target = $(document.getElementById(targetId));
target.show();
}
The alert clicked never appears when this problem happens, and that is how I concluded the ajax call is not working.
A few other notes:
This issue isn't happening on Firefox.
This only happens if I directly login to the page with a direct URL. If I log in via the application's home screen, and then go to the page that uses the above javascript, the issue doesn't occur.
Thank you.
EDIT: I just now see that the same issue is now occurring in Firefox as well. It's just much less frequent.
After trial and error, I think I fixed the issue by adding a forward slash to the beginning of each of the URLs, and added the type: "POST", to the ajax call. I don't know why it was working fine before, but now this works in all my attempts.

Apply Masonry on content from Facebook API

I have been trying to implement Masonry into this project for ages now, and I would be totally happy to have someone who can help me out. The internet is full of similar problems with masonry, but none of the given solutions could help me fix this.
Basically, I am pulling reviews from my Facebook page via the Open Graph API with the following code. The Facebook response data is converted from json to an array and then stored in the fb_reviews variable for later use. This one works as desired:
[...]
function (response) {
if (response && !response.error) {
//convert to array
fb_reviews = Object.keys(response).map(function (_) {
return response[_];
});
//only store needed data of fb_reviews[0]
fb_reviews = fb_reviews[0];
reviews();
}
;
});
[...]
This works perfectly. As you can see, the following reviews() function is called next to display the Facebook data, and this is where I would like masonry to kick in:
// DISPLAY REVIEWS
var print2 = "";
var reviews = function() {
var z = fb_reviews.length - 1;
var print2 = "";
for (i = 0; i < z; i++) {
//put together div container for every review object
print2 += '<div class="review" id="review-' + i + '"><div class="meta">' + fb_reviews[i].reviewer.name + ' rated ' + fb_reviews[i].rating + '/5</div><blockquote>' + fb_reviews[i].review_text + '</blockquote></div>';
}
print2 = $(print2);
// still works!!!
$("#reviews").append(print2);
//until here, everything still works, but the following does no longer work:
$("#reviews").masonry({
itemSelector: '.review'
});
}
;
The content is appended as desired etc., but I have literally tried any possible way to initialize masonry, including using all snippets I could find for appended content, e. g.:
$("#reviews").append( print2).masonry( 'appended', print2 );
There are many more, including reload and layout etc, but this does not make much sense to me, because there is no content in the #reviews-div-container until all Facebook reviews are loaded and appended.
Masonry ALWAYS seems to be called BEFORE the Facebook reviews are appended, no matter where I would position and spread the masonry code snippets.
So what is the best way to get Masonry initialized AFTER the Facebook data is stored and appended?
Thank you so much in advance for your help! Really appreciate your support
Simon

JSON file / script preventing page from displaying.

I have a JSON file that is approx 500 lines long. The script that reads in the file is the first thing to happen when the page is loaded. The script works perfectly. It updates a drop down box automatically depending on a users choice.
A moment ago I added an additional 50 lines or so to the JSON file, maintained correct syntax etc etc. When I reloaded the page there was nothing but a white screen, no error logs etc. I removed what I had added to the JSON and received the same white screen, I'd also reloaded the page after clearing cache and on different browsers, same thing.
I then commented out the script that calls the JSON, reloaded and voila, it's fine. I un-comment the script again so it is as it was and magic, it now works.
Can anyone explain what could be happening and how I might solve it please? I can't force it to happen again but that doesn't mean it won't.
Many thanks.
Simplified sample of JSON:
"angle" : [
{
"value":"degree",
"name":"Degree (deg)"
},
{
"value":"grad",
"name":"Grad (grad)"
}]
The script that calls it:
<script>
$.getJSON('JSON/conversionJSON.json', function(data){
$.each(data, function (key, conversions) {
console.log(key + ":" + conversions);
$.each(conversions, function (index, conversion) {
console.log("<li>Name: " + conversion.name + " :Value: " + conversion.value + "</li>");
if(key == "<?php echo $conversionType ?>"){
$("#to").append('<option class="'+key+'" id="'+conversion.value+'" value="'+conversion.value+'">'+conversion.name+'</option>');
}
});
});
});
</script>
Thanks

How to tell if an image has loaded correctly

Is there a way to tell, after the fact, whether an image (placed with the <img> tag, not via JS) has loaded correctly into a page? I have a gallery of head shots, and occasionally the third-party image server ends up serving up a 404. I can change the server-side code to use an onerror="showGenericHeadshot()", but I really want to avoid making changes to server-side code. Ultimately, I want to determine if an image is missing or broken and replace it with a generic "Image Not Found" graphic. Things I've tried:
Image.prototype.onerror = showGenericHeadshot -- doesn't work for <img> tags
$('img[src*=thirdpartyserver.com]).error(showGenericHeadshot) -- doesn't work in IE
$('img[src*=thirdpartyserver.com]).css('backgroundImage','url(replacementimage.gif)') -- works, but still doesn't get rid of the broken image icon in IE
<img scr='someUrl' id="testImage" />
jQuery('#testImage').bind('load',function(){
alert ('iamge loaded');
});
to avoid race condition do as below
<img _src="http://www.caregiving.org/intcaregiving/flags/UK.gif" />
// i have added an underscore character before src
jQuery('img').each(function(){
var _elm=jQuery(this);
_elm.bind('load',_imageLoaded).attr('src',_elm.attr('_src'))
});
function _imageLoaded()
{
alert('img loaded');
}
Unfortunately, I'm not able to accept either #TJ Crowder's nor #Praveen's excellent answers, though both do perform the desired image-replacement. #Praveen's answer would require a change to the HTML (in which case I should just hook into the <img> tag's own error="" event attribute. And judging by network activity, it look like if you try to create a new image using the url of an image that just 404ed in the same page, the request actually does get sent a second time. Part of the reason the image server is failing is, at least partly, our traffic; so I really have to do everything I can to keep requests down or the problem will only get worse..
The SO question referred to in #danp's comment to my question actually had the answer for me, though it was not the accepted answer there. I'm able to confirm that it works with IE 7 & 8, FF and webkit browsers. I'm doubtful it will work with older browsers, so I've got a try/catch in there to handle any exceptions. The worse case will be that no image-replacement happens, which is no different from what happens now without doing anything. The implementation I'm using is below:
$(function() {
$('img[src*=images.3rdparty.com]').each(
function() {
try {
if (!this.complete || (!$.browser.msie && (typeof this.naturalWidth == "undefined" || this.naturalWidth == 0))) {
this.src = 'http://myserver.com/images/no_photo.gif';
}
} catch(e) {}
}
);
});
Would an alternate text be sufficient? If so you can use the alt attribute of the img tag.
I think I've got it: When the DOM is loaded (or even on the window.load event — after all, you want to do this when all images are as complete as they're going to get), you can retroactively check that the images are okay by creating one new img element, hooking its load and error events, and then cycling through grabbing the src from each of your headshots. Something like the code below (live example). That code was just dashed off, it's not production quality — for instance, you'll probably want a timeout after which if you haven't received either load or error, you assume error. (You'll probably have to replace your checker image to handle that reliably.)
This technique assumes that reusing a src does not reload the image, which I think is a fairly reliable assumption (it is certainly an easily testable one) because this technique has been used for precaching images forever.
I've tested the below on Chrome, Firefox, and Opera for Linux as well as IE6 (yes, really) and IE8 for Windows. Worked a treat.
jQuery(function($) {
var imgs, checker, index, start;
// Obviously, adjust this selector to match just your headshots
imgs = $('img');
if (imgs.length > 0) {
// Create the checker, hide it, and append it
checker = $("<img>").hide().appendTo(document.body);
// Hook it up
checker.load(imageLoaded).error(imageFailed);
// Start our loop
index = 0;
display("Verifying");
start = now();
verify();
}
function now() {
return +new Date();
}
function verify() {
if (!imgs || index >= imgs.length) {
display("Done verifying, total time = " + (now() - start) + "ms");
checker.remove();
checker = undefined;
return;
}
checker[0].src = imgs[index].src;
}
function imageLoaded() {
display("Image " + index + " loaded successfully");
++index;
verify();
}
function imageFailed() {
display("Image " + index + " failed");
++index;
verify();
}
function display(msg) {
$("<p>" + now() + ": " + msg + "</p>").appendTo(document.body);
}
});​
Live example

Categories

Resources