Наследование контроллера AngularJS
У AngularJS есть наследование контроллера на основе DOM, как указано в документах angular.
<div ng-controller="BaseController">
<p>Base Controller Value: {{value}}</p>
<button ng-click="updateValue()">Update In Base</button>
<div ng-controller="DerivedController">
<p>Derived Controller Value: {{value}}</p>
<button ng-click="updateValue()">Update In Derived</button>
</div>
</div>
Значение переменной "значение" присутствует только в BaseController. Исходя из этого, изменяя значение в методе в BaseController или DerivedController, я хочу, чтобы оба значения нужно было обновить. Но обновляется только отдельная переменная области.
Вот скрипка, демонстрирующая тот же пример: http://jsfiddle.net/6df6S/1/
Как можно изменить изменения на уровне для непосредственного дочернего элемента и непосредственного родителя текущей области.
Мы можем реализовать это, используя
$сфера. $Смотреть
Есть ли способ сделать это, не используя его или таких наблюдателей?
Изменить 1:
Используя $scope. $watch, вот что я имел в виду
$scope.$watch("value", function () {
$scope.$broadcast("childChangeListener"); //Downwards to all children scopes
$scope.$emit("parentChangeListener"); //Upwards to all parent scopes
});
Я искал способы, в которых значение будет обновляться во всех областях без использования такого механизма.
Ответы
Ответ 1
Когда нескольким контроллерам нужен доступ к тем же данным, следует использовать service. Вы не должны полагаться на наследование области, так как ограничивают, как вы можете писать свой HTML. Например, в будущем вы решили, что DerivedController не должен быть дочерним элементом BaseController.
Ваша служба должна обычно предоставлять публичный API и скрывать реализацию. Это облегчает реорганизацию внутренних компонентов.
HTML:
<div ng-controller="BaseController">
<p>Base Controller Value: {{model.getValue()}}</p>
<button ng-click="model.updateValue('Value updated from Base')">Update In Base</button>
<div ng-controller="DerivedController">
<p>Derived Controller Value: {{model.getValue()}}</p>
<button ng-click="model.updateValue('Value updated from Derived')">Update In Derived</button>
</div>
</div>
JavaScript:
app.factory('sharedModel', function () {
// private stuff
var model = {
value: "initial Value"
};
// public API
return {
getValue: function() {
return model.value;
},
updateValue: function(value) {
model.value = value;
}
};
});
function BaseController($scope, sharedModel) {
$scope.model = sharedModel;
}
function DerivedController($scope, sharedModel) {
$scope.model = sharedModel;
}
Fiddle.
Кроме того, я не рекомендую использовать $rootScope для совместного использования между контроллерами.
Ответ 2
Связывание в вашей скрипке напрямую зависит от свойства. Наследование, которое вам нужно, может быть достигнуто за счет привязки данных к объекту в области.
http://jsfiddle.net/2Dtyq/
scope.shared = {}
scope.shared.value = "Something"
Вместо просто
scope.value= "Something"
Что происходит?
В то время как DerivedController сконструирован, объем, передаваемый прототипом, наследуется от области BaseController.
Объект объекта DerivedController по-прежнему не имеет собственного свойства, называемого" значение". Поэтому он по-прежнему привязывается к свойству, полученному от родительской области.
Теперь, если вы нажмете кнопку Обновить в базе, она будет отображаться в обеих привязках.
Когда вы нажмете кнопку Обновить в производной, в области DerviedController будет создано новое свойство с именем "значение". Поэтому привязка к свойству родительского значения нарушена. Все больше кликов по Обновить в базе не обновляет вторую привязку данных.
Помещение его в отдельный объект запрещает создание нового свойства, поэтому наследование сохраняется.
Ответ 3
Вы не можете напрямую ссылаться на строковое значение в дочернем контроллере. Из-за установки прототипного наследования свойство value
в дочерней области (которое создается при использовании дочернего контроллера) создает это свойство в области дочернего элемента, а не обновляет свойство родительской области.
Ваша область применения не является моделью, поэтому мы должны избегать загрязнения переменной $scope
множеством свойств. Создайте объект модели и создайте на нем дополнительные свойства. Затем этот объект можно передать вдоль дочерних контроллеров \scope.
Я изменил ваш jsfiddle, чтобы объяснить вышеприведенную точку.
Также я настоятельно рекомендую вам пройти эту страницу wiki, чтобы понять неприятности прототипного наследования.
Ответ 4
взгляните на метод $broadcast: $broadcast
Из документации:
Отправляет имя события вниз во все дочерние области (и их дети), уведомляющие зарегистрированных пользователей. $rootScope.Scope # $на слушателях.
Ответ 5
Используйте объекты вместо использования примитивного значения. В вашем случае определите объект, подобный этому
$scope.obj = {"value":"base"};
и попробуйте (obj.value). это будет работать.
Ответ 6
Это происходит из-за того, что ngController создает новую область $scope, а ссылка для значения - не то же самое.
Вы можете решить это, используя свойство $parent
, подобное этому:
<div ng-controller="BaseController">
<p>Base Controller Value: {{value}}</p>
<div ng-controller="DerivedController">
<p>Derived Controller Value: {{$parent.value}}</p>
</div>
</div>
И в DerivedController вы можете использовать что-то вроде этого: $scope.$parent.value
Но лучший способ реализовать это, чтобы использовать синтаксис controllerAs
.
<div ng-controller="BaseController as BaseController ">
<p>Base Controller Value: {{BaseController.value}}</p>
<div ng-controller="DerivedController">
<p>Derived Controller Value: {{BaseController.value}}</p>
</div>
И в DerivedController вы можете использовать что-то вроде этого: $scope.BaseController.value
Это дает читателю более читабельность, потому что вы знаете, что такое контроллер, на который вы ссылаетесь.
Подробнее об этом в ngController Docs или Копаем в Angular s "контроллер как" от ToddMotto