Angular - Следите за изменениями ngShow/ngHide в предках, которые влияют на детскую видимость элементов DOM
Я элемент DOM (привязанный, скажем, к таблице). Я являюсь дочерним элементом элемента управления вкладками ngShow. Я живу на второй вкладке. Когда страница визуализируется, я существую, но я пока не видим.
Я хотел бы как-то быть уведомленным, когда я становлюсь видимым через моего не-непосредственного родителя, когда его выражение ngShow станет истинным.
Возможно ли это? Я хотел бы избежать добавления кода вне себя - например, я бы предпочел не добавлять код в событие с измененной вкладкой. Я бы предпочел, чтобы зарегистрироваться, чтобы узнать, когда с помощью изменений в самых внешних контейнерах, которые связаны через ngShow/ngHide, моя видимость меняется. Это можно сделать?
Ответы
Ответ 1
Поскольку у вас есть область действия, доступная в директиве, вы можете использовать ее для просмотра изменений видимости:
scope.$watch(function() { return element.is(':visible') }, function() {
// Do whatever should happen when the visibility changes
});
Это позволяет избежать опроса видимости, которая может быть результативной. Конечно, это предполагает, что область применения применяется по каким-либо причинам видимости для изменения. Я пробовал это в своей собственной директиве, но не связан с ngShow/ngHide.
Кредит, на который рассчитывается кредит: это было изначально предложено (не мной):
https://groups.google.com/d/msg/angular/w7Gxa5M_17M/koYCZnsobawJ
EDIT 2014-02-24
Повторяя этот ответ на несколько месяцев, я заметил, что это работает, но немного замедлит ваш цикл дайджеста. Лучшая практика заключается в том, чтобы не использовать дорогие функции, например, для грязной проверки. Используйте с осторожностью!
Ответ 2
Лучший способ найти:
link: function (scope, element, attr) {
attr.$observe('ngShow', function (expr) {
scope.$watch(function () {
return $parse(expr)(scope);
}, function (value) {
console.log(value)
})
});
}
Удачи!
Ответ 3
Единственное, что я могу придумать, это создать директиву, которая будет видеть, является ли элемент видимым. Что-то вроде:
angular.module('testModule', [])
.directive('onVisible', ['$timeout', function($timeout) {
return {
restrict: 'A',
scope: {
onVisible: '&'
},
link: function(scope, element, attrs) {
var checkVisibility = function() {
if (element.is(':visible')) {
scope.onVisible();
} else {
$timeout(checkVisibility, 100);
}
};
$timeout(checkVisibility, 100);
}
};
}]);
Конечно, если вам нужно, чтобы он выполнялся каждый раз, когда элемент становится видимым, вам также нужно будет следить за тем, чтобы элемент переходил обратно в скрытое.
Изменить. Это предполагает, что у вас есть jQuery.
Ответ 4
Я сделал это с директивой:
Elemement:
<test-directive ng-show="showMe" show-model="showMe"></test-directive>
Директива
app.directive('testDirective', function() {
return {
restrict: 'E',
scope: {
showModel: "=?",
},
controller: function($scope) {
if (angular.isDefined($scope.showModel)) {
$scope.$watch('showModel', function(newValue, oldValue) {
// Do stuff
});
}
}
}
});
Итак, идея состоит в том, чтобы поставить $watch на ту же переменную, связанную с ng-show.
Ответ 5
Другим возможным способом может быть использование $broadcast. Когда выбран вкладка, вы можете транслировать событие
$scope.$broadcast('secondTabSelected');
Вы можете обрабатывать это событие внутри своего контроллера и выполнять дальнейшую обработку.
$scope.$on('secondTabSelected', function(e){
// do something awesome.
})
Это будет уведомлять вас каждый раз, когда вкладка видна. Чтобы выполнить его только один раз, вы можете сделать
var firstTimeSelected = false;
$scope.$on('secondTabSelected', function(e){
if(firstTimeSelected){
firstTimeSelected = true;
// do something awesome
}
})