AngularJS, связать область применения коммутатора?

Чтобы получить контроль над AngularJS, я решил поэкспериментировать с одним из примеров, в частности, просто добавив "полный" экран в пример Todo, когда пользователь вводит 5 задач, он использует переключатель для переключения на другой div, Код доступен здесь http://jsfiddle.net/FWCHU/1/ если он используется.

Тем не менее, похоже, что каждый переключатель имеет свою собственную область ($scope.todoText недоступен), однако к нему можно получить доступ, используя "this" из addTodo() в этом случае. Пока все хорошо, но, скажем, я хочу получить доступ к toText (который находится внутри корпуса переключателя) вне корпуса переключателя, как мне поступить? Могу ли я связать область действия коммутатора с моделью, возможно, она доступна каким-либо другим способом или должна быть решена другим способом?

PS. Я не пытаюсь найти ЛЮБОГО решения для приведенного выше кода, я почти уверен, что знаю, как решить его без использования переключателей, я хочу понять, как работают области в этом случае!

2 ответа

Решение

У Марка есть отличные предложения! Обязательно проверьте расширение AngularJS Batarang Chrome, чтобы увидеть различные области видимости и их значения (среди прочего). Обратите внимание, что он не очень хорошо работает с 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 на внешней области.

Если вы измените код обратно на использование примитива (как в этой скрипке) родительской области видимости todoText не будет отражать любые изменения, которые вы вносите в текстовое поле. Скорее всего, это больше связано с тем, как JavaScript копирует ссылочные значения (см. Этот пост для получения дополнительной информации), а не с AngularJS.

Обновление 2: Теперь, когда я знаю немного больше об AngularJS, вот гораздо лучший ответ.

скажем, я хочу получить доступ к todoText (который находится внутри корпуса коммутатора) вне корпуса коммутатора, как мне поступить?

Родительские области не могут получить доступ к дочерним областям. ( По словам разработчиков Angular, одной из причин такого ограничения является упрощение управления областями памяти.) (Ну, вы могли бы использовать $$childHead и $$childTail для доступа к дочерней области, но вы не должны!)

Могу ли я связать область действия коммутатора с моделью, возможно, она доступна каким-либо другим способом или должна быть решена другим способом?

Существует три распространенных способа доступа к родительской модели из дочерней области:

  1. Сделайте то, что предлагает @Gloopy: создайте объект в родительской области, затем обратитесь к свойствам этого объекта в дочерней области.
  2. Используйте $parent в дочерней области, чтобы получить доступ к родительской области и ее свойствам, даже примитивным свойствам.
  3. Вызовите метод в родительской области

Чтобы преобразовать вашу скрипку в $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());
}

Обновление 1: (зачеркивание добавлено в плохой совет, [] добавлено для ясности)

Для этого сценария, где AngularJS создает дополнительные внутренние области (неявно), и вам не нужен / не нужен другой контроллер, мне нравится решение Gloopy. Служба (то, что я изначально предложил ниже) [неправильный способ сделать это], вероятно, излишняя здесь. Мне также нравится, что решение Gloopy не требует использования "this" в методах контроллера.

Оригинальный ответ: (зачеркивание добавлено к плохому совету, [] добавлено для ясности)

Чтобы увидеть, где создаются области (если вы еще не пробовали, это удобно):

.ng-scope { margin: 4px; border: 1px dashed red }

Чтобы получить доступ к todoText вне корпуса коммутатора (следовательно, вне его области действия), вы по существу спрашиваете о связи между контроллерами, так как задействованы несколько областей. У вас есть несколько вариантов, но сервис, вероятно, лучше. Храните данные (которые должны быть разделены) внутри службы и внедряйте эту службу в каждый контроллер, которому требуется доступ к данным.

В вашем конкретном примере, я думаю, вам нужно подключить контроллер к каждому коммутатору и внедрить в него сервис, чтобы получить доступ к общим данным.

Смотрите также AngularJS: Как я могу передавать переменные между контроллерами?,

Другие варианты:

Использование $scope.$ Parent во внутренней области действия [один из способов сделать это - см. Выше обновление 2] не рекомендуется, так как тогда контроллер будет делать предположения о том, как представлены данные.

Использование $rootScope не рекомендуется, за исключением, может быть, простых одноразовых приложений. Эти общие данные могут начать жить своей собственной жизнью, и $rootScope не место для этого. Сервисы проще использовать, добавлять поведение и т. Д.

Использование $scope.$ Emit - это еще один вариант, но он выглядит грязным и немного странным: генерирование событий для обмена данными (вместо запуска поведения).

[Использование объекта в родительской области видимости, вероятно, лучше всего - см. Ответ @ Gloopy.]

Другие вопросы по тегам