Как получить двухстороннюю привязку данных в директиве * без * области выделения?

Использование scope: { ... } в директиве вводит область выделения, которая не прототипически наследуется от ее родительской области. Но я всегда использовал его по другой причине: удобный способ объявить атрибуты HTML с двусторонней привязкой данных:

scope: {
    attr1: '=',
    attr2: '?='
}

Чтобы получить неизолированную область видимости, вы должны использовать scope: true, что не дает возможности объявить такие атрибуты. Теперь мне нужна директива с неизолированной областью, но с двухсторонней привязкой. Какой лучший способ достичь этого?


Пример: Мой пример использования выглядит примерно так: в представлении outer-directive:

<div ng-repeat="e in element">
    <inner-directive two-way-attr="e.value"></inner-directive>
</div>

Но inner-directive находится в том же модуле, что и outer-directive. Он не должен быть инкапсулирован с областью изоляции. На самом деле, мне нужно использовать наследование $scope для других целей, поэтому область выделения не является опцией. Это просто, что использование атрибута HTML для установления этой двусторонней связи чрезвычайно удобно.

Ответы

Ответ 1

Ответ на pixelbits помог мне разобраться в этом много времени, но, будучи прямым ответом на мой первоначальный вопрос, кажется слишком сложным. Изучив это, решение действительно довольно просто.

Возьмите директиву с областью выделения, подобной этой:

scope: { model: '=myModel' },
link: function(scope, element, attr) {
    //...
}

Ниже приведен эквивалент, за исключением того, что область не изолирована:

scope: true,
link: function(scope, element, attr) {
    scope.model = scope.$parent.$eval(attr.myModel);
    //...
}

См. рабочий пример здесь: http://jsfiddle.net/mhelvens/SZ55R/1/

Ответ 2

Рабочий демонстрационный пример здесь

В директиве той же возможно иметь как неизолированную область видимости, так и область выделения. Возможно, вы захотите сделать это, например, если у вас есть сочетание неизолированных шаблонов (что означает, что они не должны искать привязки через наследование сферы) и изолированные шаблоны (они должны искать привязки только в своей области) и они оба определены в одной и той же директиве.

Чтобы настроить область выделения и неизолированную область, вы можете сделать следующее:

  • В определении вашей директивы укажите scope=true
  • В вашей функции ссылок скомпилируйте и привяжите шаблон к параметру области. Когда вы это делаете, привязки оцениваются с помощью неизолированной области (что означает, что она разрешает привязки через наследование прототипа).

      link: function(scope, element, attr) {
    
        // this template should look for 'model' using scope inheritance
        var template2 = angular.element('<div> Prototypical Scope: {{ model }}</div>');
    
        // add the template to the DOM
        element.append(template2);
    
        // compile and link the template against the prototypical scope
        $compile(template2)(scope);
      }
    

    Преимущество прототипического наследования объектов заключается в том, что вам не нужно явно импортировать привязки в текущую область ваших директив. Пока он определен в текущей области действия или в какой-либо области выше цепочки наследования (вплоть до корневой области), время выполнения angular сможет ее разрешить.

  • В той же функции ссылок определите изолированную область с помощью scope.$new(true). Вы можете установить двустороннюю привязку своей модели, импортировав модель в свою изолированную область - isolatedScope.model = scope.$eval(attr.model):

     link: function(scope, element, attr) {
    
        // this template should look for 'model' in the current isolated scope only
        var template = angular.element('<div>Isolate Scope: {{model}}</div>');
    
        // create an isolate scope
        var isolatedScope = scope.$new(true);
    
        // import the model from the parent scope into your isolated scope. This establishes the two-way binding.            
        isolatedScope.model = scope.$eval(attr.model);
    
        // add the template to the DOM
        element.append(template);
    
        // compile and link the template against the isolate scope
        $compile(template)(isolatedScope);
    
    }
    

    Преимущество области изоляции заключается в том, что любые привязки, которые существуют (т.е. находятся в области видимости), являются теми, которые вы явно импортируете. Контрастируйте это с неизолированной областью - там, где привязки не должны быть явно определены в текущей области действия - она ​​может быть унаследована от любой области действия выше цепочки.

Ответ 3

Я написал это. Вы используете его следующим образом:

twowaybinder.attach($scope, $attrs.isDeactivated, 'isDeactivated');

.factory('twowaybinder', function ($parse) {
  function twoWayBind($scope, remote, local){
    var remoteSetter = $parse(remote).assign;
    var localSetter = $parse(local).assign;

    $scope.$parent.$watch(remote, function (value) {
      localSetter($scope, value);
    });

    $scope.$watch(local, function (value) {
      remoteSetter($scope, value);
    });
  }

  return {
    attach : twoWayBind
  };
});

Это даст истинную двустороннюю привязку из значений области. Примечание. Я не считаю, что $scope. $Parent необходим, как в унаследованном или без видимого сценария, какое-либо выражение должно разрешаться в текущей области. Вам нужно будет только вызывать $parent в изолированной области, в этом случае вы не использовали бы это, вы бы использовали изолированную конфигурацию области.

Ответ 4

вы можете использовать две директивы если gg - объект, то "=" указывает на одно место памяти!

angular.module('mymodule', []).directive('a', function($parse, $modal) {
return {
    restrict : 'A',
    scope : {
        gg : "="
    },
    require : "b",
    link : function(scope, element, attrs, bCtrl) {
        scope.$watch('gg',function(gg){
            bCtrl.setset(scope.gg);
        }
    }
}
});

angular.module('mymodule').directive('b', function($parse, $modal) {

return {
    restrict : 'A',
    /*
     * scope : { showWarn : "=" },
     */
    controller : function($scope) {
        $scope.bb = {};

        this.setset = function(nn) {

            $scope.bb=nn;
        };

    }
});