How do I make jQuery work after an AJAX call - ajax

I've read a few posts on this, but none gave a specific answer (or the questions were unnecessarily complicated...). I will keep it simple.
I am using jQuery UI for a draggable/droppable function. When a draggable is dropped on the target element, an AJAX function is called. It all works fine, but only once. When I try it again, I can't even drag the element anymore. Here is my (simplified) code:
$(document).ready(function() {
$(".item").draggable();
$(".target").droppable({
drop: function(){
AjaxFunction(var1, var2);
}
});
});
This is the simplified AjaxFunction:
function AjaxFunction (var1, var2) {
var url = "ajax/script.php";
var data = {position: var1, tag: var2};
$.post(url, data, function(data) {
$(".target").html(data).show();
});
}
Can anyone give me a specific solution to the above code on how to make it work?

You may want to refer to this post:
Jquery Draggable - How do I create a new draggable div on the fly that can then be dragged?
Specifically this part:
$(element).draggable('disable');
and
$(element).draggable('enable');
It is not exactly the same but it gives some insight on the problem. Basically, you may want to try disabling draggable and droppable, then re-enabling them after your ajax success.
function AjaxFunction (var1, var2) {
var url = "ajax/script.php";
var data = {position: var1, tag: var2};
$.post(url, data, function(data) {
$(".item").draggable("destroy");
$(".target").droppable("destroy");
$(".target").html(data).show().droppable({revert:true});
$(".item").draggable();
});
}

Related

There must be an easier way

I am trying to create an JQM app and are doing so by getting a lot of data from database. When I click on a link from a ajax/json generated calendar list I should then be able to get the info for that event by calling the server and get the data. As it is now I do this in 2 steps like this.
My ajax generated event list:
$.each(groupcalendar, function (i, val) {
output += '<li><h2>' + val.matchformname + '</h2><p><strong>' + val.matchday + '</strong></p><p>' + val.coursename + '</p><p class="ui-li-aside"><strong>' + val.matchtime + '</strong></p></li>';
});
When I click on one of the links I want to goto a page called prematchdata.html and get the data fro that specific event. I do so by first calling the click and get the eventid from data-id like this:
$(document).on('click', '#gotoMatch', function () {
var matchid = $(this).attr("data-id");
$.get("http://mypage.com/json/getmatchinfo.php?matchid="+matchid, function(data) {
localStorage["matchinfo"] = JSON.stringify(data);
$.mobile.changePage( "prematchdata.html", { transition: "slide", changeHash: true} );
}, "json");
});
I save the returned data as localStorage and then uses this data in my pageinit like this:
$(document).on("pageinit", "#prematchdata", function() {
var matchinfo = {};
matchinfo = JSON.parse(localStorage["matchinfo"])
var content = '<h2>'+matchinfo["matchname"]+'</h2>';
$('.infoholder').html(content);
});
It works, although for me it seems like the last 2 steps should be done in one, but i am not sure how to do so? It seems a little bit wrong get data, save locally and then use it? Can't this be done without the $(document).on('click', '#gotoMatch', function () {});?
Hoping for some help and thanks in advance :-)
You could try sending it up using a query string. When you're using changePage, change your code like this :
$(document).on('click', '#gotoMatch', function () {
var matchid = $(this).attr("data-id");
$.get("http://mypage.com/json/getmatchinfo.php?matchid=" + matchid, function (data) {
paramData = data[0];
$.mobile.changePage("prematchdata.html", {
transition: "slide",
changeHash: true,
data: paramData //added this extra parameter which will pass data as a query string
});
}, "json");
});
When you're getting it back,
$(document).on("pageinit", "#prematchdata", function() {
var url = $.url(document.location);
var name= url.param("matchname");
var content = '<h2>'+ name +'</h2>';
$('.infoholder').html(content);
});
Another easy way would be use a singlepage template instead of a multi page template. Then, you could just use a global variable to get and set data.
That said, what you're doing right now is more secure than this query string method. By using this, anyone can see what you are sending over the URL. So I advise you keep using localStorage. For more info on this, look into this question.

jquery each on new elements not working

$('.collapse').each(function() {
var title= $(this).siblings('.accordion-heading').find('a');
$(this).on('show hide', function (e) {
if(!$(this).is(e.target))return;
title.parent().toggleClass('active', 300);
title.parent().hasClass('active') ? $('input.party').prop('value', '') : $('input.party').val(title.siblings('.delete').prop('id'));
var id = title.siblings('.delete').prop('id');
var data = {id: id};
$.post("times.php", data, function(result) {
if(title.parent().hasClass('active')){
$('.times').html('');
} else {
$('.times').html($.parseJSON(result));
}
})
})
})
So I am adding a new accordion-group to my html by adding a new party and I wan't all this to work on the newly added elements as well. I didn't find topics that could help me since it is a bit more specific than any random each function (I think).
This future elements thing is new to me, so I would appreciate some explanations or a good link to a place other that the jquery website which I already checked.
Thank you for your time!
Basically what I want to do this replace $(this).on('show hide', function (e) { with something like $(document).on('show hide', $(this), function (e) {. What I just wrote doesn't work though.
If it is just about the event handler, then you can use event delegation to capture the event on dynamically created elements as well.
There is not reason why you have to use .each here, so just omit it:
$(document.body).on('show hide', '.collapse', function() {
var title = $(this).siblings('.accordion-heading').find('a');
if(!$(this).is(e.target))return;
// rest of the code...
});
this will apply on any new objects matching selector
jQuery(document).on('show hide', '.accordion-heading a', function(event){
...
});

JQuery - Iterating JSON Response

The Story So far....
Trying to learn JS and JQuery and i thought i would start with the basics and try alittle AJAX "search as you type" magic. Firstly i just wanted to get the AJAX part right and iterating through the return JSON object and appending it to a unordered list. Im doing no validation on the inputted value vs. the returned JSON results at this time, i just want a controlled way of when to do the AJAX getJSON call. Later i will do the validation once i get this right.
Anyways im having trouble displaying the Account Numbers in in the ul. At the moment the only thing that is being displayed is AccountNumber in the li and not my ACCOUNT NUMBERS
My JS Code is here:
http://jsfiddle.net/garfbradaz/HBYvq/54/
but for ease its here as well:
$(document).ready(function() {
$("#livesearchinput").keydown(function(key) {
$.ajaxSetup({
cache: false
});
$.getJSON(" /gh/get/response.json//garfbradaz/MvcLiveSearch/tree/master/JSFiddleAjaxReponses/", function(JSONData) {
$('<ul>').attr({
id: "live-list"
}).appendTo('div#livesearchesults');
$.each(JSONData, function(i, item) {
var li = $('<li>').append(i).appendTo('ul#live-list');
//debugger;
});
});
});
});​
My JSON file is hosted on github, but again for ease, here it is:
https://github.com/garfbradaz/MvcLiveSearch/blob/master/JSFiddleAjaxReponses/demo.response.json
{
"AccountNumber": [
1000014,
1015454,
1000013,
1000012,
12
]
}
Also here is my Fiddler results proving my JSON object is being returned.
EDIT:
There were so queries about what i was trying to achieve, so here it goes:
Learn JQuery
To build a "Search as you Type" input box. Firstly i wanted to get the AJAX part right first, then i was going to build an MVC3 (ASP.NET) Application that utilises this functionality, plus tidy up the JQuery code which includes validation for the input vs. the returned JSON.
Cheesos answer below worked for me and the JSFiddle can be found here:
http://jsfiddle.net/garfbradaz/JYdTU/
First, I think keydown is probably the wrong time to do the json call, or at least... it's wrong to do a json call with every keydown. That's too many calls. If I type "hello" in the input box, within about .8 seconds, then there are 5 json requests and responses.
But you could make it so that it retrieves the json only the first time through, using a flag.
Something like this:
$(document).ready(function() {
var $input = $("#livesearchinput"), filled = false;
$.ajaxSetup({ cache: false });
$input.keydown(function(key) {
if (!filled) {
filled = true;
$.getJSON("json101.js", function(JSONData) {
var $ul =
$('<ul>')
.attr({id: "live-list"})
.appendTo('div#livesearchesults');
$.each(JSONData, function(i, item) {
$.each(item, function(j, val) {
$('<li>').append(val).appendTo($ul);
});
});
});
}
});
});
The key thing there is I've used an inner $.each().
The outer $.each() is probably unnecessary. The JSON you receive has exactly one element in the object - "AccountNumber", which is an array. So you don't need to iterate over all the items in the object.
That might look like this:
$.each(JSONData.AccountNumber, function(i, item) {
$('<li>').append(item).appendTo($ul);
});
What you probably want is this:
$.each(JSONData.AccountNumber, function(i, item) {
var li = $('<li>').append(item).appendTo('ul#live-list');
});
Your code:
$.each(JSONData, function(i, item) {
var li = $('<li>').append(i).appendTo('ul#live-list');
});
Says "iterate over the keys and values of the outer JSON structure, and print the keys". The first key is "AccountNumber", so you end up printing that.
What you want to do is iterate over the array stored at JSONData.AccountNumber, and print the values:
$.each(JSONData.AccountNumber, function() {
var li = $('<li>').append(this).appendTo('ul#live-list');
});

Return false not working for jQuery live

Well this has me well and truly stumped. After searching for the last few hours I still cannot seem to work out where I am going wrong.
I am trying to append an AJAX response to a container when it gets clicked. That works fine but I don't want it to append another object when the elements from the AJAX response also gets clicked.... so:
<div id="container">
<!-- AJAX response to get inserted here, for example -->
<span id="ajaxResponse"></span>
</div>
Here is my script:
$('#container').click(function(e) {
var current_el = $(this).get(0);
$.ajax({
url: 'text.html',
success: function(data) {
$(current_el).append(data);
}
});
return false;
});
So it works fine but for some reason the click event on #container also fires when I click on the AJAX response span!?
According to jQuery documentation:
To stop further handlers from
executing after one bound using
.live(), the handler must return
false. Calling .stopPropagation() will
not accomplish this.
But unless I am mistaken, I am calling false? :(
Anyone help me out on this?
UPDATED:
So the only way I can get it to work is by updating my code to this:
$('#container').live('click', function() {
var current_el = $(this).get(0);
$.ajax({
url: 'text.html',
success: function(data) {
$(current_el).append(data);
}
});
});
$('#ajaxResponse').live('click', function(e) {
return false;
});
This seems a little messy though... anyone have a better solution?
Where is live part you mention in the title of the question ?
It is how the event model works.. If you click on element which does not handle the event, the event will travel up the DOM hierarchy until it finds an element that handles the click (and stops its propagation..). Otherwise you would not be able to put an image inside a <a> tag and click on it..
You can bind a canceling handler on the inner element assuming you have someway to target it..
$.ajax({
url: 'text.html',
success: function(data) {
$(current_el).append(data);
// assuming the returned data from ajax are wrapped in tags
$(current_el).children().click(function(){ return false;});
}
});
I think the return false is referring to something else in this case...
you should try calling stopPropagation() - this should stop the "click" function from propagating down to the ajaxResponse span....
One option that you may want to try is switching over to using live(). Essentially, the click event you setup is calling bind(), and the solution you referenced is using live() which is a variation on bind().
For example:
$('#container').live("click", function(e) {
var current_el = $(this).get(0);
$.ajax({
url: 'text.html',
success: function(data) {
$(current_el).append(data);
}
});
return false;
});
HTH

jQuery Live implementation in Prototype

Element.implement({
addLiveEvent: function(event, selector, fn){
this.addEvent(event, function(e){
var t = $(e.target);
if (!t.match(selector)) return false;
fn.apply(t, [e]);
}.bindWithEvent(this, selector, fn));
}
});
$(document.body).addLiveEvent('click', 'a', function(e){ alert('This is a live event'); });
The above code was done in a similar question to implement .live behaviour in Mootools. I've read the question: Prototype equivalent for jQuery live function.
How do I implement this in Prototype? Probably something that can be implemented like this:
document.liveobserve('click', 'a', function(e){ alert('This is a live event');
Edited to make the question clear.
The simplest (and perhaps not the fastest or best) way would appear to be something like:
Element.live = function(evType, evSelector, evBlock) {
var mySelector = evSelector;
var myBlock = evBlock;
this.observe(evType, function(ev) {
if (ev.target.match(mySelector)) {
evBlock(ev);
}
});
};
The parameters evSelector and evBlock are assigned to local variables so the they are available to the event handler (It's a closure). The passed block evBlock gets passed the event object just like a normal Prototype event handler.
It should be noted this is going to handle every event of type 'evType' so if it's a mouseMove/mouseOver this is going to make your page slow. Also FireBug will probably just go to sleep on you due to the number of events that it has to single step through.
EDIT: Changed as per comments

Resources