【问题标题】:AngularJS: Indicate the scope of a directiveAngularJS:指示指令的范围
【发布时间】:2014-07-10 12:34:48
【问题描述】:

我正在构建一个可以在不同控制器中使用的指令,并且我希望能够将该指令绑定到我的 $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 中的任意属性。

干杯。

【问题讨论】:

  • 你看过$transclude函数,它传递给链接函数的参数吗?它允许您传递一个对象作为转入部分的范围和一个用于 DOM 替换的函数。签出这个 SO 线程stackoverflow.com/questions/13183005/…
  • @NidhishKrishnan 变量名没有被绑定,它应该在屏幕上显示“Transclude test”。该指令使用 $scope,而不是仅使用它的一部分。好主意。
  • @javaCity my-directive-wrapper 应该得到那个部分模型,而不是嵌入的部分。
  • @vtortola: 包装指令的内容总是&lt;my-directive-inner ng-repeat="item in items" /&gt; 或者是别的什么?

标签: javascript angularjs angularjs-directive angularjs-scope


【解决方案1】:

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

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

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

// 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>"
    }
}])

现在您可以指定任何您想要的变量作为子作用域的“模型”,然后您可以直接在您的嵌入代码的内容中访问它!

见识一下: http://jsfiddle.net/P8JMm/7/

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

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

【讨论】:

  • 当你不能 angular.extend 时,它将复制 mymodel 上的所有原语,因此这将破坏双向绑定。
  • @rob 你是对的。为此,OP 需要分配一个特定的变量,或者需要使用对象进行双向绑定而不是原语。不幸的是,无论采用何种方法,都有局限性......
【解决方案2】:

如果您想要两种方式的绑定工作,那么在指令范围内创建一个变量会比直接在指令范围内应用 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/

【讨论】:

  • 您的解决方案也不错,但@drew_w 的解决方案更接近我想要的,尽管存在绑定问题。
猜你喜欢
  • 2014-11-24
  • 1970-01-01
  • 2017-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多