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.
Related
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 an image tag that retrieves the src by an url, like:
<img src="http://localhost:2000/User/GetImage/1" />
That element is generated by jQuery, that is:
this.updateImage = function()
{
console.log("Change me!");
var context = this;
var imageSrc = webApiUrl + "User/GetImage/" + this._id;
$("#ga-application-header .user-info-image").each(function()
{
$(this).empty();
/* First try */$(this).append($("<img title='" + context._firstName + " " + context._lastName + "' />").attr("src", imageSrc));
/* Second try*/$(this).append("<img title='" + context._firstName + " " + context._lastName + "' src='" + imageSrc + "' />");
});
}
That lines with coments - first and second try - are the way I've tried the get this achieved.
Now the most important detail. When page is loaded, this function is called and displays the image. This works. But if I call it again(when user change it's picture) the image doesn't shows in IE and FF. Only on Chrome. IE and FF don't even open an image request(on network tab in console) for it. Note that the console.log text "Change Me!" is always called.
The issue is caused by the browser caching the image. The fix is to append a random query string to the image source.
First, I tend to use the following pattern as opposed to string concatenation.
var img = $('<img/>').attr('title',context._firstName).attr('src',imageSrc);
$(this).append(img);
Second, inside your this.updateImage, could you console.log/dir(this), I'm guessing your context isn't proper, you may want to do a var that = this, to keep your references in check.
I just ran into the same issue with IE.
This helped me:
Instead of
$form.find( ".classname" ).append( content );
This worked in IE and all other browsers:
$form.find( ".classname" ).html( $form.find( ".classname" ).html() + content );
Hope it helps somebody here...
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)
I am using a script i found here to dynamically generate short link for my Tweet buttons and it works perfectly well, but the only thing i cant seem to do is create the link to open in either a new tab or preferably a popup window.
I have tried several variations of the window.location section of the script but so far I've had no luck. If anybody could point me in the right direct I'd be very grateful.
This is the script I am using...
<script>
var TweetThisLink = {
shorten: function(e) {
// this stops the click, which will later be handled in the response method
e.preventDefault();
// find the link starting at the second 'http://'
var url = this.href.substr(this.href.indexOf('http:', 5));
BitlyClient.shorten(url, 'TweetThisLink.response');
},
response: function(data) {
var bitly_link = null;
for (var r in data.results) {
bitly_link = data.results[r]['shortUrl'];
break;
}
var tweet_text = "Text for the Tweet goes here"
window.location = "http://twitter.com/home?status=" + encodeURIComponent(tweet_text + ' ' + bitly_link + " #Hashtag1 #Hashtag2");
}
}
jQuery('.tweetlink').bind('click', TweetThisLink.shorten);
</script>
Many thanks in advance :)
Normally you could just do window.open:
window.open("http://twitter.com/home?status=" + encodeURIComponent(tweet_text + ' ' + bitly_link + " #Hashtag1 #Hashtag2");
BUT, since you are doing an ajax call before this happens, chances are that this window popup will be blocked by the browser, since the window.open command is no longer associated with the click (browsers allow a certain time before a window.open command falls under non-initiated "popup").
A solution would be to first open the window on click (in your shorten function):
var win = window.open('about:blank');
And then redirect in your response function:
win.location = 'http://twitter.com/etc...';
Demo: http://jsbin.com/usovik/1
Perhaps you're looking for
window.open("http://example.com");
I am trying to integrate a sticky headers technique like the one shown here... Persistent Headers.
I have tried to integrate it into my code and for the most part have been successful, however it isn't behaving correctly and I REALLY can't figure it out.
I'll try to explain in a nutshell what the page it is being used on does. I have a database with a table of students and another table of assessments. This page loops through a JSON object (recieved from the database via a PHP script) and then for each student in that first object fetches another JSON with their assessments. This all works fine. It does however create a fairly long page. Visually it looks like this...
Code rendered in Chrome
The code I have written based on that tutorial I posted above is supposed to clone headers specified by a class and then hide or show them based on some logic involving scrollTop the position of the element and the length of the element. This having the effect of the header sticking to the top of the page while the container it belongs to is still visible.
The problem is something is going wrong and although all the headers are shown in sequence they are way too early, they seem to hang about for different lengths of time, and these lengths do seem to correlate to how long the container it belongs to is.
So my code...
Firstly the function used to update the headers...
containerArray = new Array;
positionArray = new Array;
floatingHeaderArray = new Array;
function updateTableHeaders() {
$(".studentContainer").each(function(i) {
containerArray[i] = $(this);
var position = containerArray[i].position();
positionArray[i] = position.top;
var scrollTop = $("#main").scrollTop();
floatingHeaderArray[i] = $(".floatingHeader", this);
if ((scrollTop > positionArray[i]) && (scrollTop < positionArray[i] + containerArray[i].outerHeight(true))) {
floatingHeaderArray[i].css({
"visibility": "visible"
});
} else {
floatingHeaderArray[i].css({
"visibility": "hidden"
});
};
});
}
Now the code that generates the containers, headers and tabs.
$("#mainContent").fadeIn(0);
loadMessage = "Loading data for " + event.target.id;
$.getJSON('php/oneFullClass.php?techClass=' + event.target.id, function(data) {
$('#mainTitle').fadeOut(0);
$('#action').html('You are ' + actionIntent + 'ing ' + event.target.id);
$('#action').fadeIn(300);
$('#mainTitle').fadeIn(300);
$('#mainContent').append('<div id="scrollTopDisplay"></div>')
dynamicPositioning();
$.each(data, function(key, val) {
var thisPosition = positionArray[0]
$('#mainContent').append(
'<div class="studentContainer studentView" id="' + val.idStudent + '">' +
'<div class="studentName">' + val.name + ' ' + val.surname + ' - (' + val.form.substr(0, 1) + '/' + val.form.substr(1, 2) + ')</div>' +
'<div class="floatingHeader">' + val.name + ' ' + val.surname + ' - (' + val.form.substr(0, 1) + '/' + val.form.substr(1, 2) + ')</div>' +
'<div class="studentTarget"> Target: <strong>' + val.target + '</strong></div>' +
'</div>');
$(".studentContainer").hide().each(function(i) {
//$(this).slideDown(0);
$(this).delay(i * 50).slideDown(300).fadeIn(500);
})
//Get previous assessments for this student and build tabs
buildTabs('php/allPreviousAssess.php?sid=' + val.idStudent, val.idStudent);
});
});
$('#mainContent').append('<div id="expandAll" onClick="expandAll()">Expand</div>');
$('#mainContent').append('<div id="collapseAll" onClick="collapseAll()">Collapse</div>');
dynamicPositioning();
$('#expandAll').delay(300).fadeIn(300);
$('#collapseAll').delay(300).fadeIn(300);
$("#main").scroll(updateTableHeaders);
I think that's all the info you'll need but I'll post any other code that may be referenced in this code if you think it'll help figure it out.
I have a suspicion that the problem is something to do with the animated slide in effect I am using on the 'assessment cards' messing with the position values, or possible position()'s inability to get positions of hidden elements. However, as I call updateTableHeaders() with every scroll event, this shouldn't be an issue as all animation is over by the time you are given access to the layout (there is a modal shade effect that only dissapears once all AJAX requests are complete.
I hope someone can help, this one is making me unhappy! :(
Balloon, a library I wrote for easily making your headers stick, is pretty hassle-free. You simply make a Balloon object instance, specifying if you want your sticky headers to be stacked or replaced, and then inflate the headers by passing in the strings of their ids. Give it a try and let me know if it helped you:
https://github.com/vhiremath4/Balloon
If you find any issues with it, file a bug report on the repository, but I feel like it should do its job in your case.