AngularJS - Доступ к охвату ребенка

Если у меня есть следующие контроллеры:

function parent($scope, service) {
    $scope.a = 'foo';

    $scope.save = function() {
        service.save({
            a:  $scope.a,
            b:  $scope.b
        });
    }
}

function child($scope) {
    $scope.b = 'bar';
}

Какой правильный способ позволить parent читать b из child? Если необходимо определить b в parent, не сделает это семантически неправильным, если предположить, что b является свойством, которое описывает что-то, относящееся к child, а не parent?

Обновление: Если подумать об этом, если более одного ребенка имеет b, он создаст конфликт для parent, на котором b будет извлекаться. Мой вопрос остается, какой правильный способ доступа к b из parent?

Ответ 1

Области в AngularJS используют прототипное наследование, при поиске свойства в области дочерних объектов интерпретатор будет искать цепочку прототипов, начиная с ребенка, и продолжит родителям, пока не найдет свойство, а не наоборот.

Проверьте комментарии Vojta по поводу проблемы https://groups.google.com/d/msg/angular/LDNz_TQQiNE/ygYrSvdI0A0J

Вкратце: вы не можете получить доступ к дочерним областям из родительской области.

Ваши решения:

  • Определить свойства у родителей и получить доступ к ним от детей (прочитайте ссылку выше)
  • Использовать службу для совместного использования состояния
  • Передача данных через события. $emit отправляет события вверх родителям до тех пор, пока область корня и $broadcast не отправит события вниз. Это может помочь вам сохранить вещи семантически правильно.

Ответ 2

В то время как jm-answer - лучший способ справиться с этим случаем, для дальнейшего использования можно получить доступ к дочерним областям с помощью областей $$ childHead, $$ childTail, $$ nextSibling и $$ prevSibling. Они не документированы, поэтому они могут меняться без предварительного уведомления, но они есть, если вам действительно нужно пересекать области.

// get $$childHead first and then iterate that scope $$nextSiblings
for(var cs = scope.$$childHead; cs; cs = cs.$$nextSibling) {
    // cs is child scope
}

Fiddle

Ответ 3

Вы можете попробовать следующее:

$scope.child = {} //declare it in parent controller (scope)

затем в дочернем контроллере (область) добавьте:

var parentScope = $scope.$parent;
parentScope.child = $scope;

Теперь родитель имеет доступ к области содержимого.

Ответ 4

Один возможный обходной путь - это ввести дочерний контроллер в родительский контроллер, используя функцию init.

Возможная реализация:

<div ng-controller="ParentController as parentCtrl">
   ...

    <div ng-controller="ChildController as childCtrl" 
         ng-init="ChildCtrl.init()">
       ...
    </div>
</div>

Где в ChildController у вас есть:

app.controller('ChildController',
    ['$scope', '$rootScope', function ($scope, $rootScope) {
    this.init = function() {
         $scope.parentCtrl.childCtrl = $scope.childCtrl;
         $scope.childCtrl.test = 'aaaa';
    };

}])

Итак, теперь в ParentController вы можете использовать:

app.controller('ParentController',
    ['$scope', '$rootScope', 'service', function ($scope, $rootScope, service) {

    this.save = function() {
        service.save({
            a:  $scope.parentCtrl.ChildCtrl.test
        });
     };

}])

Важно:
Чтобы правильно работать, вам нужно использовать директиву ng-controller и переименовать каждый контроллер с помощью as, как я сделал в html, например.

Советы:
Используйте chrome plugin ng-inspector во время процесса. Это поможет вам понять дерево.

Ответ 5

Да, мы можем назначить переменные из дочернего контроллера переменным родительского контроллера. Это один из возможных способов:

Обзор.. Основная цель приведенного ниже кода - назначить дочернему контроллеру $scope.variable родительскому контроллеру $scope.assign

Объяснение: Есть два контроллера. В html обратите внимание, что родительский контроллер включает дочерний контроллер. Это означает, что родительский контроллер будет выполнен до дочернего контроллера. Итак, первый setValue() будет определен, а затем элемент управления перейдет к дочернему контроллеру. $scope.variable будет назначен как "дочерний". Затем этот дочерний объект будет передан как аргумент функции родительского контроллера, где $scope.assign получит значение как "дочерний"

<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<script type="text/javascript">
    var app = angular.module('myApp',[]);

    app.controller('child',function($scope){
        $scope.variable = "child";
        $scope.$parent.setValue($scope);
    });

    app.controller('parent',function($scope){
        $scope.setValue = function(childscope) {
            $scope.assign = childscope.variable;
        }
    });

</script>
<body ng-app="myApp">
 <div ng-controller="parent">
    <p>this is parent: {{assign}}</p>
    <div ng-controller="child">
        <p>this is {{variable}}</p>
    </div>
 </div>
</body>
</html>

Ответ 6

Я не уверен, должен ли вам "получить" доступ к дочерней сфере от родителя, но это возможно. Я знаю это, потому что я сделал это сам. Вот мой сценарий:

У меня есть функция, которая перемещает мои страницы путем изменения строки внутри переменной. Эта переменная указана в основном файле index.html как ng-include. Итак, когда строка изменяется, в этот ng-include загружается новый html файл. Внутри одного из этих html файлов у меня есть еще один ng-include. Подумайте об этом как о маленьком окне в первом окне. Каждый раз, когда я изменяю содержимое в этих окнах, я также меняю содержимое боковой панели. Эта боковая панель находится на родительском уровне. Но, когда я перехожу в меньшее окно внутри родителя, на боковой панели этого родительского уровня есть навигационные ссылки, которые меняют вещи в маленьком окне. Поскольку боковая панель находится на родительском уровне, а навигация для меньшего окна позаботится в своем собственном контроллере на уровне дочернего уровня, когда я нажимаю ссылки на боковой панели, он должен редактировать дочерний контроллер. Это может быть плохое программирование. Честно говоря, я не знаю. Я только начал с angularjs несколько месяцев назад, и я все еще учусь. Но для того, чтобы он работал для моего сценария, я создал функцию в родительской области, которая вызывается при загрузке детской области:

function parent($scope, service) {
    setCurrentChildController = function (childScope) {
    this.$scope.childScope = childScope;
}
}

function child($scope) {
    scope.$parent.setCurrentChildController($scope);
}

Таким образом, теперь переменная родительской области $scope.childScope по существу является областью детского контроллера. Он имеет доступ ко всем переменным и функциям в пределах дочернего объекта. Если это плохое программирование, и каждый может придумать альтернативное решение проблемы с моим сценарием, это было бы здорово. Но это работает при необходимости.