I have some code like this:
$scope.$on("$locationChangeStart", function(event, newPath, oldPath) {
// Do some sync checks
if (!$scope.isPageAllowed($location.path()))
{
// Prevent default for some reason
event.preventDefault();
}
});
When I trying to resolve promises like this:
$scope.$on("$locationChangeStart", function(event, newPath, oldPath) {
// Do some async checks
$scope.fooPromises().then(function (data) {
// Prevent default for some reason when promises resolved (only if resolved)
event.preventDefault();
});
});
I got successfull event (because of async execution) and after a while prevented event when promises are resolved.
Is there a way to link event with my promises, so it would be prevented exactly after promises being resolved and not streight after function end?
Sorry, this won't work :-). Events are purely synchronous.
You're looking for $route.resolve. Asynchronous resolution/rejection of routes, to give a controller data or just to check something.
http://www.egghead.io/video/Kr1qZ8Ik9G8
Related
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();
I'm triyng to build a simple animation jQuery-plugin. The main idea is to take an element and manipulate it in some way repeatedly in a fixed intervall which would be the fps of the animation.
I wanted to accomplish this through events. Instead of using loops like for() or while() I want to repeat certain actions through triggering events. The idea behind this: I eventualy want to be able to call multiple actions on certain events, like starting a second animation when the first is done, or even starting it when one animation-sequence is on a certain frame.
Now I tried the following (very simplified version of the plugin):
(function($) {
$.fn.animation = function() {
obj = this;
pause = 1000 / 12; //-> 12fps
function setup(o) {
o.doSomething().trigger('allSetUp');
}
function doStep(o, dt) {
o.doSomething().delay(dt).trigger('stepDone');
}
function sequenceFinished(o) {
o.trigger('startOver');
}
function checkProgress(o) {
o.on({
'allSetup': function(event) {
console.log(event); //check event
doStep(o, pause);
},
'stepDone': function(event) {
console.log(event); //check event
doStep(o, pause);
},
'startOver': function(event) {
console.log(event); //check event
resetAll(o);
}
});
}
function resetAll(o) {
/*<-
reset stuff here
->*/
//then start over again
setup(o);
}
return this.each(function() {
setup(obj);
checkProgress(obj);
});
};
})(jQuery);
Then i call the animation like this:
$(document).ready(function() {
$('#object').animation();
});
And then – nothing happens. No events get fired. My question: why? Is it not possible to use events like this inside of a jQuery plugin? Do I have to trigger them 'manualy' in $(document).ready() (what I would not prefer, because it would be a completely different thing – controling the animation from outside the plugin. Instead I would like to use the events inside the plugin to have a certain level of 'self-control' inside the plugin).
I feel like I'm missing some fundamental thing about custom events (note: I'm still quite new to this) and how to use them...
Thx for any help.
SOLUTION:
The event handling and triggering actually works, I just had to call the checkProgress function first:
Instead of
return this.each(function() {
setup(obj);
checkProgress(obj);
});
I had to do this:
return this.each(function() {
checkProgress(obj);
setup(obj);
});
So the event listening function has to be called before any event gets triggered, what of course makes perfect sense...
You need set event on your DOM model for instance:
$('#foo').bind('custom', function(event, param1, param2) {
alert('My trigger')
});
$('#foo').on('click', function(){ $(this).trigger('custom');});
You DOM element should know when he should fire your trigger.
Please note that in your plugin you don't call any internal function - ONLY DECLARATION
I currently have a function that looks like this:
$(function(){
$('.chained_to_vehicle_make_selector').remoteChainedTo('.chained_parent_vehicle_make_selector', '/models.json');
$('.chained_to_vehicle_model_selector').remoteChainedTo('.chained_parent_vehicle_model_selector', '/trims.json');
$('.chained_to_vehicle_trim_selector').remoteChainedTo('.chained_parent_vehicle_trim_selector', '/model_years.json');
});
As you can probably tell, each remoteChainedTo function is making an AJAX call, which is working fine, but takes a bit of time.
I then have a second code block:
$(function() {
$(".chzn-select").chosen();
$(".chained_parent_vehicle_make_selector").chosen().change( function() {$(".chained_to_vehicle_make_selector").trigger("liszt:updated"); });
$(".chained_parent_vehicle_model_selector").chosen().change( function() {$(".chained_to_vehicle_model_selector").trigger("liszt:updated"); });
$(".chained_parent_vehicle_trim_selector").chosen().change( function() {$(".chained_to_vehicle_trim_selector").trigger("liszt:updated"); });
$(".chained_child").chosen();
});
This section of the code works fine as long as it fires after the first section is complete. Because of the AJAX calls, however, it is currently firing before the previous section.
How can I implement a structure so that the second code block always fires after the first block is completely done? The remoteChainedTo function does not have a defined callback (that I can see), and in any case it would be impossible to know which of the three calls will finish last, hence wanting to put the callback somehow on the block, so that the second section of code fires only after the last AJAX call completes.
EDIT: After a bit more refactoring, my code now looks as follows:
function makeChains(){
$('.chained_to_vehicle_make_selector').remoteChainedTo('.chained_parent_vehicle_make_selector', '/models.json');
$('.chained_to_vehicle_model_selector').remoteChainedTo('.chained_parent_vehicle_model_selector', '/trims.json');
$('.chained_to_vehicle_trim_selector').remoteChainedTo('.chained_parent_vehicle_trim_selector', '/model_years.json');
}
var chainCall = $(function() {
makeChains();
});
chainCall.done(function() {
$(".chzn-select").chosen();
$(".chained_parent_vehicle_make_selector").chosen().change( function() {$(".chained_to_vehicle_make_selector").trigger("liszt:updated"); });
$(".chained_parent_vehicle_model_selector").chosen().change( function() {$(".chained_to_vehicle_model_selector").trigger("liszt:updated"); });
$(".chained_parent_vehicle_trim_selector").chosen().change( function() {$(".chained_to_vehicle_trim_selector").trigger("liszt:updated"); });
$(".chained_child").chosen();
});
But i'm still getting the error Object [object Object] has no method 'done'. Any hints appreciated.
In Metor 0.3.5, when all events were jQuery events, I was able to use use jQuery UI Draggable and then handle the drag & dragstop events using a Metor event map:
Template.game.events['dragstop .card'] = function (e) {
//stuff
};
But I just read this in the Meteor mailing list:
In 0.3.6, event maps no longer depend on jQuery
And sure enough, the above technique no longer seems to work – my dragstop handler isn't called at all now.
I'd greatly appreciate any advice as to how to achieve the same effect in 0.3.6.
Nowadays, you can simply use body events to accomplish this the "Meteor" way:
Template.body.events({
'dragstop #somedivid': function(e) {
// Do stuff
}
});
Custom jQuery events can be bound with plain old jQuery, bypassing event maps altogether:
$(function () {
$('body').on('dragstop', '.card', function (e) {
//stuff
});
});
Remember to use jQuery's on function to bind the handlers, since template elements are not necessarily included in the DOM at all times.
Element.implement({
addLiveEvent: function(event, selector, fn){
this.addEvent(event, function(e){
var t = $(e.target);
if (!t.match(selector)) return false;
fn.apply(t, [e]);
}.bindWithEvent(this, selector, fn));
}
});
$(document.body).addLiveEvent('click', 'a', function(e){ alert('This is a live event'); });
The above code was done in a similar question to implement .live behaviour in Mootools. I've read the question: Prototype equivalent for jQuery live function.
How do I implement this in Prototype? Probably something that can be implemented like this:
document.liveobserve('click', 'a', function(e){ alert('This is a live event');
Edited to make the question clear.
The simplest (and perhaps not the fastest or best) way would appear to be something like:
Element.live = function(evType, evSelector, evBlock) {
var mySelector = evSelector;
var myBlock = evBlock;
this.observe(evType, function(ev) {
if (ev.target.match(mySelector)) {
evBlock(ev);
}
});
};
The parameters evSelector and evBlock are assigned to local variables so the they are available to the event handler (It's a closure). The passed block evBlock gets passed the event object just like a normal Prototype event handler.
It should be noted this is going to handle every event of type 'evType' so if it's a mouseMove/mouseOver this is going to make your page slow. Also FireBug will probably just go to sleep on you due to the number of events that it has to single step through.
EDIT: Changed as per comments