AngularJS:指示指令的范围

时间:2014-07-10 12:34:49

标签: javascript angularjs angularjs-directive angularjs-scope

我正在构建一个可以在不同控制器中使用的指令,我希望能够将指令绑定到我的$scope的特定属性。

我想做这样的事情:

<div ng-app="myapp">
    <div ng-controller="myController">
        <my-directive-wrapper ng-model="mymodel">
            <my-directive-inner ng-repeat="item in items" />
        </my-directive-wrapper>
    </div>
</div>

使用这个模型:

$scope.mymodel = { 
    name : "Transclude test",
    items : [
        { title : "test1" },
        { title : "test2" },
        { title : "test3" }
    ]
};

因此指令myDirectiveWrapper$scope.mymodel作为范围,而不是其他任何内容。然后我可以将指令放两次,指向不同的属性。

我有一个带有问题的演示项目:http://jsfiddle.net/vtortola/P8JMm/3/

同样的演示工作正常(不限制范围):http://jsfiddle.net/vtortola/P8JMm

问题是,如何在使用我的指令时表明我想使用我的$scope的特定属性作为我的指令的范围。应该可以将指令绑定到同一$scope中的任意属性。

干杯。

2 个答案:

答案 0 :(得分:2)

所以这个问题的基本答案是 - 你可以做你想做的事,但它比你想象的要复杂一些。要了解这里发生的事情,您需要了解角度范围。范围本质上是一个包含视图可访问数据的对象。有(至少)三种范围以角度运行的方式:

  • 隔离 - 在这种情况下,angular基本上为指令创建了一个全新的范围。没有任何属性被复制。
  • 扩展 - 在这种情况下,您将从根范围开始,但要对其进行浅层复制。更改的对象将在根范围中更改,但原语不会更改。
  • 共享 - 在这种情况下,您可以与根范围共享部分甚至全部数据。

根据您的上述问题,您在此处要做的是扩展父作用域 - 将对象复制到新创建的子作用域中具有特定名称的属性。获得此行为的方法是在转换之前手动创建新的子范围。执行此操作的两个关键代码行是:

// create a "new" scope
var childScope = scope.$new();

// extend using the model binding provided
angular.extend(childScope, scope[iAttr.myModel]);

在您的指令的上下文中,这看起来像:

.directive('myDirectiveWrapper', ['$compile', function ($compile) {
   return {
        transclude: true,
        restrict: 'E',
        compile: function (element, attrs, transclude) {
            var contents = element.contents().remove();
            var compiledContents;
            return function(scope, iElement, iAttr) {
               var childScope = scope.$new();
               angular.extend(childScope, scope[iAttr.myModel]);
                if (!compiledContents) {
                    compiledContents = $compile(contents, transclude);
                }
                compiledContents(childScope, function(clone, childScope) {
                         iElement.append(clone); 
                });
            };
        },
        template: "<div><h3>{{ name }}</h6><a class='back'>Back</a><div ng-transclude class='list'></div><a class='next'>Next</a>"
    }
}])

现在,您可以指定任何您想要的变量作为&#34;模型&#34;对于子范围,您可以直接在转换代码的内容中访问它!

查看好消息: http://jsfiddle.net/P8JMm/7/

编辑:为了好玩,我为这个指令创建了一个更复杂的用例:http://jsfiddle.net/P8JMm/9/

注意 - 角度网站也有一些非常好的资源来更好地了解范围。 See here

答案 1 :(得分:1)

如果你想要双向绑定工作,那么在指令范围内创建一个变量要容易得多,而不是直接将mymodel应用到指令范围。

<强> HTML

<div ng-app="myapp">
    <div ng-controller="myController">
        <my-directive-wrapper model="mymodel">
            <my-directive-inner ng-repeat="item in mymodel.items" />
        </my-directive-wrapper>
    </div>
</div>

<强>指令

.directive("myDirectiveWrapper", function(){
    return {
        scope: {
            model: '='        
        },
        restrict: 'E',
        transclude: true,
        link: function(scope, element, attrs, controller) {

        },
        template: "<div><h3>{{ model.name }}</h6><a class='back'>Back</a><div ng-transclude class='list'></div><a class='next'>Next</a>"
    }
})

http://jsfiddle.net/kQ4TV/

如果你不关心双向绑定我想你可以做这样的事情,但我不推荐它:

.directive("myDirectiveWrapper", function(){
    return {
        scope: {
            model: '='        
        },
        restrict: 'E',
        transclude: true,
        link: function(scope, element, attrs, controller) {
            angular.extend(scope, scope.model);
        },
        template: "<div><h3>{{ name }}</h6><a class='back'>Back</a><div ng-transclude class='list'></div><a class='next'>Next</a>"
    }
})

http://jsfiddle.net/vWftR/

以下是第二种方法何时可能导致问题的示例。请注意,当您在输入字段中输入内容时,它将更改指令的名称,但不会更改外部范围中的名称:http://jsfiddle.net/r5JeJ/