jQuery delay() not working as intended - javascript

Working on a small piece of code for a custom shopping cart. I want to change a button to show a success message for 2 seconds, then revert the button back to the original HTML.
HTML...
<button id="42" class="btn btn-primary btn-block" type="button" onclick="added_to_order('42')">1st Semester<span class="glyphicon glyphicon-chevron-right float-right"></span></button>
Javascript...
function added_to_order(id){
var old_html = $('#' + id + '').html();
$('#' + id + '').html('<span class="glyphicon glyphicon-ok-sign"></span> Added to your order!');
$('#' + id + '').removeClass('btn-primary').addClass('btn-success').delay(2000).html(old_html);
}
Everything is fine, except I'm not getting the delay of 2 seconds before the button is updated with the old HTML.
Any ideas?

It's best to use the setTimeout function in this case.
function added_to_order(id){
var old_html = $('#' + id + '').html();
$('#' + id + '').html('<span class="glyphicon glyphicon-ok-sign"></span> Added to your order!');
$('#' + id + '').removeClass('btn-primary').addClass('btn-success');
setTimeout(function() {
$('#' + id + '').html(old_html);
}, 2000);
}

I don't think that any old function qualifies to be a valid member of the jQuery effects queue. I've wrapped your code in some queue function calls. Take a look at the other examples on that page for more ideas.
function added_to_order(el){
var old_html = $(el).html();
$(el).html('<span class="glyphicon glyphicon-ok-sign"></span> Added to your order!');
$(el)
.queue(function () {
$(el).removeClass('btn-primary').addClass('btn-success').dequeue();
})
.delay(2000)
.queue(function () {
$(el).html(old_html).dequeue();
});
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="btn btn-primary btn-block" type="button" onclick="added_to_order(this)">1st Semester<span class="glyphicon glyphicon-chevron-right float-right"></span></button>

Related

MVC Data passage from Javascript Function with Bootstrap Modal

I have a button that open a confirmation modal created with bootstrap.
When the modal is confirmed i execute a Javascript function with the data passed from the first button.
This is the button that open the modal:
<input class='btn btn-info btnChiusura' type='button' value='Close Day' data-corriere="Bartolini" data-magazzino="#item.NomeMagazzino" data-committente="#ViewBag.comm" />
This is the code for click on each btnChiusura of my page:
$('.btnChiusura').on('click', function (event) {
event.preventDefault();
_self = $(this);
var corriere = _self.data('corriere');
var magazzino = _self.data('magazzino');
var committente = _self.data('committente');
$("#myModalLabel").text("Close day " + _self.data('corriere') + " " + _self.data('magazzino'));
$("#myModaBody").text("Conferm close day for " +_self.data('corriere') + " " + _self.data('magazzino')+"?");
$("#myModalClick").attr("onclick", "Close(" + _self + ");");
$("#myModal").modal();
});
});
I try to call this function:
function ChiusuraGiornata(el) {
alert(el.data('corriere'));};
But i have this error on console:
Unexpected identifier
How can i pass _self data to another javascript funtion?
Thanks to all
With your current code you are reading the data attribute of the clicked button and using that to set the title and body content of the modal dialog. If you want to access that later using the data attribute again when the button in modal is clicked. You need to set those same values to some elements's data attribute.
You can set those to the "save"/"delete" button which is in the modal so that you can access it when user click on one of them.
Assuming your modal footer has these 2 buttons.
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="button" id="btn-save" class="btn btn-primary">Save changes</button>
</div>
Now, before firing the modal, find the button with id "btn-save" and set it's data attribute.
$('.btnChiusura').on('click', function (event) {
event.preventDefault();
_self = $(this);
var corriere = _self.data('corriere');
var magazzino = _self.data('magazzino');
var committente = _self.data('committente');
$("#myModalLabel").text("Close day " + _self.data('corriere') +
" " + _self.data('magazzino'));
$("#myModaBody").text("Conferm close day for " + _self.data('corriere') + " "
+ _self.data('magazzino') + "?");
$("#myModalClick").attr("onclick", "Close(" + _self + ");");
// Set the attributes to the button in modal.
$("#btn-save").attr("data-magazzino", magazzino).attr("data-corriere", corriere);
$("#myModal").modal();
});
Now when the button is clicked,you can read it's data("magazzino") to get the value you set.
$(document).on("click","#btn-save",function (e) {
e.preventDefault();
alert($(this).attr("data-corriere"));
alert($(this).attr("data-magazzino"));
});

How to get parent element's ID?

So I got into this tricky situation. I have a variable which present table data:
row += '<td>' + c + '<button class="btn btn-success" id="' + callId + ' " onclick="handleCall()">Call</button>' + '<button class="btn btn-danger" id="' + hangupId + ' " onclick="handleHangUp()">Hangup</button>' + '</td>' ;
Latter on I will append that into my table. Now, when I click Call button, I want to get the button's Id. I have tried this way:
function handleClick() {
console.log(this);
}
but it refer to window object. Can anybody show me the way to achieve my goal? Thanks
Simply pass the elements ID as a parameter to keep it simple,
Change,
onclick="handleCall()"
to,
onclick="handleCall(this.id)"
this referring to the button in question the user is pressing.
then,
function handleClick(id) {
console.log(id);
}
Finally don't use inline event handlers as they are a pain to work with in the long run, make use of the addEventListener method.
row += '<td>' + c + '<button class="btn btn-success" id="' + callId + ' " onclick="handleCall(this)">Call</button>' + '<button class="btn btn-danger" id="' + hangupId + ' " onclick="handleHangUp()">Hangup</button>' + '</td>' ;
function handleClick(element) {
console.log(element);
//here you will have all element properties
}
There are two ways you can do this, you can do it via jQuery by using attr or if you are wanting to stay vanilla Javascript then you can use .id.
For jQuery please see code below:
console.log(jQuery('element').attr('id'));
For Javascript please see code below:
console.log(element.id);

jQuery AJAX Get Callback Only Called Once [duplicate]

This question already has answers here:
Prevent browser caching of AJAX call result
(21 answers)
Closed 6 years ago.
I have this problem where the jQuery get function inside my updateMyApps isn't being called correctly. I call the function right after declaring it and that works perfectly. It loops through the data and appends the elements to the DOM.
But when I submit the form #addapplicationform it runs the jQuery post function which works correctly but the updateMyApps function doesn't seem to be working correctly when that happens.
The console.log("Test"); always seems to get called. Even when submitting the form. But for some reason the callback function for that get request only gets called that one time on page load.
<script>
function updateMyApps() {
console.log("Test"); //Always works
$.get("/api/clients", function(data) {
console.log(data); //Works first time
$("#myapps").html("<h4>My Applications</h4>");
data.forEach(function (item) {
var element = '<div>' + item.name + '</div>' + '<div>' + item.id + '</div>' + '<div>' + item.secret + '</div>' + '<input type="submit" class="submit btn btn-primary form-control" value="Edit" style="width: 100px;">';
$("#myapps").append(element);
});
});
}
updateMyApps(); // Works perfectly
$("#addapplicationform").submit(function( event ) {
event.preventDefault();
$.post("/api/clients", $( "#addapplicationform" ).serialize(), function () {
updateMyApps(); //Doesn't work
});
});
</script>
Any ideas on why the get request callback is only firing once?
EDIT
Forgot to mention this. It looks like the GET /api/clients only is getting called on page load. When submitting the form it isn't even hitting my back end at all.
EDIT 2
Realized this was a caching issue. Adding $.ajaxSetup({ cache: false }); seems to have fixed the issue. Also marked the question as duplicate of where I found that code snippet.
Try adding a console.log in your submit....
<script>
function updateMyApps() {
console.log("Test"); //Always works
$.get("/api/clients", function(data) {
console.log(data); //Works first time
$("#myapps").html("<h4>My Applications</h4>");
data.forEach(function (item) {
var element = '<div>' + item.name + '</div>' + '<div>' + item.id + '</div>' + '<div>' + item.secret + '</div>' + '<input type="submit" class="submit btn btn-primary form-control" value="Edit" style="width: 100px;">';
$("#myapps").append(element);
});
});
}
updateMyApps(); // Works perfectly
$("#addapplicationform").submit(function( event ) {
event.preventDefault();
console.log("works!!!"); // <-- add this console.log
$.post("/api/clients", $( "#addapplicationform" ).serialize(), function () {
updateMyApps(); //Doesn't work
});
});
</script>

Is a JavaScript function not executed always the same way?

Using javascript to create the content of the body of a modal i notice that the result is not always the same. Sometimes the modal body is empty some times is as expected. The function is this:
function newServiceModal() {
$("#newServicesModal-bd").html("");
$("#newServiceModalHiddenId").val("");
$("#newServiceModal-title").html("New Service - body not created yet ");
var modalbody = "";
var div = document.createElement('div');
//var provideroptions = {
// providerid:providerid
//}
$.ajax({
type: 'post',
url: baseSiteURL + 'home/ReturnProviders', //supposed to return all available providers
//data: options
}).done(function (data) {
$("#newServiceModal-title").html("New Service - body was created");
modalbody = modalbody.concat(" <div class='col-md-4'> <p>Provider</p><select id='newproviderSelect' class='form-control'>");
for (i = 0; i < data.length; i++) {
if (i==0)
modalbody = modalbody.concat(" <option value=" + data[i].id + " selected>Type: " + data[i].providerType + "</option>");
else
modalbody = modalbody.concat(" <option value=" + data[i].id + ">Type: " + data[i].providerType + "</option>");
}
modalbody = modalbody.concat('</select></div>');
div.innerHTML = modalbody;
document.getElementById('editServicesModal-bd').appendChild(div);
$("#newServiceModal-title").html("New Service - body was created");
})
//var customeroptions = {
// customerid: customerid
//}
$.ajax({
type: 'post',
url: baseSiteURL + 'home/ReturnCustomers', //supposed to return all available customers
//data: options
}).done(function (data) {
modalbody = modalbody.concat(" <div class='col-md-4'> <p>Customer</p><select id='newcustomerSelect' class='form-control'>");
for (i = 0; i < data.length; i++) {
if (i==0)
modalbody = modalbody.concat(" <option value=" + data[i].id + " selected>" + data[i].company + "</option>");
else
modalbody = modalbody.concat(" <option value=" + data[i].id + ">" + data[i].company + "</option>");
}
modalbody = modalbody.concat('</select></div>');
div.innerHTML = modalbody;
document.getElementById('editServicesModal-bd').appendChild(div);
})
//var applicationroptions = {
// applicationid: applicationid
//}
$.ajax({
type: 'post',
url: baseSiteURL + 'home/ReturnApplications', //supposed to return all available applications
//data: options
}).done(function (data) {
modalbody = modalbody.concat(" <div class='col-md-4'> <p>Application</p><select id='newapplicationSelect' class='form-control'>");
for (i = 0; i < data.length; i++) {
if (i==0)
modalbody = modalbody.concat(" <option value=" + data[i].id + " selected>" + data[i].name + "</option>");
else
modalbody = modalbody.concat(" <option value=" + data[i].id + ">" + data[i].name + "</option>");
}
modalbody = modalbody.concat('</select></div>');
div.innerHTML = modalbody;
document.getElementById('newServicesModal-bd').appendChild(div);
})
$("#newServiceModal").modal('show');
}
the modal html is this:
<div id="newServiceModal" class="modal fade local-modal" role="dialog" aria-hidden="true" position="fixed">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<section id="newService">
#using (Html.BeginForm("Services", "Home", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 class="modal-title" id="newServiceModal-title">original title</h4>
</div>
<div id="newServiceModalHiddenId"></div>
<div class="modal-body row" id="newServicesModal-bd" style='margin-right:20px; margin-left:20px;'>
#* bootstrap.min.css applies here this rule : .row{margin-right:-15px;margin-left:-15px} *#
#* services.js puts content here *#
</div>
<div class="modal-footer">
<div class="col-md-6 pull-left">
<button id="savebtn" type="button" class="btn btn-primary ladda-button" data-style="expand-right" data-size="l" onclick="saveNewService()"><span class="ladda-label">Save</span></button>
<button type="button" class="btn btn-warning" data-dismiss="modal" aria-hidden="true">Close</button>
</div>
#*<div class="col-md-6">
<button type="button" class="btn btn-danger" onclick="deleteUser()">Delete</button>
</div>*#
</div>
}
</section>
</div>
</div>
The first line of the function
$("#newServicesModal-bd").html("");
is emptying the modal body (to not have concatenated the previous content with what is about to be created).
I imagine my problem is related with this, because 9 of 10 times the modal is created as expected but some times its body is empty, which makes me suspect that either the body content is not created at all or the
$("#newServicesModal-bd").html("");
is executed after the body content is created.
To verify that the content does get created i have this
$("#newServiceModal-title").html("New Service - body not created yet ");
right after i empty the body of the modal and i put this
$("#newServiceModal-title").html("New Service - body was created");
when i get some content created.
I would see the title always to be "New Service - body was created" so i think that its safe to assume that the body does get created.
I read about hoilsting and scope and i dont think think that they have to do with this matter can't find but in any case i can find any reason for this inconsistent behaviour.
If any one could point out why this happens i would appreciate it.
Thank you for reading this.
Solution (?)
I investigated a little more and i want to make some more comments, maybe i will clarify the problem better.
The function newServiceModal() is making 3 calls to different other functions. ReturnProviders, ReturnCustomers and ReturnApplications(which are in my HomeController class) and they are calling the functions that are actually retrieving the data from the database.
I found that the problem occurs only when they (ReturnProviders, ReturnCustomers and ReturnApplications) are not called with this order. The reason that they are not called with the same order as they are written in the function was shown to me by a seasoned programmer after i explained him the problem and he googled, totally he needed 5 minutes.
I just added
async: false
in my ajax requests and now the results are coming in the order that are expected.
It was pointed out to me that my approach is not correct and i should be making one ajax call for all the data i need instead of 3. So i will post the correct solution as soon as i do it.
Thank you all for your time and help.
I managed to solve the problem by making one ajax call, i think that the solution is irrelevant with my question, if anyone is interested email me to give more information.
As far as my original question is concerned the answer is that the ajax requests are being executed as they are written in the function but sometimes the results are not coming back in the same order unless this is added to the ajax call
async: false
Solution was found in this post
How do I make jQuery wait for an Ajax call to finish before it returns?
Like #ManoDestra said in the comments, you shouldn't execute functions that reference or manipulate DOM elements until after they have been loaded. It's best practice to put your newServiceModal() code at the end of the body or run it inside a window.onload event or $(function(){ ... }) wrapper.

jQuery: Count number of child elements inside a div, update number when element added/removed

I'm adding child elements inside a div using append() and counting/adding a number to each one using ++ to +1 each time an item is added.
I want the value to automatically adjust if an item is removed, for example if I have 4 elements:
Element #1
Element #2
Element #3
Element #4
Currently if element #3 is removed the list looks like this:
Element #1
Element #2
Element #4
But I want it to look like this:
Element #1
Element #2
Element #3
Appreciate any advice on what I should use to achieve this, thanks.
Example code: https://jsfiddle.net/wepsrzkm/
var price_rule_html = '<button class="remove_price_rule button" type="button">Remove Element</button>';
var price_rule_count = 1;
var price_rule_count = jQuery(".price_rule_area_1").children().length;
jQuery('.add_price_rule').click(function () {
price_rule_count++;
jQuery('.price_rule_area_1').append('<div class="price_rule_wrapper"><div class="price_rule_count">Element #<span>' + price_rule_count + '</span></div>' + price_rule_html + '</div>');
jQuery(".remove_price_rule").click(function() {
jQuery(this).parents('.price_rule_wrapper').remove();
});
});
Decrease price_rule_count by 1 when removing.
After remove one element, alter the existing elements #number.
UPDATED: As from Arun P Johny's answer, we don't need to traverse all the left elements, only need to change those which are after the removed one's text.
The origin code will register multiple events to .remove_price_rule each time you add a item, that means if you create the element 3 times, when you remove one, the logic in the remove handler will execute 3 times, so the price_rule_count will be inconsistent to the actual counts if we use price_rule_count--, however, even if we use jQuery(".price_rule_area_1").children().length; to get real count, its stll redundant to execute the same logic many times.
So It's better to use .on's delegate form here.
var price_rule_html = '<button class="remove_price_rule button" type="button">Remove Element</button>';
var price_rule_count = jQuery(".price_rule_area_1").children().length;
jQuery('.add_price_rule').click(function () {
price_rule_count++;
jQuery('.price_rule_area_1').append('<div class="price_rule_wrapper"><div class="price_rule_count">Element #<span>' + price_rule_count + '</span></div>' + price_rule_html + '</div>');
});
+jQuery('.price_rule_area_1').on("click", ".remove_price_rule", function() {
// As from Arun P Johny's answer, we only need to change the text after the removed element.
$element = jQuery(this).parents('.price_rule_wrapper');
$element
.nextAll('.price_rule_wrapper')
.find('span')
.text(function(index, prevText) {
return parseInt(prevText, 10) - 1;
});
jQuery(this).parents('.price_rule_wrapper').remove();
--price_rule_count;
// This would be slower as some elements don't need to be traversed.
// jQuery('.price_rule_wrapper').each(function(idx) {
// $(this).find(".price_rule_count > span").text(idx + 1);
// });
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="price_rule_area_1"></div>
<button class="button-primary add_price_rule" type="button">Add Element</button>
jsfiddle
Check out this fiddle, I have used CSS counters in order to automatically keep your element number:
https://jsfiddle.net/wepsrzkm/8/
.price_rule_area_1{
counter-reset: section;
}
.price_rule_area_1 .price_rule_wrapper{
counter-increment: section;
}
.price_rule_area_1 .price_rule_wrapper .price_rule_count::after{
content: "#"counter(section);
display:inline-block;
}
You can update the content of the span element inside the price_rule_wrapper element like
var price_rule_html = '<button class="remove_price_rule button" type="button">Remove Element</button>';
var price_rule_count = 1;
var price_rule_count = jQuery(".price_rule_area_1").children().length;
jQuery('.add_price_rule').click(function() {
price_rule_count++;
jQuery('.price_rule_area_1').append('<div class="price_rule_wrapper"><div class="price_rule_count">Element #<span>' + price_rule_count + '</span></div>' + price_rule_html + '</div>');
});
jQuery('.price_rule_area_1').on('click', ".remove_price_rule", function() {
var $wrapper = jQuery(this).closest('.price_rule_wrapper');
$wrapper.nextAll('.price_rule_wrapper').find('span').text(function(i, text) {
return text - 1
})
$wrapper.remove();
price_rule_count--;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="price_rule_area_1"></div>
<button class="button-primary add_price_rule" type="button">Add Element</button>
Note: Use event delegation to handler the click event of dynamically recreated elements.
You are binding multiple event handler for each remove element
var price_rule_html = '<button class="remove_price_rule button" type="button">Remove Element</button>';
var price_rule_count = 1;
var price_rule_count = jQuery(".price_rule_area_1").children().length;
jQuery('.add_price_rule').click(function() {
price_rule_count++;
jQuery('.price_rule_area_1').append('<div class="price_rule_wrapper"><div class="price_rule_count">Element #<span>' + price_rule_count + '</span></div>' + price_rule_html + '</div>');
});
$('div.price_rule_area_1').on('click', '.remove_price_rule', function() {
// event handler for dynamically generated element
jQuery(this).parents('.price_rule_wrapper')
.nextAll('div')
// get all div after the removing div
.find('span')
// get number span inside it
.html(function(i, v) {
return parseInt(v) - 1;
})
// decrementing value of it
.end().end()
// get back to the removing div
.remove();
// removing the div
price_rule_count--;
// decrementing the count by 1 after removing the element
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div class="price_rule_area_1"></div>
<button class="button-primary add_price_rule" type="button">Add Element</button>
try this mate
<html>
<body>
<div class="price_rule_area_1"></div>
<button class="button-primary add_price_rule" type="button">Add Element</button>
</body>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-alpha1/jquery.min.js"></script>
<script>
var price_rule_html = '<button class="remove_price_rule button" type="button">Remove Element</button>';
var price_rule_count = 1;
jQuery('.add_price_rule').click(function () {
var price_rule_count = jQuery(".price_rule_area_1").children().length;
price_rule_count++;
jQuery('.price_rule_area_1').append('<div class="price_rule_wrapper"><div class="price_rule_count">Element #<span class="bull ">' + price_rule_count + '</span></div>' + price_rule_html + '</div>');
jQuery(".remove_price_rule").click(function() {
jQuery(this).parents('.price_rule_wrapper').remove();
price_rule_count--;
alert(jQuery('.price_rule_area_1').children().length)
jQuery('.price_rule_area_1').children().eq(price_rule_count-1).find('.bull').text(price_rule_count)
});
});
</script>
</html>

Categories