Is there a method, similar to $(document).ready(), that can be applied
to an arbitrary element? For example, if an ajax call sets the content
of a DIV and includes a lot of IMG tags, is there a way to trigger
a function call when all of the images have completed loading? Something
along the lines of:
$.ajax({
url: '/get/my/page.php',
dataType: "html",
success: function(response)
{
$('#my_element').html(response);
$('#my_element').ready(function() {alert('all images loaded');});
}
});
Thanks for your advice.
If you're specifically interested in images being loaded, then you can try imagesLoaded, which seems to cover the example case that you mention.
Identical to $("document").ready() -- no, however, there are ways that you can make it work:
Put whatever function you need executed as a callback to the AJAX call:
$.get("link.php?item=1", function() {
//callback function here
})
You can have an onchange event listener that triggers whenever the div is being changed and you can specifically trigger a function after a certain number of elements is loaded:
$("#div").on('change', function() {
if ( $("#div").length > DESIRED_NUMBER_OF_ELEMENTS + 1)
{
//Execute function here
}
})
The on('change') can be used in any which way you want: it can trigger a function based on the number of elements, based on the nature of elements inside (if it's an image, a link, another div, etc), anything you can think of.
Something along these lines should do what you want.
onImagesLoaded('#my_element img',function(){
console.log('images have all loaded')
});
function onImagesLoaded(seletor,callback){
var $images = $(seletor);
var count = $images.length;
$images.each(function(img){
//create an image
var tempImage = new Image();
//set a function for the onload event
tempImage.onload = function(){
count--;
//if the count is 0 it means all images are done loading
if(count===0){
callback();
}
};
//set the source to the src of the image.
tempImage.src = $(img).attr('src');
});
}
Try
var request = $.ajax({url: "/get/my/page.php", dataType: "html"});
request.done(function (data, textStatus, jqxhr) {
// parse returned `data` string for html
var html = $.parseHTML(data),
//
len = html.length,
div = $("div");
// do stuff when all images loaded into `div`
div.on("imgsready", function(e, htmlimgs, divimgs) {
console.log("ready", htmlimgs, divimgs);
$(e.target).prepend(divimgs + " images ready<br>" )
});
// set `div` html contents to `html` string
$.when(div.html(html)
// return image `on` `load` event
, $("img", div)
.load(function(e) {
// return image `promise` object
return $(e.target).promise()
})
)
.then(function (el, i) {
// if `div` contains `len` length images , call `imgsready` event
return el.children(i).length === (i.length && len)
&& el.children(i).eq(len -1).is("*")
? el.trigger("imgsready", [len, i.length])
// else check again in 1000ms
: setTimeout(function() {
el.children(i).eq(len -1).is("*") ?
el.trigger("imgsready", [len, i.length])
: console.log(el.children(i).length)
},1000)
});
});
jsfiddle http://jsfiddle.net/guest271314/vhuaen71/
Related
I have UI with a list of users in a table. Each entry / user has two buttons. One of the buttons is a 'check' button.
<button type="submit" id="$id_from_db" class="bg-aqua btnCheckUser">Check</button>
When a check button is clicked for a particular user a POST request is sent to a server. While the request is loading all buttons should be disabled, the button which started the request should change its class from bg-puple to bg-aqua
and its text from Check to Checking.... If the request returns an error (which is indicated by result having the value 1) the button should change its class from bg-aqua to bg-danger. If there is no error the class should change from bg-aqua to bg-navy and the text from Checking... to User Okay.
I'm able to achieve this but it does not only affect the button which started the request but all buttons.
This is my code:
$(document).on("click", ".btnCheckUser", function() {
var Item_Number = $(this).attr("Item_Number");
/************************** MANIPULATE BUTTONS *******************************************************************************/
$(this).removeClass('bg-purple').addClass('bg-aqua');
$(this).html('Checking ...');
$(this).attr("disabled", true);
$('.btnViewUser').attr("disabled", true);
/******************************* PROCESS AJAX **************************************************************************/
var value = {
Item_Number: Item_Number
};
$.ajax({
url: "./plugins/serverside/CheckUserStatus",
type: "POST",
data: value,
success: function(data, textStatus, jqXHR) {
var data = jQuery.parseJSON(data);
if (data.result == 1) {
$(this).removeClass('bg-aqua').addClass('bg-danger');
$("#CheckUser").html('Failed!');
$('.btnCheckUser').attr("disabled", false);
$('.btnViewUser').attr("disabled", false);
setTimeout(function() {
var table = $('#User_Table').DataTable();
table.ajax.reload(null, false);
}, 3500);
} else if (data.result == 2) {
//------------------------ IF User Okay -------------------------------------------------------------------------------------------------------------------
$("#CheckUser").removeClass('bg-aqua').addClass('bg-navy');
$("#CheckUser").html('User Okay');
$('.btnCheckUser').attr("disabled", false);
$('.btnViewUser').attr("disabled", false);
}
How can I fix this and only affect the button which started the request, but still disable all buttons when a request is loading?
JSFiddle
I stripped the code down to the parts which matter for the button logic. I'm using a dummy API and I randomly generate the result value as I have no access to the actual API you're using.
$(() => $('.btnCheckUser').on('click', ({ target }) => clickHandler(target)));
function clickHandler(button) {
// Disable all buttons when one of them is clicked
$('.btnCheckUser').prop('disabled', true);
$('.btnViewUser').prop('disabled', true);
// Remove all non standard classes, then add 'loading' class and text
$(button).removeClass('bg-purple').removeClass('bg-navy').removeClass('bg-danger').addClass('bg-aqua');
$(button).text('Loading...')
$.ajax({
url: 'https://reqres.in/api/users?delay=3',
success: raw => {
// Random result value
const result = Math.random() > 0.5 ? 1 : 2;
if (result === 1) {
// Something went wrong, add 'danger' class and text
$(button).addClass('bg-danger');
$(button).text('Failed!')
} else if (result === 2) {
// Everything went fine, add 'success' class and text
$(button).addClass('bg-navy');
$(button).text('Success!');
}
},
error: () => {
// Add 'danger' class if something goes wrong
$(button).addClass('btn-danger');
},
complete: () => {
// Enable all buttons as we got a response
$('.btnCheckUser').prop('disabled', false);
$('.btnViewUser').prop('disabled', false);
// Remove 'loading' class as we got a response
$(button).removeClass('bg-aqua');
}
});
}
This should give you the expected behavior.
hello there this is truly easy what you have to do is
function TheClickerFunction(){
$("body").on("click",".YourButton",function(){
//this will only affect the clicked element
$(this).attr("disabled",true);
});
}
$(document).ready(function(){
TheClickerFunction();
});
/*
i think creating a global counter and increment it on each element would b better*/
var GlobalCounter= 0;
function DynamicBuilder(){
var stringBuilder="";
for(var i = 0; i< lengthOfYourElement ; i++){
GlobalCounter+=1;
stringBuilder+="<input type='submit' id='myButton"+GlobalCounter+"'></input>";
}
$("body").append(stringBuidler);
}
in this way each time a click is made
$(".yourClass").click(function(){
var elementID = $(this).attr("id");
//here you can do what ever you want with its id
})
*/
Using tutorials found i'm currently loading new pages with this:
$("a.nav-link").click(function (e) {
// cancel the default behaviour
e.preventDefault();
// get the address of the link
var href = $(this).attr('href');
// getting the desired element for working with it later
var $wrap = $('#userright');
$wrap
// removing old data
.html('')
// slide it up
.hide()
// load the remote page
.load(href + ' #userright', function () {
// now slide it down
$wrap.fadeIn();
});
});
This loads the selected pages perfectly, however the pages have forms that themselves use ajax to send the following:
var frm = $('#profileform');
frm.submit(function (ev) {
$.ajax({
type: frm.attr('method'),
url: frm.attr('action'),
data: frm.serialize(),
success: function (data) {
alert(data)
}
});
However this is not sending the form as it did before the page itself was called to the parent page via ajax. Am I missing something? Can you not use an ajax call in a page already called by ajax?
I also have other issues, for example I disable the submit button unless there are any changes to the form, using:
var button = $('#profile-submit');
var orig = [];
$.fn.getType = function () {
return this[0].tagName == "INPUT" ? $(this[0]).attr("type").toLowerCase() : this[0].tagName.toLowerCase();
}
$("#profileform :input").each(function () {
var type = $(this).getType();
var tmp = {
'type': type,
'value': $(this).val()
};
if (type == 'radio') {
tmp.checked = $(this).is(':checked');
}
orig[$(this).attr('id')] = tmp;
});
$('#profileform').bind('change keyup', function () {
var disable = true;
$("#profileform :input").each(function () {
var type = $(this).getType();
var id = $(this).attr('id');
if (type == 'text' || type == 'select') {
disable = (orig[id].value == $(this).val());
} else if (type == 'radio') {
disable = (orig[id].checked == $(this).is(':checked'));
}
if (!disable) {
return false; // break out of loop
}
});
button.prop('disabled', disable);});
However this also doesn't work when pulled to the parent page. Any help much appreciated! I'm really new to ajax so please point out any obvious mistakes! Many thanks in advance.
UPDATE
Just an update to what i've found. I've got one form working by using:
$(document).on('mouseenter', '#profile', function() {
However the following:
$(document).on('mouseenter', '#cancelimage', function() {
$('#cancelimage').onclick=function() {
function closePreview() {
ias.cancelSelection();
ias.update();
popup('popUpDiv');
$('#imgForm')[0].reset();
} }; });
Is not working. I understand now that I need to make it realise code was there, so I wrapped all of my code in a mouseover for the new div, but certain parts still don't work, so I gave a mouseover to the cancel button on my image form, but when clicked it doesn't do any of the things it's supposed to.
For anyone else who comes across it, if you've got a function name assigned to it, it should pass fine regardless. I was trying to update it, and there was no need. Doh!
function closePreview() {
ias.cancelSelection();
ias.update();
popup('popUpDiv');
$('#imgForm')[0].reset();
};
Works just fine.
I'm working on a banner for a website and I need it to loop through the images. My problem is that it plays through the images once and then stops. I've tried everything that I can think of with no luck. I'm sure this is simpler than I'm making it, but some help would be greatly appreciated. The latest version is below.
$(document).ready(function(){
// Variables required by script
var currentimage;
// Load Gallery XML file
$.ajax({
url: 'banner.xml',
type: 'GET',
dataType: 'xml',
error: function(){
alert('Error loading XML document');
},
success: function(xmlData){
// do something with xml
setupImages(xmlData);
}
});
// Display images
function setupImages(xmlData) {
// read xml and use it to populate page
//get first image
currentimage = $(xmlData).find("image:first");
// Fade in image after countdown
var t = setTimeout(function(){showNewImage()}, 1000);
}
// Display the image, caption, rating and label
function showNewImage() {
var image = $(currentimage).find("path").text();
var caption = $(currentimage).find("caption").text();
$("#imagelabel").removeClass("active");
// Fade out current image and fade in new image
$("#bannerimgholder").animate({opacity:0},500,
function(){
$(this).css({"backgroundImage":"url("+image+")"}).animate({opacity:1},1000,
function(){
$("#imagelabel").addClass("active");
});
});
// Add caption
$("#imagelabel").text(caption);
var to = setTimeout(function(){getNextImage()}, 5000);
}
function getNextImage(){
var tmp = $(currentimage).next();
if ($(tmp).find("path").text()=="") {
currentimage = $(xmlData).find("image:first");
} else {
currentimage = tmp;
}
showNewImage();
}
});
Your code is using next(), which will return nothing once you reach the last image.
You need to use a different test to close the loop, for example:
tmp.length==0
Note that tmp is already a jQuery object, so you don't need to wrap it in $().
This page offers an example of nextOrFirst() function that does what you want.
Here is a solution that I came up with.
First I added an element to the end of my xml file with just a 'path' attribute of "last".
Next, I add the following variable to save the path name of the first element:
var imagepathtext;
Then, in the setupImages(xmlData) function I added the following:
imagepathtext = $(currentimage).find("path").text();
Lastly, I changed the getNextImage() function from
function getNextImage(){
var tmp = $(currentimage).next();
if ($(tmp).find("path").text()=="") {
currentimage = $(xmlData).find("image:first");
} else {
currentimage = tmp;
}
showNewImage();
}
to
function getNextImage(){
var tmp = $(currentimage).next();
if ($(tmp).find("path").text()=="last") {
while ($(tmp).find("path").text()!=firstimagepath)
{
var tmp1 = $(tmp).prev();
tmp = tmp1;
}
currentimage = tmp;
} else {
currentimage = tmp;
}
showNewImage();
}
And just like magic it loops correctly now!
I would like to create a JavaScript that clicks a particular LINK after a certain amount of delay say e.g. 10 seconds on an HTML page.
Can you please provide me with the JavaScript, please? What I only managed to find after doing a search on Google is click a particular LINK but without a delay.
Can you help me please?
Thanks.
Include this method (however you want):
function fireEvent(element,event) {
if (document.createEvent) {
// dispatch for firefox + others
var evt = document.createEvent("HTMLEvents");
evt.initEvent(event, true, true ); // event type,bubbling,cancelable
return !element.dispatchEvent(evt);
} else {
// dispatch for IE
var evt = document.createEventObject();
return element.fireEvent('on'+event,evt)
}
}
Then call it:
window.setTimeout(function() {
var e = document.getElementById('yourLinkId');
if(e) fireEvent(e, 'click');
}, 10000);
window.setTimeout(function() {
window.location = "http://your_url_here.com";
}, 10000);
The second parameter is the time in milliseconds. So 10000 milliseconds is 10 seconds.
If you need the delay something like the one shown on this site (See the "Testimonials" container at the bottom-left corner of the page), use the following jQuery code.
(function($){
$(document).ready(function(){
var el = $("#testimonial"); //The id of the container. It may be a `<div>`
if (el){
RotateTestimonial();
setInterval(RotateTestimonial, 20000);
}
});
function RotateTestimonial(){
var pageUrl = "RandomTestimonial.jsp" //The page where the request goes.
$.ajax({
type: "GET",
url: pageUrl,
cache:false,
success: function(msg) {
$("#testimonial").slideUp('slow').fadeOut(3000, function (){
var el = $("#testimonial");
el.html(msg);
el.slideDown('slow').fadeIn('slow');
});
}
});
}
})(jQuery)
The script is on jsfiddle here : CODE
What it does at the moment: it's a form that have two types of URL field textarea and input, it converts the texts in those fields to a link to be click-able.
How it works: if you click next to the link/links you can edit the link or on a double click on the link. IF you click once on the link it takes you to that page.
Last update: i added the .trigger('blur'); on the last line, Because before i did that, the text area was showing the links like one merged link, for example : test.com and test2.com were showing test.comtest2.com, after i added this last update, the split for textera work also on the load of page not just on the edit of textarea ( it was working without the last update but only when you edit the textarea and put between links a space, and i want it to be working on the load of page because the textarea format was sent already as one link pre row ).
My problem: after i did this last update, the double click is messed up, it should just be able to edit the link and don't go to that page unless one click, but now it edits it and in like one second it goes also to that page. I want the double click just to edit without going to that page. and to go only with one click.
Thanks a lot in advance!
The code also here:
$('.a0 a').click(function(){
var href = $(this).attr('href');
// Redirect only after 500 milliseconds
if (!$(this).data('timer')) {
$(this).data('timer', setTimeout(function () {
window.open(href, '_blank')
}, 500));
}
return false; // Prevent default action (redirecting)});
$('.a0').dblclick(function(){
clearTimeout($(this).find('a').data('timer'));
$(this).find('a').data('timer', null);
$(this).parent().find('input,textarea').val($(this).find('a').text()).show().focus();
$(this).hide();})
$('.a0').click(function(){
$(this).parent().find('input,textarea').val($.map($(this).find('a'),function(el){return $(el).text();}).join(" ")).show().focus();
$(this).hide();})
$('#url0, #url1,#url4').each(
function(index, element){
$(element).blur(function(){
var vals = this.value.split(/\s+/),
$container = $(this).hide().prev().show().empty();
$.each(vals, function(i, val) {
if (i > 0) $("<span><br /></span>").appendTo($container);
$("<a />").html(val).attr('href',/^https?:\/\//.test(val) ? val : 'http://' + val).appendTo($container);;
}); })
}).trigger('blur');
A double-click is always predeeded by the following chain of events:
mousedown, mouseup, click, mousedown, mouseup, click, dblclick
You can make your click-events wait and check if a double-click event happened afterwards. setTimeout is your friend. Be sure to copy any data you need from the event object passed to your handler. That object is destroyed after the handler finished - which is before your delayed handler is invoked.
You can manually dispatch a double click event to prevent click-events from being executed prior to them. See the Fiddle
// ms to wait for a doubleclick
var doubleClickThreshold = 300;
// timeout container
var clickTimeout;
$('#test').on('click', function(e) {
var that = this;
var event;
if (clickTimeout) {
try {
clearTimeout(clickTimeout);
} catch(x) {};
clickTimeout = null;
handleDoubleClick.call(that, e);
return;
}
// the original event object is destroyed after the handler finished
// so we'll just copy over the data we might need. Skip this, if you
// don't access the event object at all.
event = $.extend(true, {}, e);
// delay click event
clickTimeout = setTimeout(function() {
clickTimeout = null;
handleClick.call(that, event);
}, doubleClickThreshold);
});
function handleClick(e) {
// Note that you cannot use event.stopPropagation(); et al,
// they wouldn't have any effect, since the actual event handler
// has already returned
console.log("click", this, e);
alert("click");
}
function handleDoubleClick(e) {
// this handler executes synchronously with the actual event handler,
// so event.stopPropagation(); et al can be used!
console.log("doubleclick", this, e);
alert("doubleclick");
}
jsfiddle refuses to load on my connection for some reason, so cant see the code.
Based on your explanation i suggest you look into event.preventDefault to add more control on what should happen on your click events. This could be used in conjunction with #rodneyrehm's answer.
Refer to my previous answer.
For your quick reference, I have pasted my answer here
$('.a0 a').click(function(){
var href = $(this).attr('href');
// Redirect only after 500 milliseconds
if (!$(this).data('timer')) {
$(this).data('timer', setTimeout(function() {
window.open(href, '_blank')
}, 500));
}
return false; // Prevent default action (redirecting)
});
$('.a0').dblclick(function(){
var txt = document.createElement('div');
$.each($(this).find('a'), function(i, val) {
clearTimeout($(val).data('timer'));
$(val).data('timer', null);
$(txt).append($(val).text());
$("<br>").appendTo(txt);
});
var content = $(this).parent().find('input,textarea');
var text = "";
$.each($(txt).html().split("<br>"), function(i, val) {
if (val != "")
text += val + "\n";
});
$(content).html(text);
$(this).hide();
$(content).show().focus();
})
$('#url0, #url1, #url4').each(function(index, element) {
$(element).blur(function(){
if ($(this).val().length == 0)
$(this).show();
else
{
var ele = this;
var lines = $(ele).val().split("\n");
var divEle = $(ele).hide().prev().show().empty();
$.each(lines, function(i, val) {
$("<a />").html(val).attr({
'href': val,
'target': '_blank'}).appendTo(divEle);
$("<br/>").appendTo(divEle);
});
}
});
});