callback after jQuery.trigger() function - javascript

i have got a little problem here. I have to trigger an event which contains $.post() to load a form and assign it to a DOM. After this is done, i have edit the fields of the form.
I tried:
$.when(function(){
$('#type_rank_field').trigger('change'); //calls the $.post() to load the form
})
.done(function(){
$('#quest_'+questions[i].split('|')[1]).children('option[value="'+questions[i].split('|')[0]+'"]').attr('selected',true);
});
Unfortunately this doesnt work and if i leave it just like that:
$('#type_rank_field').trigger('change');
$('#quest_'+questions[i].split('|')[1]).children('option[value="'+questions[i].split('|')[0]+'"]').attr('selected',true);
The change even looks like this:
$('#type_rank_field').live('change',function(){
var id = $(this).children('option:selected').attr('id');
var id_edited = get_id_from_id(id);
$.post('ajax/load_questions_of_rank.ajax.php',{id: id_edited},function(data){
//alert(data);
$('#rank_fields').html(data);
});
});
Then the form editation is executed before the form is properly loaded and attached to DOM. This might be a stupid question for JavaScript guys, but i am mainly a PHP guy so dont be cruel :-)
Thanks

Can separate out your change handler code? Something like this:
$('#type_rank_field').on('change',function(){
handleChange($(this));
});
function handleChange(elem, callback) {
var id = elem.children('option:selected').attr('id');
var id_edited = get_id_from_id(id);
$.post('ajax/load_questions_of_rank.ajax.php',{id: id_edited},function(data){
//alert(data);
$('#rank_fields').html(data);
if (typeof callback === "function") {
callback(data);
}
});
};
Then instead of triggering the change you can just call handleChange passing a callback to execute when the AJAX call is complete:
handleChange($("#type_rank_field"), function(data) {
$('#quest_'+questions[i].split('|')[1])
.children('option[value="'+questions[i].split('|')[0]+'"]')
.attr('selected',true);
});

Return the promise object from your event handler:
$(document).on('change','#type_rank_field',function(){
var id = $(this).children('option:selected').attr('id');
var id_edited = get_id_from_id(id);
return $.post('ajax/load_questions_of_rank.ajax.php',{id: id_edited},function(data){
//alert(data);
$('#rank_fields').html(data);
});
});
and then use triggerHandler() instead.
var promise = $('#type_rank_field').triggerHandler('change');
promise && promise.done(function(){
// do stuff
});
Here's a simple example showing the functionality being used: http://jsfiddle.net/WQPXt/

I think we have to add callback after posted
$('#type_rank_field').on('change', function(ev, cb){
var id = $(this).children('option:selected').attr('id');
var id_edited = get_id_from_id(id);
$.post('ajax/load_questions_of_rank.ajax.php',{id: id_edited},function(data){
//alert(data);
$('#rank_fields').html(data);
// add after callback to make sure that html is inserted
if(typeof cb == "function"){
cb.apply($(this)) // this apply with the jq object context or another context u want
}
});
the trigger change will look like this
$('#type_rank_field').trigger('change', [function(){
$('#quest_'+questions[i].split('|')[1]).children('option[value="'+questions[i].split('|')[0]+'"]').attr('selected',true);
}]);

.live has been deprecated in jQuery since v1.7, and has been removed in v1.9.
You should replace it with .on().
.on has 2 signatures for binding elements, whereas .live only had 1.
If the element exists at the time you are binding, you do it like this:
$('.element').on('click', function(){
.......
});
You can even use the shorthand:
$('.element').click(function(){
.........
});
If the element does not exist at the time, or new ones will be added (which is what .live was normally used for), you need to use "event delegation":
$(document).on('click', '.element', function(){
........
});
NOTE: You want to bind to the closest static element, not always document.
In the meantime, the jQuery Migrate plugin can be used to restore the .live() functionality if you upgrade your jQuery to the newest version.

Related

jQuery script doesn't work without an alert

I have an script that uses jquery, but i have a problem in the next part:
$("#botonAgregar").click(function() {
$.ajax({
type: "GET",
url: $(this).attr('href'),
success: function(html) {
$("#dialogDiv").html(html);
$("#dialogDiv").dialog('open');
}
});
alert();
$("a[type='submit']").click(function() {
var formName = $(this).attr("nombreform");
var formSelector = "form#" + formName;
$(formSelector).submit();
});
return false;
});
It works as it is, but if i remove the "alert();" line it doesnt add the click event to $("a[type='submit']") objects. What could be wrong?
it doesnt add the click event to $("a[type='submit']") objects
Yes it does. However, if more of those elements are being added during the AJAX call then you'll need to re-add the handler to those new elements after those are added to the DOM. Currently you're not doing that because the code after your call to .ajax() is happening before the AJAX call completes. This is because AJAX is, by definition, asynchronous. It's possible for the AJAX call to complete before later code is executed, but it is not guaranteed. (And in the case of code that's immediately after it, it's highly unlikely.)
Your success handler is called when the AJAX call completes, so that would be an opportune time to do this:
$("#dialogDiv").html(html);
$("#dialogDiv").dialog('open');
$("a[type='submit']").click(function() {
var formName = $(this).attr("nombreform");
var formSelector = "form#" + formName;
$(formSelector).submit();
});
However, there is a much better way to do this.
One of the problems with the approach you have is that you're going to re-add the handler to the same elements over and over. You're also adding the same handler to many elements, when you really only need one. Take a look at the jQuery .on() function. Essentially what it does is add a single handler to a common parent element of the target elements, and then filter the events based on the target element selector. So you only need to add the handler once:
$(function () {
$(document).on('click', 'a[type=submit]', function () {
var formName = $(this).attr('nombreform');
var formSelector = 'form#' + formName;
$(formSelector).submit();
});
});
In this case I'm using document as the common parent, though any other parent will work. (The body tag, a div which contains all of the target elements, etc. It just needs to be a common parent element which doesn't change throughout the life of the DOM.)

jQuery focus blur pass parameter

I can't seem to access the variable defaultValue down in my .blur() function. I've tried various stuff but with no luck. So far I only get an empty object. What's wrong?
jQuery(document).ready(function(){
jQuery('#nameInput, #emailInput, #webInput').focus(function(){
var defaultValue = jQuery(this).val();
jQuery(this).val("");
})
.blur(function(defaultValue){
if(jQuery(this).val() == ""){
jQuery(this).val(defaultValue);
}
});
});
Looks like the question is about the passing data into the .blur or .focus event.
per jQuery API - http://api.jquery.com/blur/
blur( [eventData ], handler(eventObject) )
So if you want to pass data - you can send a parameter to event - which will appear as data in event object.
see this fiddle for more info
http://jsfiddle.net/dekajp/CgP2X/1/
var p = {
mydata:'my data'
};
/* p could be element or whatever */
$("#tb2").blur(p,function (e){
alert('data :'+e.data.mydata);
});
Because your code is wrong :-) you define var inside function (var defaultValue) which is then immediately wiped out.
There are two solutions: define your var as a global var before you bind blur event, or store it in the data of object liket his (which I recommend):
$(document).ready(function(){
$('#nameInput, #emailInput, #webInput').focus(function(){
$(this).val("").data('defaultValue',jQuery(this).val());
}).blur(function(defaultValue){
if($(this).val() == ""){
$(this).val($(this).data('defaultValue'));
}
});
});
It seems to me that you don't understand the basics of JavaScript.
First of all variables in JS are localized to function's scope, so you can't declare variable with var in one function and access it in other function
Second, you can't pass anything to DOM-event handler, except event-object, this is defined by the DOM specification, sometimes you can use event data parameter to the blur jQuery method.
Try this:
jQuery(document).ready(function(){
var defaultValue;
jQuery("#nameInput, #emailInput, #webInput").focus(function(){
defaultValue = jQuery(this).val();
jQuery(this).val("");
})
.blur(function(){
if(jQuery(this).val() == ""){
jQuery(this).val(defaultValue);
}
});
});
First of all, you need to distinguish blur method (function) and handler (function) which is the argument to the blur. You was trying to pass the defaultValue exactly to handler, but that can't be done. Inside handler the defaultValue would be equal eventObject, so you can do smth like console.log(defaultValue.timeStamp) and you'll see smth like 123482359734536
In your approach you can't even use event.data argument to the blur cause it will be set at the time of blur's call (attaching handler). You need to declare a var outside of the both handlers, so it will be visible to both of them
You may consider to read some comprehensive book on JS.
I read "Professional JaveScript For Webdevelopers" by Nicolas Zakas. There is a new edition

Why are these nested triggers for jQuery not working?

I am using the following code to load two underscore.js templates. Once the first link is clicked, the skeleton template is loaded. The first trigger executes the find bind, which executes the loadBookmarks function correctly, but the 'loaded' trigger never fires and the loadFriendBookmarks never executes. Why is this? Is there another way to make this happen?
$('#bookmarks-link').click(function() {
$('#bookmarks-count').text("0");
var skeleton = modalTemplate();
$('#bookmarks').append(skeleton);
$('#bookmarks').trigger('skeleton');
});
$('#bookmarks').bind('skeleton', function() {
$('#bookmarks .thumbnails').loadBookmarks( getBookmarksUrl(1) );
// If I add an alert('hi') here, it works perfectly.
$('#bookmarks').trigger('loaded');
});
$('#bookmarks').bind('loaded', function() {
$('#bookmarks .thumbnails a').each(function() {
$(this).bind('click', function() {
$('#bookmarks .bookmarks-table tbody').empty();
$('#bookmarks .bookmarks-table tbody').loadFriendBookmarks(
getFriendBookmarksUrl($(this).attr('data-item'))
);
});
});
});
So interesting enough, the triggers do work correctly: If I stick an alert in between loadBookmarks and trigger, everything works fine. If I take it out, then it doesn't. Any idea why?
Based on your description and common sense, it sounds like loadBookmarks() loads data from a remote source, such as an ajax call. This means that trigger('loaded') can fire before loadBookmarks() has received the data. You can add a callback argument to loadBookmarks() and trigger the event there:
$('#bookmarks .thumbnails').loadBookmarks( getBookmarksUrl(1) , function() {
$('#bookmarks').trigger('loaded');
});
But this requires your loadBookmarks to know to call this function after it receives the data and creates the needed HTML - I can't demonstrate this without seeing the actual code you have in loadBookmarks.
Additional suggestion: don't bind handlers this way, use event delegation instead:
$('#bookmarks').on('click', '.thumbnails a', function(e) {
e.preventDefault(); // don't want the link to actually be followed, do we
var url = getFriendBookmarksUrl($(this).attr('data-item'));
if(url) { // in case it's clicked before the data attribute is set
var $tbody = $('#bookmarks .bookmarks-table tbody');
$tbody.empty();
$tbody.loadFriendBookmarks(url);
}
});
This means that all elements matching the selector '#bookmarks .thumbnails a' will call this click handler, even if they were added to the document after you called on. Meaning you can delegate these events even before calling loadBookmarks, removing the need for the loaded event at all. Plus, this way you only have one copy of the handler function in memory, as opposed to your bind which created a separate copy of the function for each a node.
the problem is else where in your code. probably some js error in loadBookmarks* functions.
see:
http://jsfiddle.net/BBESV/
triggers work perfectly

How do you unbind an event from CKEditor?

to bind something to an onChange event, one would write something similar to this:
CKEDITOR.on( 'currentInstance', function( ev )
{
if (CKEDITOR.instances[element_id].checkDirty()) {
unsaved_changes = true;
}
});
But... how does one unbind that that function?
The above code is part of some instantiating code that I use when creating an editor. An issue arises when I use ajax to change the page, and the CKEditor (and all other javascript variables) remain defined on the page. So, the onChange event ends up getting multiple bindings... which can cause performance issues.
The eventInfo documentation of CKEditor is missing the "removeListener" method that you can find using Firebug. I've added it now but it might take a day until it's published.
You just have to call that method on the event object, for example:
CKEDITOR.on( 'currentInstance', function( ev )
{
ev.removeListener();
if (CKEDITOR.instances[element_id].checkDirty()) {
unsaved_changes = true;
}
});
window.ckeditor=CKEDITOR.replace('ckeditor'); //create instance
var focus_action =function (){
console.log('focus');
}; /*callback must have own name*/
ckeditor.on('instanceReady',function (){
var _this=this;
this.document.on('keyup',function (){
console.log(ckeditor.checkDirty());
});
this.document.on('focus',focus_action); //bind our callback
this.document.on('blur',function (){
console.log('blur');
_this.document.removeListener('focus',focus_action); //remove our callback
//_this.document.removeAllListeners(); //remove all listeners
});
});

How to refer to object in JavaScript event handler?

Note: This question uses jQuery but the question has nothing to do with jQuery!
Okay so I have this object:
var box = new BigBox();
This object has a method named Serialize():
box.AddToPage();
Here is the method AddToPage():
function AddToPage()
{
$('#some_item').html("<div id='box' onclick='this.OnClick()'></div>");
}
The problem above is the this.OnClick() (which obviously does not work). I need the onclick handler to invoke a member of the BigBox class. How can I do this?
How can an object refer to itself in an event handler?
You should attach the handler using jQuery:
function AddToPage()
{
var self = this;
$('#some_item').empty().append(
$("<div id='box'></div>")
.click(function() { self.OnClick(someParameter); })
);
}
In order to force the event handler to be called on the context of your object (and to pass parameters), you need to add an anonymous function that calls the handler correctly. Otherwise, the this keyword in the handler will refer to the DOM element.
Don't add event handlers with inline code.
function AddToPage()
{
$('#some_item').html("<div id='box'></div>");
$('#box').click(this.OnClick);
}
EDIT:
Another way (avoids the extra select):
function AddToPage()
{
var div = $('<div id="box"></div>'); // probably don't need ID anymore..
div.click(this.OnClick);
$('#some_item').append(div);
}
EDIT (in response to "how to pass parameters");
I'm not sure what params you want to pass, but..
function AddToPage()
{
var self = this, div = $('<div></div>');
div.click(function (eventObj) {
self.OnClick(eventObj, your, params, here);
});
$('#some_item').append(div);
}
In jQuery 1.4 you could use a proxy.
BigBox.prototype.AddToPage= function () {
var div= $('<div>', {id: box});
div.click(jQuery.proxy(this, 'OnClick');
div.appendTo('#some_item');
}
You can also use a manual closure:
var that= this;
div.click(function(event) { that.OnClick(event); });
Or, most simply of all, but requiring some help to implement in browsers that don't yet support it (it's an ECMAScript Fifth Edition feature):
div.click(this.OnClick.bind(this));
If you are using jQuery, then you can separate your code from your markup (the old seperation of concerns thing) like this
$(document).ready(function() {
var box = new BigBox();
$('#box').click(function() {
box.serialize();
});
});
You only need to add the click handler once for all divs with id of box. And because the click is an anonymous function, it gets the scope of the function it is placed in and therefore access to the box instance.

Categories