Как автоматически передавать строковые и bool переменные в родительскую область директивы

0

Я связываю переменную в директиве следующим образом:

<path-filter-modal is-opened="filterModalIsOpened">

И в директиве я использую привязку '=' следующим образом:

scope: {
   isOpened: '='
}

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

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

  • 0
    У вас есть образец jsFiddle проблемы?
  • 0
    = должно работать .. пожалуйста, прикрепите скрипку / планкр
Показать ещё 4 комментария
Теги:
scope
bind

2 ответа

1
Лучший ответ

Потому что 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

Для получения дополнительной информации: Понимание областей (здесь представлено множество интуитивных изображений, четко иллюстрирующих концепции)

  • 0
    Это то, что я тоже думал, но люди выше говорят мне, что для строк и bools это должно работать тоже.
  • 1
    Хорошо, я понимаю, в чем проблема, но вы не правы. Директива изолированного объема принимает значения непосредственно не из прототипа. Он принимает объекты по ссылке.
Показать ещё 5 комментариев
1

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;
}]);
  • 0
    Обновил мой вопрос. Я должен к контролерам. Первый - это контроллер маршрута, а другой определяется в директиве. Так что в моем случае у меня такая же реализация, кроме места реализации контроллера. Итак, я думаю, что это правильное угловое поведение, не так ли? (родительский контроллер маршрута не принимает значения bool и string)
  • 0
    «Я думаю, что это обычный случай проблемы наследования прототипа». Это не так, изолированная область берет объекты непосредственно от родителя по ссылке. Вот почему я получаю неизмененные значения.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню