【问题标题】:Angular directive code changes scope, but template shows the same valueAngular 指令代码更改范围,但模板显示相同的值
【发布时间】:2017-11-01 18:54:57
【问题描述】:

我有如下指令:

.directive('myDirective', function() {
    return {
        restrict: 'AE',
        replace: true,
        templateUrl: '/myDirective.html?v=' + window.buildNumber,
        link: function (scope, element, attrs) {
            scope.itemClasses = attrs.itemClasses || '';
        }
    }
})

它的模板看起来像:

<div class="my-directive">
    <div class="items" ng-repeat="item in items">
        <div class="item {{ itemClasses }}">{{ item.title }}</div>
    </div>
</div>

并且该指令在不同的地方被调用(每个模板调用一次),如下所示:

<my-directive item-classes="col-md-6"></my-directive>
...
<my-directive item-classes="col-md-12"></my-directive>

并且所有模板都呈现相同的itemClasses 值。同时链接函数设置了正确的值(我通过调用console.log()检查了这个事实)。

如果我将scope: true 属性添加到指令的代码中,那么一切正常。因此,似乎拥有自己的继承范围会有所帮助。你能解释一下这种行为吗?

谢谢。

【问题讨论】:

    标签: javascript angularjs scope angularjs-scope


    【解决方案1】:

    当你使用scope: true 时,你为你的指令创建了一个子作用域,同时你也继承了父级的属性(在这种情况下,我认为你的控制器)。因此,您的所有指令实例都将具有适当的范围。

    使用scope: false 你的指令实际上没有作用域,它与它的父级共享作用域。

    所以,当你这样做时,回到你的问题,scope:false

    scope.itemClasses = attrs.itemClasses || '';

    您正在将itemClasses 属性设置为父级的范围。 这意味着当您在链接函数中看到它似乎工作正常时,但实际上每次您要覆盖控制器的相同范围变量。

    因此,在您的情况下,第一次将范围变量关联到父控制器时:

    scope.itemClasses= 'col-md-6';

    但实际上第二次你用新值覆盖了父级的相同范围变量:

    scope.itemClasses= 'col-md-12';

    这有意义吗?

    【讨论】:

    • 感谢您的解释!请让我总结一下,以确保我做对了。在任何模板渲染之前调用所有link 函数。所以,我的代码只是覆盖范围内的相同属性。在渲染模板时,我只有最后一个赋值。对吗?
    • 那么,scope: true 方法是否正确?还是有更好的?
    • 简而言之:如果范围为 false,您将使用父级的范围。因此,您总是在父范围内设置相同的变量。所以你总是覆盖相同的变量。对于正确的方法,它取决于您将如何处理此值。你打算用 itemClasses 做什么?当控制器中的某些变量发生变化时,您需要更改它们吗?
    • 我只是希望能够将一些参数传递给指令。该值将在模板中呈现。我的意思是,我有 3 个布局相同的 HTML 块。它们之间的唯一区别是添加到元素的类。所以我决定创建一个指令并用参数(改变类)调用它。
    • 是的,我理解scope: false 让我使用父范围的想法。所以,是的,它总是会设置相同的变量。我认为它的工作方式如下: setVariable -> render; setVariable -> 渲染(所以没有问题)。从您的回答中,我了解到它的工作方式如下: setVariable -> setVariable;渲染->渲染。因此,我们在完成所有设置的程序后进行渲染。正确的? :)
    【解决方案2】:

    通过直接从属性绑定item-classes,您基本上是在复制属性值。

    解决方案是:如果您想将input-classes 设为输入绑定,您可以像这样使用隔离范围:

    {
        restrict: 'AE',
        replace: true,
        scope: {
            itemClasses: '='
        },
        templateUrl: '/myDirective.html?v=' + window.buildNumber,
        link: function (scope, element, attrs) {
            // scope.itemClasses = attrs.itemClasses || '';
        }
    }
    

    或者如果您不想使用隔离范围,您可以使用attrs.$observe

    link: function (scope, element, attrs) {
        attrs.$observe('itemClasses ', function(val) {
            scope.itemClasses = val || '';
        });
    }
    

    【讨论】:

    • 感谢您的回答。 AFAIU,隔离范围不允许我访问外部范围的属性。所以,这不是我的选择。考虑到@quirimmo 的答案,我不确定第二个解决方案。我的意思是,似乎它也将在任何模板呈现之前执行。即,在模板渲染步骤中,我们将获得最后一个赋值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多