On route reload, new directives bind before old ones unbind
Looks like when angular does a route reload, it loads the new template alongside the old one, so if I have the same hotkey defined in multiple templates, the new template will bind before the old template unbinds and I will lose the hotkey.
The order in which things run ends up being:
- angular route $reload
- new template loaded, directive processed, hotkey added/bound
- old template unloaded, $destroy fired, hotkey removed/unbound
I was able to work around this by marking my hotkeys as persistent: false and not removing them on $destroy (as the new ones have bound at that point) and instead manually calling purgeHotkeys() before I do the route reload, though a better solution might be to delay hotkey binding in the directive until $routeChangeSuccess or something, not exactly sure.
This problem is also present when declaring the hotkeys in the controller, since the new controller is processed before the old controller is destroyed.
We're using angular v1.2.9 if that matters, though I don't think this new behavior in ngRoute
Cool find. I'll confirm via tests and take a look
I'm assuming this only affects hotkeys created via directives, correct?
I'm not sure if I'm having the same issue or not - I have the same hotkey defined on multiple scopes (same controller, loaded multiple times on the page), it all works until I destroy one of the scopes - then they all stop working.
scope.$on('$destroy', function () {
var i = boundScopes[scope.$id].length;
while (i--) {
_del(boundScopes[scope.$id][i]);
delete boundScopes[scope.$id][i];
}
});
if I remove this part of the code, it stops breaking, so I'm assuming it's a problem in the _del function.
FWIW, I'm not using it as a directive, just call hotkeys.bindTo($scope).add(....) in my controller.
I added a try/catch block around the offending code in the _del function in hotkeys. The below is my code. Would be cool if this gets fixed or at least the below workaround is added to hotkeys master branch.
function _del (hotkey) {
var combo = (hotkey instanceof Hotkey) ? hotkey.combo : hotkey;
Mousetrap.unbind(combo);
if (angular.isArray(combo)) {
var retStatus = true;
var i = combo.length;
while (i--) {
retStatus = _del(combo[i]) && retStatus;
}
return retStatus;
} else {
var index = scope.hotkeys.indexOf(_get(combo));
if (index > -1) {
// if the combo has other combos bound, don't unbind the whole thing, just the one combo:
if (scope.hotkeys[index].combo.length > 1) {
scope.hotkeys[index].combo.splice(scope.hotkeys[index].combo.indexOf(combo), 1);
} else {
// remove hotkey from bound scopes
angular.forEach(boundScopes, function (boundScope) {
try { //Added by traviskds
var scopeIndex = boundScope.indexOf(scope.hotkeys[index]);
if (scopeIndex !== -1) {
boundScope.splice(scopeIndex, 1);
}
} catch (e) {} //Added by traviskds
});
scope.hotkeys.splice(index, 1);
}
return true;
}
}
return false;
}