I try to make a link fire a javascript function wich fires a ajax call to delete an item.
Like so:
<a class="delete" href="#item.Product.Id">(x)</a>
Clicking the cross caries the id of the product to be deleted.
The only reason the href attribute is there is to carry the value.
$(document).ready(function () {
$('.delete').click(function (e) {
e.preventDefault();
var id = $(this).attr("href");
deleteItem(id);
return false;
});
});
Ajax call: as requested:
function deleteItem(id) {
$.ajax({
url: "/Shoppingcart/RemoveItem",
type: "POST",
data: "id=" + id,
cache: false,
error: function (xhr, status, error) {
console.log(xhr, status, error);
},
success: function () {
$.ajax({
url: "/Shoppingcart/Index",
type: "GET",
cache: false,
error: function (xhr, status, error) {
console.log(xhr, status, error);
},
success: function (result) {
success(result);
}
});
}
});
}
The success function is there to get an updated version of the cart.
And this actually works just fine. However I get a wierd page refresh half way trough the cycle.
I click the link.
the page refreshes and the item is not deleted.
I click the link once more.
the page is not refreshed.
the item is deleted.
Why do I have to click two time and what can I do to resolve this?
The most correct answer is: You don't know what the error is,
because the page is refreshing before you see the error.
Return false prevents the page from refreshing after a click event, but if the code runs into an error before that point...
So you could try to remove the href tag and make it an rel (or something else) tag instead. read that and use it for your AJAX call. give the href a value like # or #removeItem.
This will give you the error your craving for.
Hope this helps!
Usually you get such behavior when page the is quite big and the document.ready event just hasn't fired yet when you click the link. The second time it may load faster (scripts/css already downloaded and coming from cache).
As per my knowledge, have a hidden field or a hidden span to save the "ProductId" and remove the href attribute altogether something like below.
<span id="productIdSpan">#item.Product.Id</span>
<a class="delete"></a>
jQuery:
$(document).ready(function () {
$('.delete').click(function (e) {
var id = $("#productIdSpan").html();
deleteItem(id);
return false;
});
});
EDIT:
Approach-2:
You can store the ProductId in the anchor tag's "title" attribute something like below
jQuery:
$(document).ready(function () {
$(".delete").on("click", function (e) {
deleteItem($(this).attr("title"));
return false;
});
});
This should solve your problem. Hope this helps!!
The correct answer is:
When you add an element to your html after the page is loaded ( for example with AJAX ) and you want to have, in any way, fire an event. You have to rebind the click event to the new element.
When the page is loaded and your javascript and jQuery are loaded. The element isn't their yet so they can't find it or interact with it.
So in my situation:
function addItem(id, amount) {
$.ajax({
url: "/Shoppingcart/AddItem",
type: "POST",
data: "id=" + id + "&amount=" + amount,
cache: false,
error: function (xhr, status, error) {
console.log(xhr, status, error);
},
success: function () {
// Calls for the new update version of the shopping cart.
$.ajax({
url: "/Shoppingcart/Index",
type: "GET",
cache: false,
error: function (xhr, status, error) {
console.log(xhr, status, error);
},
success: function (result) {
//Call the function that changes the html
success(result);
}
});
}
});
}
function success(result) {
$("#shoppingcart").html(result);
//The tricky part: rebinding the new event.
$('.delete').click(function (e) {
e.preventDefault();
var id = $(this).attr("data-id");
deleteItem(id);
return false;
});
}
The delete button did work after a refresh because in that way javascript got reloaded and the element was correctly bound.
Related
I have some JS files included in my page that are simple for displaying blocks on click ant etc..
On another part of page, I have a button. When I click it an ajax call is made that returns some values that I display on the page. To display it, I'm reloading part of page like this:
$(document).ready(function () {
$(document).on('click', '.add', function (e) {
$this = $(this);
$.ajax({
type: 'POST',
url: 'add',
dataType: 'JSON',
data: {product: $this.parent('.input-append').find('input').data('id'),quantity: $this.parent('.input-append').find('input').val()},
success: function (data) {
if(data.success == false){
alert('error')
}else{
$('.test').load(" .test");
$('.sidebar').load(" .sidebar");
$('.top').load(" .top");
}
}
});
});
This reloads part of page, displays values and etc..
However, after the ajax call is made, the JS stops working. When I click my buttons, nothing happens. No errors or anything.
I think it has to do with the ajax when I refresh part of twig and it messes up the previously loaded JS files. But what can I do in that situation? Somehow refresh the loaded JS files? How?
You have to attach event listener on button starting from the container which doesn't get reloaded by Ajax request, like this:
//#mainCont is a container that doesn't get reloaded by Ajax
$("#mainCont").on("click", ".yourBtn", function(){
//do something
});
As said #Nacho M, you need to reinit listener from the loaded element, so you hsould have something like this :
function init() {
$(document).on('click', '.yourclass', function (e) {
//your content
}
// add every button who needs to be reloaded.
}
Init them on loading page first :
$("document").ready(function() {
init();
})
And on success of Ajax call :
$.ajax({
type: 'POST',
url: 'add',
dataType: 'JSON',
data: {product: $this.parent('.input-append').find('input').data('id'),quantity: $this.parent('.input-append').find('input').val()},
success: function (data) {
if(data.success == false){
alert('error')
}else{
$('.test').load(" .test");
$('.sidebar').load(" .sidebar");
$('.top').load(" .top");
init();
}
}
});
I had a question regarding Ajax loading of html into a DIV. Ideally what I want is this:
A toggle div with close button, which I have the code for here: http://jsfiddle.net/tymeJV/uhEgG/28/
$(document).ready(function () {
$('#country').click(function () {
$("#country_slide").slideToggle(function() {
if ($(this).is(":visible")) {
alert("im visible!");
}
});
});
$('#close').click(function (e) {
e.preventDefault();
$('#country_slide').slideToggle();
});
});
Then I want some AJAX code to load a html file into the div when the div is expanded. The trick is that if the HTML is loaded successfully, I want it to avoid reloading the HTML file again if the div is closed and repoened, since I have already loaded it, and just simply toggle the content in and out with the button. The code I have for this (which I got help on from here is this):
http://jsfiddle.net/spadez/uhEgG/55/
$(function () {
$('#country_link').on('click', function (e) {
// Prevent from following the link, if there is some sort of error in
// the code before 'return false' it would still follow the link.
e.preventDefault();
// Get $link because 'this' is something else in the ajax request.
var $link = $(this);
// Exit if the data is loaded already
if ($link.data('loaded') === true)
return false;
$.ajax({
type: 'GET',
dataType: 'html',
url: '/ajax/test.html',
timeout: 5000,
beforeSend: function () {
},
success: function (data, textStatus) {
$("#country_slide").html(data);
alert('request successful');
// If successful, bind 'loaded' in the data
$link.data('loaded', true)
},
error: function (xhr, textStatus, errorThrown) {
$("#country_slide").html('Error');
},
complete: function () {
},
});
});
});
I haven't been able to get this working yet though. So my question is, is it actually possible to do this, and if it is, can anyone with more experience with jquery please help me integrate the div toggle with the ajax loading script.
This is one of my first jquery scripts and I am having a bit of a hard time with it, perhaps it is not for beginners. Thank you.
I edited the fiddle you posted adding the call to slideToogle() where appropriate. Also added a div element to hold the loaded html code.
<div id="country_slide">
Close
<div class=".content"></div> <!-- This is the div I added -->
</div>
You can check the log messages in the console to verify that the code is doing what you expect. The URL for the Ajax call you were doing always returned an error so I changed to the URL that jsfiddle provides for testing: /echo/html/.
Here's the modified JS code:
$(function () {
$('#close').click(function (e) {
e.preventDefault();
$('#country_slide').slideToggle();
});
$('#country_link').on('click', function (e) {
e.preventDefault();
var $link = $(this);
// Exit if the data is loaded already
if ($link.data('loaded') === true) {
console.log('Not using Ajax.');
$("#country_slide").slideToggle();
return false;
}
$.ajax({
type: 'GET',
dataType: 'html',
url: '/echo/html/',
timeout: 5000,
beforeSend: function () {
$("#country_slide .content").html('<p>Loading</p>')
},
success: function (data, textStatus) {
console.log('Fecthed with Ajax.');
$("#country_slide .content").html(data);
$("#country_slide").slideToggle();
// If successful, bind 'loaded' in the data
$link.data('loaded', true)
},
error: function (xhr, textStatus, errorThrown) {
alert('request failed');
},
complete: function () {
},
});
});
});
I was working on a simple form page and I was wondering what happens if someone clicks the submit button many many times (incase my shared hosting somehow seems to be slow at that time).
Also, incase anyone wants to look at my code
$.ajax({
url: "submit.php",
type: 'POST',
data: form,
success: function (msg) {
$(".ressult").html("Thank You!");
},
error: function () {
$(".result").html("Error");
}
});
Is there a way to make it so after the user clicks it once, it won't run it again until the first click is done?
Thank you
You can use jQuery's .one() function:
(function handleSubmit() {
$('#submitBtn').one('click', function() {
var $result = $('.result');
$.ajax({
url: 'submit.php',
type: 'POST',
data: form,
success: function (msg) {
$result.html('Thank You!');
handleSubmit(); // re-bind once.
},
error: function () {
$result.html('Error');
}
}); // End ajax()
}); // End one(click)
}()); // End self-invoked handleSubmit()
*Edit: * Added recursion for multiple submissions.
Use a boolean flag
if (window.isRunning) return;
window.isRunning = true;
$.ajax({
url:"submit.php",
type: 'POST',
data: form,
success: function (msg){
$(".ressult").html("Thank You!");
},
error: function (){
$(".result").html("Error");
},
complete : function () {
window.isRunning = false;
}
});
var $button = $(this);
$button.prop('disabled', true); // disable the button
$.ajax({
url:"submit.php",
type: 'POST',
data: form,
success: function (msg){
$(".ressult").html("Thank You!");
},
error: function (){
$(".result").html("Error");
},
complete: function() {
$button.prop('disabled', false); // enable it again
}
});
Have you considered replacing your submit button with a loader image while the query executes, then re-adding it once the query is complete?
EDIT: Using the loader image is a sort of universal "I'm doing something" indicator, but disabling the button would work too!
You could disable the submit button, before the ajax call is made. And then, if required, enable it on success.
This code works fine for first click as it changes class along with image which is referenced from CSS. But when I click second time it acts like clicked in previous class which I assume removed already.
if(Model.SeenItWantToSeeIt.Status==1)
{
<div class="movie_data">
<div class="usermovie_option"> </div>
</div>
<div class="clear"></div>
}
else{
<div class="movie_data">
<div class="usermovie_option"> </div>
</div>
<div class="clear"></div>
}
And Javascript for toggling class is
$(".want_to_see_it").click(function () {
var wantToSeeIt = $(this);
alert('clicked on want to see it.');
$.ajax({
url: '#Url.Action("SeenIt", "MovieProfile")',
data: { Status: 1, MovieID: movieID },
dataType: 'json',
type: "POST",
success: function (data) {
wantToSeeIt.removeClass();
wantToSeeIt.addClass("dont_want_to_see_it");
$("dont_want_to_see_it").show();
},
error: function (data) {
alert('Error occurred.');
}
});
});
$(".dont_want_to_see_it").click(function () {
alert('clicked on donot want to see it');
var wantToSeeIt = $(this);
$.ajax({
url: '#Url.Action("SeenIt", "MovieProfile")',
data: { Status: 0, MovieID: movieID },
dataType: 'json',
type: "POST",
success: function (data) {
wantToSeeIt.removeClass();
wantToSeeIt.addClass("want_to_see_it");
$("want_to_see_it").show();
},
error: function (data) {
alert('Error occurred.');
}
});
});
And problem is it shows "clicked on donot want to see it" or "clicked on want to see it" as alert every time I click . What I have to do is this message should alternate every time I Click on their respective image.
Problem here is that you want to change the handlers dynamically on click of each element. But events are bound to the element directly using click event.
One option is to hide and show respective items.
Another option is to bind and unbind events.
Third option is to use event delegation. Your requirement will work with this since with event delegation events are not directly attached to the elements, they are instead delegated. So the moment you swap the class name event subscribed for that class name will automatically get delegated. SO next click on the same element will go to the other event handler attached its new class name. See if this is what you were looking for.
$(document).on('click',".want_to_see_it" ,function (e) {
var wantToSeeIt = $(this);
alert('clicked on want to see it.');
///Your ajax
wantToSeeIt.removeClass();
wantToSeeIt.addClass("dont_want_to_see_it");
$(".dont_want_to_see_it").show();
});
$(document).on('click',".dont_want_to_see_it" ,function (e) {
alert('clicked on donot want to see it');
var wantToSeeIt = $(this);
///Your ajax
wantToSeeIt.removeClass();
wantToSeeIt.addClass("want_to_see_it");
$(".want_to_see_it").show();
});
Note:- In the example i have attached to the document, You should n't attach it to the document, instead attach it to any containing element that is present in DOM at any time.
Demo
There was another issue, you missed . before the classname in your ajax success.
The problem is you need to unbind("click") to clear the previous handler then bind a new event handler for its new class.
Instead of unbinding and rebinding, do in one handler:
$(".usermovie_option a").on("click", function () {
var status = 0;
if ($(this).hasClass("want_to_see_it")) {
status = 1;
}
$.ajax({
url: '#Url.Action("SeenIt", "MovieProfile")',
data: { Status: status, MovieID: movieID,
dataType: 'json',
type: "POST",
success: function (data) {
$(this).toggleClass("want_to_see_it");
$(this).toggleClass("dont_want_to_see_it");
},
error: function (data) {
alert('Error occurred.');
}
});
});
I have a simple jQuery function that resizes text areas, and I want it to apply to all text areas.
For the most part, this works great:
$(document.ready(function(){$("text_area").resizer('250px')});
However, because it is only called once when the document is ready, it fails to catch text areas that are later added onto the page using Ajax. I looked at the .live() function, which seems very close to what I'm looking. However, .live() must be bound to a specific event, whereas I just need this to fire once when they're done loading (the onLoad event doesn't work for individual elements).
The only thing I can get working is a really obtrusive inclusion of the JavaScript call directly into the Ajax. Is that the recommended way to be doing this?
Edit: Here is the rails source code for what it does for Ajax requests:
$('a[data-confirm], a[data-method], a[data-remote]').live('click.rails', function(e) {
var link = $(this);
if (!allowAction(link)) return false;
if (link.attr('data-remote') != undefined) {
handleRemote(link);
return false;
} else if (link.attr('data-method')) {
handleMethod(link);
return false;
}
});
// Submits "remote" forms and links with ajax
function handleRemote(element) {
var method, url, data,
dataType = element.attr('data-type') || ($.ajaxSettings && $.ajaxSettings.dataType);
if (element.is('form')) {
method = element.attr('method');
url = element.attr('action');
data = element.serializeArray();
// memoized value from clicked submit button
var button = element.data('ujs:submit-button');
if (button) {
data.push(button);
element.data('ujs:submit-button', null);
}
} else {
method = element.attr('data-method');
url = element.attr('href');
data = null;
}
$.ajax({
url: url, type: method || 'GET', data: data, dataType: dataType,
// stopping the "ajax:beforeSend" event will cancel the ajax request
beforeSend: function(xhr, settings) {
if (settings.dataType === undefined) {
xhr.setRequestHeader('accept', '*/*;q=0.5, ' + settings.accepts.script);
}
return fire(element, 'ajax:beforeSend', [xhr, settings]);
},
success: function(data, status, xhr) {
element.trigger('ajax:success', [data, status, xhr]);
},
complete: function(xhr, status) {
element.trigger('ajax:complete', [xhr, status]);
},
error: function(xhr, status, error) {
element.trigger('ajax:error', [xhr, status, error]);
}
});
}
So in my particular case, I've got a link, that has data-remote set to true, which points to a location that will return JavaScript instructing a form containing a text area to be appended to my document.
A simple way to do this would be to use ajaxComplete, which is fired after every AJAX request:
$(document).ajaxComplete(function() {
$('textarea:not(.processed)').resizer('250px');
});
That says "every time an AJAX request completes, find all textarea elements that don't have the processed class (which seems to be added by the resizer plugin -- terrible name for its purpose!) and call the resizer plugin on them.
You may be able to optimise this further if we could see your AJAX call.
Generally speaking, I would do it this way..
$.ajax({
type : "GET",
url : "/loadstuff",
success: function(responseHtml) {
var div = $("#containerDiv").append(responseHtml);
$("textarea", div).resizer("250px");
}
});
Wondering if you could use .load for this. For example:
$('text_area').load(function() {
$("text_area").resizer('250px');
});