jQuery Execute Order - jquery-plugins

I'm using the following jQuery plugin and it executes when there's a click action on the specified element :
http://www.andresvidal.com/labs/relcopy.html
I also created a click function for the same element, but I expected it to execute after the plugin. However that isn't the case, the click function always executes first, thus causing problems.
Please check my code below for example, I'm new to jQuery so any suggestions / help would really be appreciated!
$.getScript('../js/relCopy.js', function() {
$('#AddTable').relCopy({
limit: 10,
excludeSelector: '.newListSelected'
});
$('#AddTable').click(function() {
do something here after relcopy has finished
});

Event handlers are executed in the order they were bound, and since the callback from $.getScript() executes after that script is loaded, it's binding it's click handler after yours.
So get the order you want you need to bind in the order you want, that means binding your click handler in the callback as well, like this:
$.getScript('../js/relCopy.js', function() {
$('#AddTable').relCopy({
limit: 10,
excludeSelector: '.newListSelected'
}).click(function() {
//do something here after relcopy has finished
});
});

Related

Meteor, how to browser tab select events?

Template.temp.events({
"focusOut window" : function(){
console.log('exit window')
}
});
Like this focusOut window trigger code?
Not sure this will work as the template will only list to dom events inside its own scope.
Better to handle this using jquery and setup an event listener when the template is rendered.
Template.temp.onRendered(function() {
Meteor.setTimeout(function(){
$(window).blur(function() {
// Do something here....
$("title").text("Don't forget to read this..." + pageTitle);
});
}, 1000);
}
Something along these lines should work, its fragile... and may need some tweaking, but this should get you started.

How can I waitFor an element to have children with Geb?

I'm executing a test that runs a functional use of a "click to add" feature.
The user is given a table of items that allow them to click an "Add" button to add the item to their cart.
The button executes an ajax call to append the item to the user's cart. When the item is added successfully, the item is then displayed in the Cart UI. The Cart UI is essentially another table.
//pseudo code
$('.addButton').on('click', function (event) {
$.ajax({
url:...,
success: updateCart
});
});
function updateCart (data) {
// use data to create tr_fragment
$("#cart-ui-target").append(tr_fragment); //new row
}
What I've tried is in the then statement is use waitFor until the #cart-ui-target has a <tr> size greater or equal to 1:
waitFor(5) {$('#cart-ui-target').find('tr').size() >= 1}
However, every once in a while the test fails with the following exception:
geb.waiting.WaitTimeoutException: condition did not pass in 5.0 seconds (failed with exception)
I've even tried to increase the waitFor time to 10 seconds with a 2 second interval, but it still doesn't work:
waitFor(10, 2) {$('#cart-ui-target').find('tr').size() >= 1}
What can I do to make this a better wait and prevent the sporadic failures?
UPDATE
This is what I'm seeing in the log info of phantomjs.
$('#cart-ui-target').find('tr').size()
| | |
| [] 0
[[[[[PhantomJSDriver: phantomjs on LINUX (113358b0-7bf1-11e4-a10e-9f2b2537fa31)] -> tag name: html]] -> css selector: #cart-ui-target]]
I think your trying to test the JavaScript behaviour, not the adding to the cart itself (probably tested in backend logic?).
I think the way to go is to mock $.ajax and call the callback from your mock using fixture data. If your using jasmine this can look something this:
it('should add something when something is succesfully addes', function() {
data = 'data_for_callback_here';
spyOn($, 'ajax').andCallFake(function(data) { data.success(data); } );
$('.addButton').click();
expect() // Expect something
});

jQuery Mobile 1.4+ pagecontainerbeforechange bug?

I am experimenting with the new way of handling page events in jqM and have run into a curious issue. When handling the pagecontainerbeforechange event
$(document).on('pagecontainerbeforechange',function(e,u){test(e,u,'changing');})
function test(e,u,msg){console.log($(u.toPage));}
Attempting to put a jQuery object wrapper around u.toPage - as done above - produces strange behavior.
Check out this fiddle to see what I mean
Click on the Second Page button and then view the console. Nothing will happen (the second page is not shown) and you will see a message along the lines of *Uncaught error:syntax error, unrecognized expression http://jsfiddle.net/egn7g5xb/1/show/#second
Now comment out Line 7 and run the fiddle again. No such issue this time and the second page gets shown.
Perhaps someone here might be able to explain what is going on here?
On initial run, jQuery Mobile creates a fake page before navigating to first page in DOM. At that stage, pagecontainerbeforechange fires twice and returns .toPage as an object.
Later on, upon navigating to other pages, it fires twice again; however, it returns a string first time (URL/hash) and second time it returns an object which is the page itself.
Therefore, when using that event, you have to determine whether .toPage is an object or a string.
$(document).on("pagecontainerbeforechange", function (e, data) {
if (typeof data.toPage == "string") {
/* parse url */
}
if (typeof data.toPage == "object") {
/* manipulate page navigating to */
}
});
Note that pagecontainerbeforetransition is similar to beforechange, however, it fires once and returns .toPage as an object.
First, create your pagecontainer events within $(document).on("pagecreate", "#first", function(){ .. }).
Then the selector for these events should be $(":mobile-pagecontainer") or $("body") NOT $(document).
function test(e,u,msg)
{
console.log(msg);
var IsJQ = u.toPage instanceof $;
console.log(IsJQ);
if (IsJQ){
console.log(u.toPage.data());
} else {
console.log(u.toPage);
}
console.log('---');
}
$(document).on("pagecreate", "#first", function(){
$(":mobile-pagecontainer").on('pagecontainerbeforechange', function (e, u) {
test(e,u,'changing');
});
$(":mobile-pagecontainer").on('pagecontainerchange',function(e,u){
test(e,u,'changed');
});
});
Updated FIDDLE

BackboneJS .ajaxStart() and .ajaxStop() while fetching collection

I have a BackboneJS App where I fetch a bunch of collections. Now I want to apply some sort of loader to indicate that the collection is loading and the user gets to know that something is happening. So I want to use the .ajaxStart() and .ajaxStop()-method. So I was thinking about something like this:
this.artistsCollection.fetch(
$(document).ajaxStart(function () {
console.log('ajax start');
$('.someDiv').addClass('TEST');
}),
$(document).ajaxStop(function () {
console.log('ajax stop');
// stop doing stuff
})
);
Issue is that first time I trigger the .fetch() my console says ajax stop and the class is not applied!?!? Second time I trigger the .fetch() it works like it should and the class gets applied. Does anyone know whats the issue?
Please help anyone?
You're passing the returned result of adding the two event handlers with jQuery as parameters to the Collection fetch method. The Backbone Collection fetch method receives an options object which can include a success callback (see documentation).
I think if you move the listeners out of the method call it should work as you expect:
// Global AJAX listeners
$(document).ajaxStart(function () {
console.log('ajax start');
// do stuff
});
$(document).ajaxStop(function () {
console.log('ajax stop');
// stop doing stuff
});
this.artistsCollection.fetch();

Event removal in Mootools, and syntax of event addition

So I have been adding my events thusly:
element.addEvent('click', function() {
alert('foobar');
});
However, when attempting to remove said event, this syntactically identical code (with "add" switched to "remove") does not work.
element.removeEvent('click', function() {
alert('foobar');
});
I assume this is because the two functions defined are not referenced the same, so the event is not technically removed. Alright, so I redefine the event addition and removal:
element.addEvent('click', alert('foobar'));
element.removeEvent('click', alert('foobar'));
Which works great, except now when the page loads, the click event is fired even before it's clicked!
The function is removed, though, which is great......
update: when you do .addEvent('type', function(){ }) and .removeEvent('type', function(){ }), even though the functions may have the same 'signatures', they are two separte anonymous functions, assigned on the fly. function 1 is !== to function 2 - hence there is no match when MooTools tries to remove it.
to be able to remove an exact handler, o:
function handler(){ ... }
el.addEvent('click', handler);
// .. later
el.removeEvent('click', handler);
Internally, events are actually a map of keys to functions in element storage. have a look at this fiddle i did a while back for another SO question - http://www.jsfiddle.net/mVJDr/
it will check to see how many events are stacked up for a particular event type on any given element (or all events).
similarly, removeEvent looks for a match in the events storage - have a look on http://jsfiddle.net/dimitar/wLuY3/1/. hence, using named functions like Nikolaus suggested allows you to remove them easily as it provides a match.
also, you can remove events via element.removeEvents("click") for all click events.
your page now alerts because you pass on alert as the function as well as execute it with the params 'foobar'. METHOD followed by () in javascript means RUN THE METHOD PRECEDING IT IMMEDIATELY, NOT LATER. when you bind functions to events, you pass the reference (the method name) only.
to avoid using an anonymous function and to pass argument,s you can do something like:
document.id('foobar').addEvent('click', alert.bind(this, 'foo'));
as bind raps it for you, but removing this will be even more complicated.
as for event delegation, it's:
parentEl.addEvents({
"click:relay(a.linkout)": function(e, el) {
},
"mouseover:relay(li.menu)": function(e, el) {
}
});
more on that here http://mootools.net/docs/more/Element/Element.Delegation#Element:removeEvent
keep in mind it's not great / very stable. works fine for click stuff, mouseenter is not to be used delegated, just mouseover - which means IE can fire mouseout when it should not. the way i understand it, it's coming improved in mootools 2.0
edit updating to show an example of bound and unbound method within a class pattern in mootools
http://www.jsfiddle.net/wmhgw/
var foo = new Class({
message: "hi",
toElement: function() {
return this.element = new Element("a", {
href: "http://www.google.com",
text: "google",
events: {
"click": this.bar.bind(this), // bind it
"mouseenter": this.bar // unbound -> this.element becomes this
}
});
},
bar: function(event) {
event.stop();
// hi when bound to class instance (this.message will exist)
// 'undefined' otherwise.
console.log(this.message || "undefined");
}
});
document.id(new foo()).inject(document.body);
the mouseenter here will be unbound where this will refer to the default scope (i.e the element that triggered the event - the a href). when bound, you can get the element via event.target instead - the event object is always passed on to the function as a parameter.
btw, this is a slightly less familiar use of class and element relation but it serves my purposes here to illustrate binding in the context of classes.
assig the function to a variable and use the same reference to add and remove the event.
if you use an anonymous function you will get to different references
var test = function(){ alert('test: ' + this.id); }
$('element').addEvent('click', test);
...
$('element').removeEvent('click', test);
addEvent : Attaches an event listener to a DOM element.
Example -
$('myElement').addEvent('click', function(){
alert('clicked!');
});
removeEvent : Works as Element.addEvent, but instead removes the specified event listener.
Example -
var destroy = function(){ alert('Boom: ' + this.id); } // this refers to the Element.
$('myElement').addEvent('click', destroy);
//later...
$('myElement').removeEvent('click', destroy);
This means when you add an event with a eventhandler not an anonymous function if you than remove the event than it will be removed.

Resources