Jquery Event Delegation Issue - javascript

Can anyone suggest where I'm going wrong here? news_active is a static div, everything else is loaded in via ajax calls, nothing is being triggered for the alert, pretty stumped?!
$('#news_active').load('ajax.php', function() {
// Delete news active
$('#news_delete').on('click', function() {
var vNid = $('#news_delete').attr('data-nid').val();
alert(vNid);
//$('#news_active').load('ajax.php?nid='+vNid);
});
});
The button looks like this, there are multiple buttons loaded in with different data-nid values:
<button id="news_delete" data-nid="1">Delete</button>

Since the news_delete is loaded dynamically, you need to use event delegation to register the event handler like:
// New way (jQuery 1.7+) - .on(events, selector, handler)
$('#news_active').on('click', '#news_delete', function(event) {
var vNid = $('#news_delete').data('nid');
alert(vNid);
});
Also, the way of getting the data-nid attribute value in your code is not correct.
Either use this:
var vNid = $('#news_delete').attr('data-nid'); // No need of .val() here
alert(vNid);
or just this using .data()
var vNid = $('#news_delete').data('nid');
alert(vNid);

You should use data() method instead:
var vNid = $('#news_delete').data('nid');
or just attr('data-nid') without val().
val() is trying to get Element.value property and you don't have it in button.

var vNid = $('#news_delete').attr('data-nid').val(); //remove the value it
// will return the value of button
change it to
var vNid = $('#news_delete').attr('data-nid');

Related

Assigning a jquery object to a variable doesn't work as expected

Can someone explain why one of these versions of code works and the other fails?
This doesn't work:
var classForSelectedElement = "hightlight";
var prevSelect = $(".form-element");
var $selectedElement = $("div").on("click", ".form-element",function(e){
prevSelect.removeClass(classForSelectedElement);
$(this).addClass(classForSelectedElement);
});
Whereas this works:
var classForSelectedElement = "hightlight";
var $selectedElement = $("div").on("click", ".form-element",function(e){
$(".form-element").removeClass(classForSelectedElement);
$(this).addClass(classForSelectedElement);
});
Why?
Presuming that the .form-element elements are appended to the DOM dynamically after load (due to your usage of a delegated event handler) then the first example doesn't work as you are attempting to retrieve the .form-element on load of the page before they exist.

callback after jQuery.trigger() function

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.

trigger a function on DOM load

I have this little function :
$('.chrnumberpickerDiv select').change(function(){
var sel = $(this),
value = sel.closest('.chrnumberpickerDiv').find('.chrnumberpickerDivText');
value.text(sel.find(':selected').text());
}).one('change');
My problem is that I also need to trigger it on DOM load. I have tried .trigger('change') instead of .one('change') but it seems like it goes in a loop and never stops refreshing my page. So what could I be doing to trigger the event on DOM but without causing any damages to other events or whatever makes the function go in a loop ?
If I understood your question, you need to trigger a function when the select changes, as well as programmatically trigger it when the page loads to populate an initial value:
// define the handler
var changeHandler = function() {
var sel = $(this),
value = sel.closest('.chrnumberpickerDiv').find('.chrnumberpickerDivText');
value.text(sel.find(':selected').text());
};
// bind the handler
$('.chrnumberpickerDiv select').change(changeHandler);
$(document).ready(function () {
// execute the handler on page load
// use proxy to change what "this" means in the handler
// (jQuery does this for you when you bind a handler through jQuery)
$.proxy(changeHandler, $('.chrnumberpickerDiv select')[0]));
});
Documentation for proxy
Try this, instead of your code
$(document).ready(function() {
$('.chrnumberpickerDiv select').change(function(){
var sel = $(this),
value = sel.closest('.chrnumberpickerDiv').find('.chrnumberpickerDivText');
value.text(sel.find(':selected').text());
}).one('change');
});
you have be careful not to assign multiple change functions. Otherwise all of them are called when the change event happens.

Jquery if its the first time element is being clicked

I need my script to do something on the first time an element is clicked and continue to do something different on click 2,3,4 and so on
$('selector').click(function() {
//I would realy like this variable to be updated
var click = 0;
if (click === 0) {
do this
var click = 1;
} else {
do this
}
});//end click
really I think it should rely on the variables but I can't think of how to update the variable from here on out any help would be awesome.
Have a look at jQuery's .data() method. Consider your example:
$('selector').click(function() {
var $this = $(this),
clickNum = $this.data('clickNum');
if (!clickNum) clickNum = 1;
alert(clickNum);
$this.data('clickNum', ++clickNum);
});
See a working example here: http://jsfiddle.net/uaaft/
Use data to persist your state with the element.
In your click handler,
use
$(this).data('number_of_clicks')
to retrieve the value and
$(this).data('number_of_clicks',some_value)
to set it.
Note: $(this).data('number_of_clicks') will return false if it hasn't been set yet
Edit: fixed link
Another alternative might be to have two functions, and bind one using the one function in $(document).ready() (or wherever you are binding your handlers), and in that function, bind the second function to be run for all subsequent clicks using bind or click.
e.g.
function FirstTime(element) {
// do stuff the first time round here
$(element.target).click(AllOtherTimes);
}
function AllOtherTimes(element) {
// do stuff all subsequent times here
}
$(function() {
$('selector').one('click', FirstTime);
});
This is super easy in vanilla Js. This is using proper, different click handlers
const onNextTimes = function(e) {
// Do this after all but first click
};
node.addEventListener("click", function onFirstTime(e) {
node.addEventListener("click", onNextTimes);
}, {once : true});
Documentation, CanIUse
If you just need sequences of fixed behaviors, you can do this:
$('selector').toggle(function(){...}, function(){...}, function(){...},...);
Event handlers in the toggle method will be called orderly.
$('#foo').one('click', function() {
alert('This will be displayed only once.');
});
this would bind click event to Corresponding Html element once and unbind it automatically after first event rendering.
Or alternatively u could the following:
$("#foo").bind('click',function(){
// Some activity
$("#foo").unbind("click");
// bind it to some other event handler.
});

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