错误:带有属性指令的组件指令的[$ compile:multidir]

时间:2017-07-19 16:28:49

标签: javascript angularjs angularjs-directive angularjs-components

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

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

我希望该指令在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       在范围。$ 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

2 个答案:

答案 0 :(得分:2)

发生错误是因为component指令和属性指令都试图创建隔离范围。

来自文档:

  

错误:$ 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属性上的角度表达式。

答案 1 :(得分:1)

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