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.]