【问题标题】:Error: [$compile:multidir] for Component Directive with Attribute Directive错误:带有属性指令的组件指令的 [$compile:multidir]
【发布时间】:2017-07-19 16:28:48
【问题描述】:

我需要一个“粘性”指令,当元素位于页面顶部时,它会向元素添加一个 css 类,并发出其状态变化的信号。出于这个原因,我定义了一个类似{ onStickyChange: '&' } 的范围。现在我想在 angularjs 组件中使用该指令,例如:

<my-component sticky on-sticky-change="$ctrl.onStickyChange(sticky)">
</my-component>

我希望该指令在我的组件被粘贴/未粘贴时通知父控制器。但是我收到以下错误:

错误:[$compile:multidir] 多个指令 [myComponent,sticky] 要求新的/隔离的范围: http://errors.angularjs.org/1.6.2/$compile/multidir?p0=myComponent&p1=&p2=s…icky%3D%22%22%20on-sticky-change%3D%22%24ctrl.onStickyChange(sticky)%22%3E 在 angular.js:68 在 assertNoDuplicate (angular.js:10049) 在 applyDirectivesToNode (angular.js:9237) 在 compileNodes (angular.js:8826) 在 compileNodes (angular.js:8838) 在 compileNodes (angular.js:8838) 编译时(angular.js:8707) 在 angular.js:1847 在 Scope.$eval (angular.js:18017) 在 Scope.$apply (angular.js:18117)

app.component('myComponent', {
    template: '<div style="height: 6000px; width: 100%; background-color: #ccf></div>',
    controller: function () {
        this.is = 'nothing';
    }
});
app.directive('sticky', ['$window', function($window) {
    return {
        restrict: 'A',
        scope: { onStickyChange: '&' },
        link: link
    };
    function link(scope, element, attributes) {
        if (typeof scope.onStickyChange !== 'function' ) {
            throw Error('Sticky requires change handler');
        }

        let sticky = isSticky(element);

        angular.element($window).bind('scroll', _.throttle(onWindowScroll, 60));

        function onWindowScroll() {
            let isNowSticky = isSticky(element);

            if (sticky === isNowSticky) {
                return;
            }

            sticky = isNowSticky;

            if (sticky) {
                element.addClass('sticky');
            }
            else {
                element.removeClass('sticky');
            }

            scope.onStickyChange({ sticky: sticky });
        }

        function isSticky(element) {
            return window.scrollTop() > element.position().top;
        }
    }

}]);

如何解决这个问题?

PS:有一个plunk

【问题讨论】:

    标签: javascript angularjs angularjs-directive angularjs-components


    【解决方案1】:

    发生错误是因为组件指令和属性指令都在尝试创建隔离范围。

    来自文档:

    错误:$compile:multidir

    多指令资源争用

    当多个指令应用于同一个 DOM 元素时会发生此错误,并且处理它们会导致冲突或不受支持的配置。

    多个不兼容指令应用于同一元素的示例场景包括:

    • 多个指令请求隔离范围。

    — AngularJS Error Reference - Error: $compile:multidir

    解决方案是重写属性指令以在不创建隔离范围的情况下工作:

    app.directive('sticky', function($window, $parse) {
        return {
            restrict: 'A',
            ̶s̶c̶o̶p̶e̶:̶ ̶{̶ ̶o̶n̶S̶t̶i̶c̶k̶y̶C̶h̶a̶n̶g̶e̶:̶ ̶'̶&̶'̶ ̶}̶,̶
            scope: false,
            link: postLink
        };
        function postLink(scope, elem, attrs) {
    
            //code ...
    
                ̶s̶c̶o̶p̶e̶.̶o̶n̶S̶t̶i̶c̶k̶y̶C̶h̶a̶n̶g̶e̶(̶{̶ ̶s̶t̶i̶c̶k̶y̶:̶ ̶s̶t̶i̶c̶k̶y̶ ̶}̶)̶;̶
                $parse(attrs.onStickyChange)(scope, { sticky: sticky });
    
            //code ...
        }
    });
    

    使用$parse Service 评估on-sticky-change 属性的角度表达式。

    【讨论】:

      【解决方案2】:

      你不能有两个指令在同一个元素上请求隔离范围——这会在 Angular 中产生内部冲突。如果您需要两个指令用于同一元素,您可以利用传递给您的 link 函数的 attrs 参数来捕获您需要的任何值(并且您需要删除指令的隔离范围属性)。

      【讨论】:

      • 不太明白。手头的问题是从外部main 控制器中的指令获取输出。 “杠杆作用”是什么意思?
      • 自从您使用代码更新了您的问题后,georgeawg 添加了更详细的答案。检查一下 - 它应该足以解决您的问题。
      猜你喜欢
      • 2015-03-23
      • 1970-01-01
      • 2016-03-27
      • 1970-01-01
      • 1970-01-01
      • 2016-11-19
      • 2021-02-11
      • 2016-11-30
      • 2018-05-19
      相关资源
      最近更新 更多