在AngularJS中的指令内调用控制器函数

时间:2014-09-02 14:29:15

标签: javascript jquery angularjs

之前已经在Stack Overflow上询问过这个问题,但由于某种原因,我不断收到某些属性未定义的错误!

所以我有以下控制器:

phonecatControllers.controller('AboutCtrl', function($scope, $state) {
    $scope.startListenToScroll = function($scope, $state) {
        $('.subsection').each(function(i) {
            var position = $(this).position();
            $(this).scrollspy({
                min: position.top,
                max: position.top + $(this).height(),
                onEnter: function(element, position) {
                    if (element.id) {
                        $state.transitionTo('about.' + element.id);
                    } else {
                        $state.transitionTo('about');
                    }
                }
            });
        });
    }
    $scope.startListenToScroll($scope, $state);
    $scope.stopListenToScroll = function() {
        $('.subsection').unbind().removeData();
    }
});

它有两个功能,用于将scrollspy插件绑定和解除绑定到我的about页面内的区域。

我还有一个指令,通过点击链接将用户滚动到某些部分:

.directive('scrollTo', function() {
    return {
        link: function(scope, element, attrs) {
            element.bind('click', function() {
                scope.stopListenToScroll();
                var divPosition = $('#' + attrs.scrollTo).offset();
                $('html, body').animate({
                    scrollTop: divPosition.top
                }, "slow", function() {
                    scope.startListenToScroll();
                });
            });
        }
    };
});

正如您所看到的,我在单击时调用了scrollspy的unbind,然后在动画完成后重新绑定它们。这是停止scrolllspy插件监听scrollTo动画引起的滚动。

但是我收到错误:Uncaught TypeError: Cannot read property 'transitionTo' of undefined大概是因为它无法看到$ state。

你会注意到我没有在指令中传递任何内容,但这是因为它应该在控制器中默认正确吗?如果没有,我该如何处理?

有什么想法吗?

4 个答案:

答案 0 :(得分:2)

首先,我强烈建议你不要将dom事件逻辑放在控制器中,它违背了角度团队所做的一切,以防止这种情况发生。

在你的情况下,我要做的就是创建一个像这样的指令:

.directive('scrollAnchor', function($state) {
    return {
        link: function(scope, element, attrs){
            scope.startListenToScroll = function(){
                var position = element.position();
                element.scrollspy({
                    min: position.top,
                    max: position.top + $(this).height(),
                    onEnter: function(ele, position) {
                        if(ele.id){
                            $state.transitionTo('about.'+ele.id);
                        } else {
                            $state.transitionTo('about');
                        }
                    }
                });
            };
            scope.stopListenToScroll = function(){
                element.off().removeData();
            };
        },
        controller: function($scope){
            this.startListenToScroll = $scope.startListenToScroll;
            this.stopListenToScroll = $scope.stopListenToScroll;
        }
    };
});

根据你当前使用scrollTo指令的位置,你可以让它需要scrollAnchor,能够在它的控制器上调用它的“this”关键字定义的函数,例如

.directive('scrollTo', function() {
    return {
        require: 'scrollAnchor',
        link: function(scope, element, attrs, scrollAnchorCtrl) {
            element.bind('click', function() {
                scrollAnchorCtrl.stopListenToScroll();
                var divPosition = $('#'+attrs.scrollTo).offset();
                $('html, body').animate({
                scrollTop: divPosition.top
                }, "slow", function(){
                    scrollAnchorCtrl.startListenToScroll();
                });
            });
        }
    };
});

我没有尝试过这段代码,只是在这里作为概念证明,以便您可以检查它是否适用于您的需求。

干杯!

如果此代码不能满足您的所有需求,那么我建议将一些逻辑移至服务中并使其具有dom感知能力。这不是最好的做法,但在某些情况下,它是一种公认​​的解决方案。

需要使用的示例共享指令逻辑刚刚为您烹饪! http://plnkr.co/edit/IxvLbGdNmkFfroCRX5sO?p=preview

干杯!

答案 1 :(得分:1)

您不需要重新定义$scope$state,因为您已将其注入控制器:

$scope.startListenToScroll = function() {
    // ...
}

$scope.startListenToScroll();

答案 2 :(得分:1)

您实际上正在覆盖此函数中的$ state注入:

    $scope.startListenToScroll = function($scope, $state) {

删除这些参数,你应该没问题。您的代码将在控制器本身上获取$scope$state注入。你只需要注射一次。

$scope.startListenToScroll = function() {

答案 3 :(得分:1)

按照自己的方式行事,你从变量获取变量$scope$state,并且在你的指令中没有它们,因为你得到了错误,你无法定义它们像参数一样,它们将取自closure

phonecatControllers.controller('AboutCtrl', function($scope, $state) {

            $scope.startListenToScroll = function() {

                $('.subsection').each(function(i) {
                    var position = $(this).position();
                    $(this).scrollspy({
                        min: position.top,
                        max: position.top + $(this).height(),
                        onEnter: function(element, position) {
                            if(element.id){
                                $state.transitionTo('about.'+element.id);
                            } else {
                                $state.transitionTo('about');
                            }
                        }
                    });
                });
            }

            $scope.startListenToScroll();

            $scope.stopListenToScroll = function(){
                $('.subsection').unbind().removeData();
            }

        });