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 для доступа к дочерней области, но вы не должны!)
Могу ли я связать область действия коммутатора с моделью, возможно, она доступна каким-либо другим способом или должна быть решена другим способом?
Существует три распространенных способа доступа к родительской модели из дочерней области:
- Сделайте то, что предлагает @Gloopy: создайте объект в родительской области, затем обратитесь к свойствам этого объекта в дочерней области.
- Используйте $parent в дочерней области, чтобы получить доступ к родительской области и ее свойствам, даже примитивным свойствам.
- Вызовите метод в родительской области
Чтобы преобразовать вашу скрипку в $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.]