AngularJS: отвязывание обработчиков и рассуждение об опасностях использования вложенных контроллеров
В нашем приложении (чего уж тут скрывать — http://m.mamba.ru, тач-версия) всё построено на встроенных в angular маршрутах.
При этом, как известно, шаблон страницы отрисовывается внутри тега ng-view.
Появилось несколько страниц, на которых внутри контента (это важно) нужно показывать баннер.
Сделал я это так:
внутри списка пользователей в html:
<div ng-switch="$index"> <div class="b-content__iframe" ng-controller="BannerMiddleCtrl" ng-switch-when="4"> <inline-ad frame-src-base="http://mamba.ru/be.phtml" position="91" show-ad="showAd"></inline-ad> </div> </div>
в контроллерах:
controller('BannerMiddleCtrl', ['$scope', '$rootScope', function BannerMiddleCtrl($scope, $rootScope) {
$rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
setCanShowAd();
});
$rootScope.$watch('showPopupTip + controllerDataLoaded + controllerDataLoadError + routeError + hidePageForPopup', function () {
setCanShowAd();
});
function setCanShowAd()
{
$scope.showAd = canShowAd();
$rootScope.middleAdShown = $scope.showAd;
}
function canShowAd()
{
if (<сложное бизнес-условие>) {
return true;
}
return false;
}
}]).
И заметил я, что после показа страницы, на которой используется этот контроллер, функция setCanShowAd() продолжает вызываться и на других страницах. И ещё забавнее, что вызываться она будет несколько раз, если несколько раз зайти на эту страницу.
Что, в общем-то, логично, хотя и печально. Получается, что AngularJS сам не снимает обработчики событий для таких контроллеров (возможно, и для обычных контроллеров тоже), что, наверное можно объяснить и идеологическими соображениями и сложностью реализации.
Поэтому родилась следующая идея (не без помощи http://stackoverflow.com/questions/14957614/angular-js-clear-watch).
angular.module('CommonControllers', []).
value('BannerMiddleCtrlWatchers', {}).
controller('BannerMiddleCtrl', ['$scope', '$rootScope', function BannerMiddleCtrl($scope, $rootScope) {
BannerMiddleCtrlWatchers.rsOnUnbind = $rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
setCanShowAd();
});
BannerMiddleCtrlWatchers.rsWatchUnbind = $rootScope.$watch('showPopupTip + controllerDataLoaded + controllerDataLoadError + routeError + hidePageForPopup', function () {
setCanShowAd();
});
function setCanShowAd()
{
$scope.showAd = canShowAd();
$rootScope.middleAdShown = $scope.showAd;
}
function canShowAd()
{
if (<сложное бизнес-условие>) {
return true;
}
return false;
}
}]).
app.js
app.run(['$rootScope', 'BannerMiddleCtrlWatchers', function($rootScope, BannerMiddleCtrlWatchers) {
$rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
BannerMiddleCtrlWatchers.rsOnUnbind && BannerMiddleCtrlWatchers.rsOnUnbind();
BannerMiddleCtrlWatchers.rsWatchUnbind && BannerMiddleCtrlWatchers.rsWatchUnbind();
});
Идея в том, чтобы отвязывать обработчики событий на rootScope.
О том, как сделать правильно — в следующем выпуске :)
LEAVE A COMMENT
Для отправки комментария вам необходимо авторизоваться.