I have an object :
var myObject = {
open : function() {
console.log('Object open');
$(this).trigger('open');
}
};
$(myObject).on('open', function() {
console.log('Open event received');
});
myObject.open();
This code throw an "too much recursion".
The problem is that trigger is calling the method, if I rename the open method, this works :
var myObject = {
_open : function() {
console.log('Object open');
$(this).trigger('open');
}
};
$(myObject).on('open', function() {
console.log('Open event received');
});
myObject._open();
Does this make sense for anyone ?
Well you created a recursive loop when you try to trigger 'open' again.
a reccursive loop is a function that calls itself over and over agains until the "stackoverflow" error happen ( no puns intended). it's a more efficient way to make loops.
on the second scenario, you trigger _open and then the function tries to trigger the 'open' event, which trigger the on('open') listener.
simple as that.
In your first example
$(this).trigger('open');
recursively triggers the invocation of the myObject.open function.
In a second one
$(this).trigger('open');
triggers new custom event 'open' and then you handle this event with handler that you defined via on() method.
So it sounds like your trying to create a event listener for when your function is executed?
If so this is how I have handled many of these types of events. I use custom events bound to the document so they are avaiable at a global level.
JS Fiddle: https://jsfiddle.net/7eaoe1hp/
var myObject = {
open : function() {
console.log('Object open');
$(document).triggerHandler('open');
}
};
$(document).on('open', function(){
console.log('Open event received');
});
myObject.open();
Related
I'm calling via ajax additional content where I add a jquery on() function for a click event. Each time I renew the content the event is also set again so at the end it get executed several times. How can I avoid this behavior?
How do I test if the click event is already set on the document?
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Click
<script>
// first ajax load
$(document).on('click', '.open-alert', function () {
alert('hello world!');
});
// second ajax load
$(document).on('click', '.open-alert', function () {
alert('hello world!');
});
</script>
I already try to just the jQuery.isFunction(), but I don't anderstand how to apply it in this case.
You can Unbind the click event , if you getting more than one time exectuated.
$(document).unbind('click').on("click", ".open-alert", function () {
//do stuff here
});
Or you can also use it
$(document).off("click", ".open-alert").on("click", ".open-alert", function () {
});
Using
$(document).on('click', '#element_id', function() {
//your code
});
Will check the DOM for matching elements every time you click (usually used for dynamically created elements with ajax)
But using
$('#element_id').on('click', function() {
//your code
});
Will only bind to existing elements.
If you use the 1st example, you only need to call it once, you can even call it before your ajax call since it will recheck for matching elements on each click.
<script>
$(document).on('click', '.open-alert', function () {
alert('hello world!');
});
// first ajax load
// second ajax load
...
</script>
In case you cannot bind the event to the specific DOM element (which might happen if you use Turbolinks for example) you can use a variable to check whether you set the event or not.
Local scope
var clickIsSet = false;
// any ajax load
$(document).on('click', '.open-alert', function () {
if ( clickIsSet ) {
alert('hello world!');
clickIsSet = true;
}
});
Global scope
I don't recommend to make clickIsSet global, but in case you are importing/exporting modules you can do that:
// main.js
window.clickIsSet = false;
// any-other-module.js
$(document).on('click', '.open-alert', function () {
if ( window.clickIsSet ) {
alert('hello world!');
window.clickIsSet = true;
}
});
jQuery check if event exists on element : $._data( $(yourSelector)[0], 'events' )
this return all of element events such : click , blur ,
focus,....
Important Note: $._data when worked that at least an event bind to element.
so now:
1.in your main script or first ajax script bind click event on element
<script>
$(document).on('click', '.open-alert', function () {
alert('hello world!');
});
</script>
2. in secound ajax:
var _data = $._data( $('.open-alert')[0], 'events' );
if(typeof _data != "undefined"){
var eventClick = $._data( $('.open-alert')[0], 'events' ).click
var hasEventClick = eventClick != null && typeof eventClick != "undefined";
if(!hasEventClick){
$(document).on('click', '.open-alert', function () {
alert('hello world!');
});
}
}
I get Confuse about your question but as far as understand your question I have three suggestions:
Use Id element (as #Mokun write the answer)
Use Common Function for call functionality instead use through the click event.(Make Sure of function does not overwrite your content by calling).
Use of flag variable (or global variable for your tracking event) in jquery and identify your function call for particular execution.
I've been working on this for a while. But I think it is going to be difficult for me to simply it for this question.
I have this object. It is a child to an other object.
The child object has an 'action' attribute which executes a fn();
On a mouse click I fire off the action I can see I am executing fn() with no problems.
I want fn() to trigger an event of the parent object.
$('#par).on('trgr.obj', fn(e, dta) { alert('success'); });
$('#par').obj({
chi: { action: fn(dta) {
console.log("doing okay so far");
// Here is where I'm trying to trigger trgr.obj event
// this is what I have so far.
var inst = $.obj.reference(dta.reference);
var objT = inst.get_node(dta.reference);
inst.trgr(
objT, { type: "default" }, "last"
, function (newDta) {
setTimeout(function () { inst.edit(newDta); }, 0);
}
);
}}
});
How does action trigger event 'trgr.obj'?
Any help appreciated.
Are you looking for jQuery to trigger a custom event?
Try $('#par').trigger('trgr.obj')
http://api.jquery.com/on/
I'm trying to run a function twice. Once when the page loads, and then again on click. Not sure what I'm doing wrong. Here is my code:
$('div').each(function truncate() {
$(this).addClass('closed').children().slice(0,2).show().find('.truncate').show();
});
$('.truncate').click(function() {
if ($(this).parent().hasClass('closed')) {
$(this).parent().removeClass('closed').addClass('open').children().show();
}
else if ($(this).parent().hasClass('open')) {
$(this).parent().removeClass('open').addClass('closed');
$('div').truncate();
$(this).show();
}
});
The problem is on line 13 where I call the truncate(); function a second time. Any idea why it's not working?
Edit jsFiddle here: http://jsfiddle.net/g6PLu/
That's a named function literal.
The name is only visible within the scope of the function.
Therefore, truncate doesn't exist outside of the handler.
Instead, create a normal function and pass it to each():
function truncate() { ...}
$('div').each(truncate);
What's the error message do you get?
You should create function and then call it as per requirement
Define the function
function truncate(){
$('div').each(function(){
});
}
Then call the function
truncate();
Another approach is to establish, then trigger, a custom event :
$('div').on('truncate', function() {
$(this).......;
}).trigger('truncate');
Then, wherever else you need the same action, trigger the event again.
To truncate all divs :
$('div').trigger('truncate');
Similarly you can truncate just one particular div :
$('div#myDiv').trigger('truncate');
The only prerequisite is that the custom event handler has been attached, so ...
$('p').trigger('truncate');
would do nothing because a truncate handler has not been established for p elements.
I know there's already an accepted answer, but I think the best solution would be a plugin http://jsfiddle.net/g6PLu/13/ It seems to be in the spirit of what the OP wants (to be able to call $('div').truncate). And makes for much cleaner code
(function($) {
$.fn.truncate = function() {
this.addClass('closed').children(":not('.truncate')").hide().slice(0,2).show();
};
$.fn.untruncate = function() {
this.removeClass('closed').children().show();
};
})(jQuery);
$('div').truncate();
$('.truncate').click(function() {
var $parent = $(this).parent();
if ($parent.hasClass('closed')) {
$parent.untruncate();
} else {
$parent.truncate();
}
});
At row level I catch the event and try to add an extra parameter
onRowClick: function(e){
console.log("Event in row");
e.model = "test";
console.log(e.model) // prints 'test'
}
In main view I catch the same event again
onRowClick: function(e){
console.log("Event in main view");
console.log(e.model) //prints undefined
}
Console:
>Event in row
>test
>Event in main view
>undefined
How can I append an attribute to the event?
The answer is that you don't catch the same event, but rather two (initially) identical events. Changing the first does not change the latter.
If you want to pass data between those events, you would need to store that data elsewhere (e.g. a closure, or if you don't care about the scope save it in the window object).
There are 2 ways that I know of to pass data to a jQuery event. One with with e.data, you can add any properties to e.data like this.
http://www.barneyb.com/barneyblog/2009/04/10/jquery-bind-data/
the other way is to use closures such as:
function myFunc() {
var model = 'test';
var x = {
onRowClick: function(e){
console.log("Event in row");
console.log(model) // prints 'test'
}
}
}
instead of catching the rowClick event in the main view, i suggest you catch it in the row view, and pass it through the backbone event system...
your parentview can bind to it's rows to catch a click.
there are two ways to do this,
trigger a custom event on your row's model, and let the parent bind to every model in the collection, though that seems like a hack and a performance hit.
i suggest doing it with an event aggregator:
var App = {
events: _.extend({}, Backbone.Events);
};
var myGeneralView = Backbone.Views.extend({
initialize: function() {
_.bindAll(this, "catchMyCustomEvent";
/*
and here you bind to that event on the event aggregator and
tell it to execute your custom made function when it is triggered.
You can name it any way you want, you can namespace
custom events with a prefix and a ':'.
*/
App.events.bind('rowView:rowClicked');
},
catchMyCustomEvent: function (model, e) {
alert("this is the model that was clicked: " + model.get("myproperty"));
}
// other methods you will probably have here...
});
var myRowView = Backbone.Views.extend({
tagName: "li",
className: "document-row",
events: {
"click" : "myRowClicked"
},
initialize: function() {
_.bindAll(this, "myRowClicked");
},
myRowClicked: function (e) {
/*
You pass your model and your event to the event aggregator
*/
App.events.trigger('rowView:rowClicked', this.model, e);
}
});
in some function I remove element like this $('#'+id+' img.load').remove(); , how can i track this event and run custom code?
(function($){
var remove_orig = $.fn.remove;
$.fn.remove = function(){
console.log('Remove called');
remove_orig.apply(this, arguments);
};
})(jQuery);
You can "hook" in to any jQuery function and place your own handling code within (including logging method(s)) which will execute before the native jQuery code is executed.
demo (another version with the selector shown)
Catching the removal is easy using the above overload. Simply alter the hook to fire a trigger before (or after) jQuery gets to it:
(function($){
var remove_orig = $.fn.remove;
$.fn.remove = function(){
this.trigger('removing');
remove_orig.apply(this, arguments);
};
})(jQuery);
$('#foo').bind('removing',function(e){
alert('#foo is being removed');
});
$('#foo').remove();
One way is to "trigger" a custom event (in this example I am using window):
$('#'+id+' img.load').remove();
$(window).trigger("MyElementRemoved", [id]);
Then in another part of your code "handle" the event:
$(window).bind("MyElementRemoved", function(e, elementId) {
alert("element removed: " + elementId);
}