$locationChangeStart event triggers too late - javascript

I have the next problem.
I have different behaviours of <a> elements. I have a controller which handle 2 events:
$scope.$on("$destroy", function () {
console.log("$destroy");
});
$scope.$on("$locationChangeStart", function () {
console.log("$locationChangeStart");
});
Sometimes $locationChangeStart event fired first, but sometimes $destroy event fired first.
I need to prevent changing page, so I need $locationChangeStart to be fired first.
Please, someone has any thoughts, why different <a> have different sequence of events?
UPD
I use the same <a> element in different parts of page
test

If you want to prevent changing page it doesn't matter which one is launch first.
In your $locationChangeStart add the event object:
$scope.$on("$locationChangeStart", function (event) {
event.preventDefault(); // will prevent the location change
});

Related

Best practice to handle big amount of events

im wondering if there is some really good way to handle big amount of JS events. I dont like id-based method - too many id's, bindings and some event need to be fired on several targets, so i need to give them different name and use something like this
$('#some-id').add('#some-id-another').click(...)
or classes. Somewhere i saw a really nice approach
<span data-cmd="menu">Open Menu First link</span>
.....some html
<span data-cmd="menu">Open Menu Second link</span>
<span data-cmd="settings">Setting</span>
<script>
//bind delegated click listeners to body
//get target's data
switch()
case "menu": do smtng
case "setting": do smtng
</script>
Seems very clear smooth and nice. What is the main disadvantages u guys can see? Much slower then id/class?
Try
$(document).on('click', '.menu', function() {
//do something
});
This will create a single click handler on the document that will fire anytime you click on the page. However it will only execute the function if the click originated from an element with the class "menu".
The disadvantage is that every click on the page fires the handler. Shouldn't be an issue with click, but if your event was mouseIn then it would be.
The advantage is a single handler which less of a burden on the browser, certainly say compared to binding up say 500 separate handlers on individual elements.
Another advantage is if you are manipulating the DOM by replacing various sections. If you bind the handlers directly to the element then when replace an element, the handler will be lost. You would need to bind the handler again. Similarly if you add new element you would need to bind the handler at that point. However, if you bind the handler to the document in the onload event then you never have to worry about it again.
With jQuery, I think you have two main solutions to handle a large amount of events and keep your code clean. The good news is that these solutions are not incompatible...
1. Organize your code as a module
var module = {
init: function () {
module.listeners();
},
listeners: function () {
$('#myDiv').mouseover(module.handlers.divHover);
$('button').click(module.handlers.buttonClick);
},
handlers: {
divHover: function () {
console.log('Div hovered!');
},
buttonClick: function () {
console.log('Button clicked!');
}
}
};
$(document).ready(module.init);
2. Use event delegation
In JavaScript, you can use bubbling or capture to handle events. With jQuery, this is pretty straightforward...
Instead of doing this:
$('.btn').click(function () {
console.log('Button clicked!');
});
You could do something like this:
$('body').on('click', '.btn', function () {
console.log('Button clicked!');
});

Disable all actions on elements inside a container

I'm implementing an interactive tutorial for a js-heavy web application. I highlight some container and expect the user to click on some element inside it. At the same time, I want to prevent the user from doing anything else, e.g. clicking on a different link.
The main problem is that I don't want to unbind any events - when the tutorial's closed, the application must work like it did before.
I started with registering a handler on all the containter's descendant elements:
element.on("click.tutorialLock", function(e){
e.stopPropagation();
e.stopImmediatePropagation();
e.preventDefault();
}
Then I set its "priority", so that it executes before any other events:
handlers = element.data("events").click;
our = handlers.pop();
handlers.splice(0, 0, our);
Finally, when I want to unlock some element, I just disable the event on it:
elementToEnable.off(".tutorialLock")
That works, but is very heavy. I tried registering the event only on elements which have some custom event handlers defined, but it omits anchors and other basic elements. Maybe you could come up with some good idea?
I would get the active parent element and pass it into a function which would disable every event other than the events in parent
$('.className').live ('click', function (e)
{
if (!$(this).parents('#targetParent').length))
return false; // same as e.preventDefault() & e.stopPropogation()
});
Hope this is similar to what you want

How to prevent touchend event after dragend?

I'm working on a mobile site and struggling with events firing when I don't want them to.
For the sake of simplicity, it's written something like this (in jQuery):
el.on('touchend', function(ev) {
ev.preventDefault();
// fire an ajax call
};
However, sometimes a user would hit the item when scrolling the page, causing the ajax request to fire (thus changing the page state).
I couldn't think of a way around it (ev.stopPropagation() didn't work) , so I decided watch for dragstart and dragend events.
el.on('dragstart', function() {
el.off('touchend');
});
el.on('dragend', function(ev) {
ev.stopPropagation(); // <-- seems to do nothing
// add back the event above (the function is set to a var)
});
If I alert inside the touchend callback, I get confirmation that the touchend event did in fact fire after I stopped dragging.
Does anyone have any idea how to prevent any other events from firing? I'm hoping I'm just being blind and missing something obvious.
You can't stop an event from firing, you can only prevent the default behavior for that event from happening.
If you're worried about the state of your page changing before the touchend event fires, you should just change your function to check for and then account for the state change.
I think in a case like this you should use event.stopImmediatePropagation();

JavaScript mouseup Event Being Fired Multiple Times On Single Click

Can someone tell me why the javascript code below causes renewSession() to be called 7 times after a single click?
$(document).ready(function () {
$("*").mouseup(function () {
renewSession();
});
});
function renewSession() {
$.ajax({
url: "/Account/RenewSession",
type: "POST"
});
}
Probably it's because the mouseup event propagates up through the DOM tree, and you're applying the handler to every element in the document. So it'll fire on the first element, and then the parent and so on until it gets to the html (or the body, I can never quite remember without checking every time).
You could use:
$(document).ready(function () {
$("*").mouseup(function (e) {
e.stopPropagation();
renewSession();
});
});
To prevent the multiple calls.
Edited to address comment from thiag0:
Thanks for the quick response...what I am trying to do is call renewSession() every time the user clicks on the site to keep the session alive. This solution prevents the renewSession from getting called multiple times in a single click but prevents the actual intent of the user's click from firing. Anyway to get around this?
You could just target the body element; so long as events are allowed to propagate through the DOM tree (so long as you're not calling event.stopPropagation() on elements between the element clicked on (or 'mouseup'-ed) then the event(s) will propagate to the body. So I'd suggest using:
$(document).ready(function () {
$("body").mouseup(function () {
renewSession();
});
});
The * selctor matches 7 elements...
Events in html bubble up the DOM tree, unless explicitly told to stop, and hence the event will be triggered for each element going up the tree that matches the selector (in this case all of them!).
If this is not your intended behaviour either use a more specific selector, or call the stopPropagation method.

Multiple events firing from single action

I have an onclick event attached to a region in my page that causes a certain action to fire when the user clicks in it (naturally). I recently added an image to that region. When the user clicks on that image, I want another action to occur, and I do NOT want the action associated with the entire region to occur. However, I find that both events are, in fact fired when one clicks the image. How do I suppress the region-wide action when the image is clicked?
The issue you are running into is known as event bubbling. The click event of the image bubbles up to all parent elements of that node. You want to cancel bubbling.
The best way to do this that works across all browsers is by using a JavaScript framework. jQuery has a very simple way to do this. Other frameworks have similar mechanisms to cancel bubbling, I just happen to be most familiar with jQuery.
For example, you could do something like this in jQuery:
$('img').click(function () {
// Do some stuff
return false;// <- Cancels bubbling to parent elements.
});
Darit is correct, you need to stop the event from bubbling (propagating):
function imgEventHandler(e) {
// ^notice: pass 'e' (W3C event)
// W3C:
e.stopPropagation();
// IE:
if (window.event) {
window.event.cancelBubble = true;
}
}
In the event handler for the image do
event.cancelBubble = true;
and then at the end do
return false;

Categories

Resources