javascript action to trigger an event - javascript

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/

Related

jQuery event collision

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();

Prevent duplcate ajaxLoad event calls added with a click event

I am using MVC Razor - The overall goal is to create a "print view" pop-up page.
The print view button is on the parent page, when clicked, an ajax event is fired which will populate an empty div with the contents that are to be included in the print preview:
//from the view
#Ajax.ActionLink("prntPreview", "Display", new { ID = Model.Detail.ID }, new AjaxOptions { UpdateTargetId = "modal" }, new { #class = "btnPreview" })
then, using JavasScript/jQuery I clone the contents of that newly populated div and create a new window with the contents:
//in the scripts file
$('.btnPreview').on('click', function () {
$(document).ajaxStop(function () {
var pageData = $('#modal').html();
setTimeout( //add a slight delay
function () {
PopupPrint(pageData);
}, 300);
});
});
function PopupPrint(data) {
var mywindow = window.open('', '', 'height=500,width=800,resizable,scrollbars');
mywindow.document.write(data);
mywindow.focus();
//do some other stuff here
}
This is where I run into difficulty. The first time I click, everything is working as expected - however, if you do not navigate away from the parent page and try to use the print preview button a second time, the popup will be created twice, then three times etc. with each additional click.
I think that the problem is because each time the .btnPreview is clicked, a new $(document).ajaxStop event is being created, causing the event to fire multiple times.
I have tried to create the ajaxStop as a named function which is declared outside the scope of the click event and then clear it but this produces the same result:
var evnt = "";
$('.btnPreview').on('click', function () {
evnt =
$(document).ajaxStop(function () {
var pageData = $('#modal').html();
setTimeout( //add a slight delay
function () {
PopupPrint(pageData);
evnt = "";
}, 300);
});
});
I also have other ajaxStop events initialised so don't want to completely unbind the ajaxStop event. Is it possible to get the name or something from each ajax event so that I can clear just that event or similar?
You can prevent adding additional triggers by checking with a variable outside of scope like this:
(function() {
var alreadyAdded = false;
$('.btnPreview').on('click', function() {
if (!alreadyAdded) {
$('.eventTrigger').click(function() {
console.log('printing!');
});
alreadyAdded = true;
}
});
})();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="btnPreview">Add Event</button>
<button class="eventTrigger">Trigger</button>
Please note that the variable and function are encapsulated in a self-executing anonymous function and do not pollute global space.
The output of the sample can be seen in the developer console. If you remove the if-check then every click on the "Add Event" button produces an additional print statement on the "Trigger" button each time it is clicked (which is your problem). With the if, there will ever only be one event on the trigger button.
There were 2 issues which I needed to address.
The answer is to unbind the ajax event after it has checked that the request had completed and to unbind and reattach the button click trigger.
This is how I did it:
//in the scripts file
$('.btnPreview').off('click').on('click', function () {
$(document).ajaxComplete(function (e) {
var pageData = $('#modal').html();
setTimeout( //add a slight delay
function () {
PopupPrint(pageData);
}, 300);
$(this).off(e);
});
});
I unbound the click event by adding .off('click') before the .on. this is what stopped it popping up multiple times.
The other issue was that anytime any ajax event completed (triggered by something else) that would also create the popup - to get around that, I added $(this).unbind(e); to the end of the code block which removed the ajaxComplete binding which was being triggered each time any ajax event completed.

Binding 'this' and getting this

$('.btn-delete').on('click', this.confirm.bind(this));
Above, on click it runs:
p.confirm = function(e) {
if(!$(this).hasClass('danger')){
$(this).addClass('danger');
$(this).bind('mouseleave',function(){
$(this).removeClass('danger');
$(this).unbind('mouseleave');
});
}
else{
this.delete();
}
};
I'm having trouble with this. I need this to get the button but I also need this to access another method (this.delete). I've tried bind but it faisl to work.
Any ideas?
Assuming I'm understanding your question correctly, you want to be able to pass the clicked element as this to the p.confirm function. You should be able to do this by using call, or by using p.confirm as the handler:
// using call
$('.btn-delete').on('click', function (e) {
p.confirm.call(this, e);
});
// as handler
$('.btn-delete').on('click', p.confirm);
Assuming that this.delete is actually p.delete, just use call in the handler to pass the clicked element as this to the delete method:
p.confirm = function (e) {
var self = $(this); // cache lookup, "this" is the clicked element
if (!self.hasClass('danger')) {
self.addClass('danger');
self.bind('mouseleave', function () {
self.removeClass('danger');
self.unbind('mouseleave');
});
} else {
p.delete.call(this); // pass clicked element to use as "this" in p.delete
}
};

Too much recursion in JavaScript

I have this JavaScript which opens new page:
$(document).ready(function () {
//$('a[id$="lnkHidden"]').trigger("click"); // Not sure if this is actually necessary
$('table[id$="dataTable"]').find("tbody").on("click", "tr", function () {
$(this).find('a[id$="lnkHidden"]').trigger("click");
});
});
This is the button which is called by the JS script:
<h:commandLink id="lnkHidden" action="#{bean.pageRedirect}" style="text-decoration:none; color:white; display:none">
</h:commandLink>
After I click on a table row I get this error message:
too much recursion [Break On This Error] ...,c=l.length;c--;)(f=l[c])&&(v[d[c]]=!(y[d[c]]=f));if(i){if(o||e){if(o){for(l=‌​[],...
Can you help me to fix this?
You can cut the infinite loop with those changes from your original code
add a second argument to trigger. The call becomes .trigger("click", [ true ])
name arguments in the event handler : function(event, simulated)
use the simulated argument which is set to true from the trigger : simulated || $(this).find('a[id$="lnkHidden"]').trigger("click", [ true ]);
However that event triggering and that kind of selectors are not recommended.
Instead of triggering synthetic click events, you could just change the current URL directly:
$(document).ready(function () {
$('table[id$="dataTable"]').find("tbody").on("click", "tr", function () {
var links = $(this).find('a[id$="lnkHidden"]');
if(links.length && links[0].href) {
window.location.href = links[0].href;
}
});
});

Overwriting a Backbone Models Change Event

I think what I want to do is pretty simple I just don't know how to do it. I would like to fire my own event when one of my models attributes changes for the purpose of passing some data to the event handler (whether the change was an increase or decrease in value).
Basically I want my handler to do this in the view
handler: function(increased) {
if(increased) {
alert("the value increased")
}
else {
alert("the value decreased")
}
}
// ...
this.model.on("change:attr", this.handler, this);
Here you go: You basically listen for change:myvar. When a change occurs you use your model's previous() to get the old value. Depending on whether it increased or decreased you fire the appropriate event. You can listen to these events as shown in the initialize().
(function($){
window.MyModel = Backbone.Model.extend({
initialize: function () {
this.on('change:myvar', this.onMyVarChange);
this.on('increased:myvar', function () {
console.log('Increased');
});
this.on('decreased:myvar', function () {
console.log('Decreased');
});
},
onMyVarChange: function () {
if (this.get('myvar') > this.previous('myvar')) {
this.trigger('increased:myvar');
} else {
this.trigger('decreased:myvar');
}
}
});
window.mymodel = new MyModel({myvar: 1});
mymodel.set({myvar: 2});
mymodel.set({myvar: 3});
mymodel.set({myvar: 1});
})(jQuery);​
Running the above will print "Increased", "Increased", "Decreased" to your console.
Just look at previousAttributes()
You can then compare:
If(this.get(attr) > this.previousAttributes()[attr]){
console.log('bigger');
} else {
console.log('smaller');
}
If you use that in your change event handler you're all set. No need for a custom trigger or a ton of code.
EDIT
This is from my Backbone.Validators project and how I obtain the list of all attributes which have changed during the validation step:
var get_changed_attributes = function(previous, current){
var changedAttributes = [];
_(current).each(function(val, key){
if(!_(previous).has(key)){
changedAttributes.push(key);
} else if (!_.isEqual(val, previous[key])){
changedAttributes.push(key);
}
});
return changedAttributes;
};
This requires Underscore 1.3.1 because it's using _.has. If you can't upgrade that's an easy thing to replace though. In your case you'd passing this.previousAttributes() and this.attributes
What if you fire your own custom event after listening to the change event?
handler: function(increased) {
this.model.trigger('my-custom-event', stuff, you, want);
},
myHandler: function(stuff, you, want){
// Do it...
}
// ...
this.model.on("change:attr", this.handler, this);
this.model.on('my-custom-event, this.myHandler, this);

Categories