Я связываю переменную в директиве следующим образом:
<path-filter-modal is-opened="filterModalIsOpened">
И в директиве я использую привязку '=' следующим образом:
scope: {
isOpened: '='
}
Когда я изменяю переменную в директиве, родительская область содержит собственное значение. Как я могу сделать, чтобы родительская область содержала одно и то же значение?
Для объектов он работает хорошо, но не с строками и булевыми. Обратите внимание, что я использую контроллер, определенный в моей директиве в моей директиве, чтобы изменить значения.
Потому что JavaScript разработан так.
Определение области выделения в директиве создает новый объект $scope
, который является отдельным объектом $scope
. Его единственная связь с родительской областью заключается в том, что: $isolateScope.$parent === $parentScope
. Он не наследует от $parentScope
прототипа.
Когда вы назначаете некоторый примитивный тип (string/boolean) на $scope.isOpened
, на самом деле механизм JavaScript создаст новую переменную isOpened
on $scope
. Он полностью не связан с $parentScope.isOpened
.
Но теперь Angular синхронизирует две переменные для вас неявно. Так что связывание примитивных переменных по-прежнему делает работу с two-way binding
хорошо. Проверьте JSFiddle.
Если вы привязываетесь к некоторому типу объекта, область содержимого и родительская область ребенка ссылаются на точно такую же копию объекта в памяти. Изменение в родительской области автоматически изменит область дочернего элемента. Поэтому для привязки объектов, а не примитивных типов, всегда рекомендуется привязка в two-way binding
.
Проверьте этот JSFiddle. Я связываю примитив и объект с директивой myDirective
. Затем измените их внутри функции link
:
scope.primitiveParam = 'primitive from directive';
// $parent.primitive and primitiveParam refer to different memory;
// Angular is responsible to sync them.
console.log(scope.$parent.primitive);
console.log(scope.primitiveParam);
scope.objectParam.name = 'object from directive';
// $parent.obj and objectParam refer to an identical object
console.log(scope.$parent.obj.name);
console.log(scope.objectParam.name);
console.log(scope.objectParam === scope.$parent.obj);
И результат подобен:
primitive from parent
primitive from directive
object from directive
object from directive
Для получения дополнительной информации: Понимание областей (здесь представлено множество интуитивных изображений, четко иллюстрирующих концепции)
RE: Для объектов он работает хорошо, но не с строками и булерами
Я думаю, что это обычный случай проблемы прототипного наследования. Когда модель исходит из объекта, она работает хорошо, но если она исходит из не-объектов, существует вероятность того, что ng-модель будет создана в дочерней области.
Чтобы решить эту проблему, используйте современный подход, используйте Controller as
подхода. Или поставьте filterModelIsOpened в объекте. Первый подход лучше.
<div ng-controller="SomeController as s">
<path-filter-modal is-opened="s.filterModalIsOpened">
</div>
function SomeController() { // no need to use $scope
this.filterModalIsOpened = false;
}
Или, если вы используете более старую версию Angular, вы не можете использовать Controller as
подхода. Просто создайте свой собственный псевдоним в контроллере:
<div ng-controller="SomeController">
<path-filter-modal is-opened="s.filterModalIsOpened">
</div>
function SomeController($scope) {
$scope["s"] = this;
this.filterModalIsOpened = false;
}
Здесь хорошая статья, объясняющая прототипное наследование: http://codetunnel.io/angularjs-controller-as-or-scope/
Вот демо, почему вы всегда должны префикс вашей модели, будь то объект или примитив.
Не рекомендуется. Демо-версия Live-кода: http://jsfiddle.net/hdks813z/1/
<div ng-app="App" ng-controller="Ctrl">
<div ng-if="true">
<input type="checkbox" ng-model="filterModalCanBeOpened"/>
<the-directive primitive-param="filterModalCanBeOpened"></the-directive>
</div>
<hr/>
<p>
The value below doesn't react to changes in primitive(non-object) property
that is created a copy on a directive(e.g., ng-repeat, ng-if) that creates
child scope
</p>
$scope.primitive: {{filterModalCanBeOpened}}
</div>
angular.module('App', [])
.directive('theDirective', function () {
return {
restrict: 'AE',
scope: {
primitiveParam: '='
},
template: '<div>primitiveParam from directive: {{ primitiveParam }}; </div>',
link: function (scope) {
}
};
})
.controller('Ctrl', ['$scope', function ($scope) {
$scope.filterModalCanBeOpened = true;
}]);
Рекомендуем: Демо-версия живого кода: http://jsfiddle.net/2rpv27kt/
<div ng-app="App" ng-controller="Ctrl as c">
<div ng-if="true">
<input type="checkbox" ng-model="c.filterModalCanBeOpened"/>
<the-directive primitive-param="c.filterModalCanBeOpened"></the-directive>
</div>
<hr/>
<p>
The value below react to changes in primitive(non-object) property that is
addressed directly by its alias c, creating child scope on it would be
impossible. So the primitive below react to changes on
the c filterModalCanBeOpened.
</p>
c.primitive: {{c.filterModalCanBeOpened}}
</div>
angular.module('App', [])
.directive('theDirective', function () {
return {
restrict: 'AE',
scope: {
primitiveParam: '='
},
template: '<div>primitiveParam from directive: {{ primitiveParam }}; </div>',
link: function (scope) {
}
};
})
.controller('Ctrl', [function () {
this.filterModalCanBeOpened = true;
}]);
=
должно работать .. пожалуйста, прикрепите скрипку / планкр