AngularJS, привязать область действия коммутатора?
Чтобы захватить AngularJS, я решил поиграть с одним из примеров, в частности, просто добавив "полный" экран в пример Todo, когда пользователь ввел 5 todos, он использует коммутационный футляр для переключения к другому div. Код доступен здесь http://jsfiddle.net/FWCHU/1/, если он используется.
Однако, похоже, что каждый случай-коммутатор получает свою собственную область ($ scope.todoText недоступен), однако в этом случае он может быть доступен с помощью "this" из addTodo(). Пока все хорошо, но скажу, что я хочу получить доступ к todoText (который находится внутри коммутационного футляра) за пределами коммутационного футляра, как бы я это сделал? Могу ли я связать сферу действия переключателя с моделью, возможно, она доступна каким-то другим способом или это должно быть разрешено каким-то другим способом?
PS. Я не, пытаясь найти ЛЮБОЕ решение для вышеприведенного кода, я уверен, что знаю, как его решить, не используя коммутационные шкафы, я хочу понять, как работают в этом случае области действия!
Ответы
Ответ 1
У Марка есть отличные предложения! Убедитесь, что вы также просмотрите AngularJS Batarang Chrome Extension, чтобы увидеть различные области и их ценности (среди прочего). Обратите внимание, что это не работает с jsFiddle.
Я не уверен, как напрямую обращаться к внутренним областям, но вот один из способов получить доступ к одному и тому же тексту во внешней области, связывая его с объектом вместо примитива.
1) Объявите todoText
как объект вместо примитива в вашем контроллере:
$scope.todoText = {text: ''};
2) Привяжите к todoText.text
вместо todoText
:
<form ng-submit="addTodo()">
<input type="text" ng-model="todoText.text" size="30" placeholder="add new todo here">
<input class="btn-primary" type="submit" value="add">
</form>
3) Измените существующие функции для использования todoText.text
:
$scope.addTodo = function() {
$scope.todos.push({text:$scope.todoText.text, done:false, width: Math.floor(Math.random() * 100) + 50});
$scope.todoText.text = '';
};
Взгляните на эту скрипту и обратите внимание, что текст, отображаемый под текстовым полем при вводе чего-либо, обращается к todoText.text
on внешний охват.
Если вы измените код на использование примитива (например, эта скрипта) родительская область todoText
не будет отображать изменения, внесенные в текстовое поле. Скорее всего, это больше связано с тем, как JavaScript копирует ссылочные значения (см. этот пост для получения дополнительной информации) и менее специфическая вещь AngularJS.
Ответ 2
Update2: Теперь, когда я знаю немного больше об AngularJS, здесь гораздо лучший ответ.
Скажем, я хочу получить доступ к todoText (который находится внутри коммутационного футляра) вне ящика коммутатора, как бы я это сделал?
Для родительских областей нет возможности доступа к дочерним областям. (Одна из причин этого ограничения, в соответствии с Angular разработчиками, упрощает управление памятью областей.) (Ну, вы могли бы использовать $$ childHead и $$ childTail для доступа к охвату пользователя, но вы не должны!)
Могу ли я связать сферу действия переключателя с моделью, возможно, это доступным каким-либо другим способом или если это будет разрешено в некоторых других способ?
Существует три общих способа доступа к родительской модели из области содержимого:
- Сделайте то, что предлагает @Gloopy: создайте объект в родительской области, затем обратитесь к свойствам этого объекта в области содержимого.
- Используйте $parent в области child для доступа к родительской области и ее свойствам, даже примитивным свойствам.
- Вызов метода в родительской области
Чтобы преобразовать вашу скрипту в использование $parent:
<input type="text" ng-model="$parent.todoText" ...
$scope.addTodo = function() {
$scope.todos.push({text: $scope.todoText, ...
$scope.todoText = '';
Как я уже упоминал в комментариях к ответу Gloopy, ng-repeat и ng-switch имеют новую прототипную дочернюю область с родительской областью. ng-repeat также копирует переменную/элемент цикла в новую дочернюю область (и применяются нюансы, которые @Gloopy описывает с примитивами против объекта). ng-switch ничего не копирует из родительской области.
Чтобы увидеть, как выглядит внутренняя/дочерняя область, добавьте следующее после ng-switch-when:
<a ng-click="showScope($event)">show scope</a>
и добавьте это в свой контроллер:
$scope.showScope = function(e) {
console.log(angular.element(e.srcElement).scope());
}
Update1: (добавлены зачеркнутые советы, [] добавлены для ясности)
Для этого сценария, где AngularJS создает дополнительные внутренние области (неявно), и вам действительно не нужен/нужен другой контроллер, мне нравится решение Gloopy. Служба (то, что я изначально предлагал ниже) - это [неправильный способ сделать это] , вероятно, переполняет здесь. Мне также нравится, что решение Gloopy не требует использования 'this' в методах контроллера.
Оригинальный ответ: (добавлены зачеркнутые советы, [] добавлены для ясности)
Чтобы узнать, где создаются области действия (если вы еще не пробовали это, это удобно):
.ng-scope { margin: 4px; border: 1px dashed red }
Чтобы получить доступ к todoText за пределами корпуса коммутатора (следовательно, вне его области действия), вы, по сути, задаете вопрос о связи между контроллерами, поскольку задействованы несколько областей. У вас есть несколько вариантов, но сервис, вероятно, лучше всего. Храните данные (которые должны использоваться совместно) внутри службы и внедряйте эту службу в каждый контроллер, которому необходим доступ к данным.
В вашем конкретном примере, я думаю, вам нужно будет подключить контроллер к каждому коммутатору и ввести в него службу, чтобы получить доступ к общим данным.
См. также AngularJS: Как передать переменные между контроллерами?.
Другие параметры:
Использование $scope. $parent во внутренней области - это [один способ сделать это - см. Update2 выше] не рекомендуется, так как тогда контроллер будет делать предположения о том, как данные будут представлены.
Использование $rootScope не рекомендуется, за исключением, может быть, простых, одноразовых приложений. Эти общие данные могут начать принимать свою собственную жизнь, а $rootScope - это не тот случай, когда это произойдет. Сервисы легче использовать, добавлять поведение и т.д.
Использование $scope. $emit - это еще один вариант, но он кажется беспорядочным и немного странным: испускание событий для обмена данными (вместо запуска поведения).
[Использование объекта в родительской области, вероятно, лучше всего - см. ответ @Gloopy.]