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

Javascript 在AngularJS中调用指令内部的控制器函数,javascript,jquery,angularjs,Javascript,Jquery,Angularjs,以前在堆栈溢出时有人问过这个问题,但由于某些原因,我不断收到错误消息,某些属性未定义 因此,我有以下控制器: phonecatControllers.controller('AboutCtrl', function($scope, $state) { $scope.startListenToScroll = function($scope, $state) { $('.subsection').each(function(i) { var posi

以前在堆栈溢出时有人问过这个问题,但由于某些原因,我不断收到错误消息,某些属性未定义

因此,我有以下控制器:

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();
    }
});
$scope.startListenToScroll = function() {
    // ...
}

$scope.startListenToScroll();
它有两个功能,用于将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的解除绑定,然后在动画完成后重新绑定它们。这是停止scrollspy插件侦听scrollTo动画引起的滚动

但是我得到了错误:
uncaughttypeerror:无法读取未定义的属性“transitiono”
,可能是因为它看不到$state

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


有什么想法吗?

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

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();
    }
});
$scope.startListenToScroll = function() {
    // ...
}

$scope.startListenToScroll();

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

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();
    }
});
$scope.startListenToScroll = function() {
    // ...
}

$scope.startListenToScroll();

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

    $scope.startListenToScroll = function($scope, $state) {
删除这些参数,您应该会很好。您的代码将拾取控制器本身上的
$scope
$state
注入。你只需要注射一次

$scope.startListenToScroll = function() {

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

    $scope.startListenToScroll = function($scope, $state) {
删除这些参数,您应该会很好。您的代码将拾取控制器本身上的
$scope
$state
注入。你只需要注射一次

$scope.startListenToScroll = function() {

按照您的方式,您将从参数中获取变量
$scope
$state
,而在指令中您没有这些变量,因为您得到了错误,您无法将它们定义为参数,它们将从


按照您的方式,您将从参数中获取变量
$scope
$state
,而在指令中您没有这些变量,因为您得到了错误,您无法将它们定义为参数,它们将从


首先,我强烈建议您不要将dom事件逻辑放在控制器中,这与angular团队为防止这种情况发生所做的一切都是背道而驰的

在您的情况下,我要做的是创建一个类似这样的指令:

.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意识。这不是最佳实践,但在某些情况下,这是一个公认的解决方案

需要使用来共享刚刚为您准备好的指令逻辑的示例


干杯

首先,我强烈建议您不要将dom事件逻辑放在控制器中,这与angular团队为防止这种情况发生所做的一切都是背道而驰的

在您的情况下,我要做的是创建一个类似这样的指令:

.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意识。这不是最佳实践,但在某些情况下,这是一个公认的解决方案

需要使用来共享刚刚为您准备好的指令逻辑的示例


干杯

函数Bind和Unbind是deprecated@SjoerdDeWit有没有关于我如何解开卷轴间谍的想法?我正在使用这个插件:@Cameron和是bind&Unbind的替代函数bind和Unbind是deprecated@SjoerdDeWit有没有关于我如何解开卷轴间谍的想法?我正在使用这个插件:@Cameron和bind&unbind的替代品在哪里定义了
scrollAnchorCtrl
?或者AngularJS是否自动理解名称后附加的
Ctrl
?Angular自动将在require属性处定义的指令控制器作为第四个参数注入。无论您如何命名参数,如果该dom项可用,它将始终注入在require中定义的参数,但它与
scrollAnchor
scrollAnchorCtrl
的关系如何,因为它们的名称不同。scrollAnchor指令中并没有说它被称为
scrollAnchorCtrl
,实际上它很简单。理解它的步骤如下。1°scrollTo指令对scrollAnchor指令有一个已定义的依赖关系,因为有这样一行:“require:'scrollAnchor'”2°如果scrollTo指令在同一dom元素上找到一个scrollAnchor指令,它会自动注入作为链接函数的第四个参数,它是控制器,无论您如何命名该参数。链接函数参数注入是按顺序工作的,而不是按名称工作的,就像AngularJS中的所有其他依赖项注入一样。
scrollAnchorCtrl
定义在哪里?或者AngularJS是否自动理解名称后附加的
Ctrl
?Angular自动将在require属性处定义的指令控制器作为第四个参数注入。无论您如何命名参数,如果参数是ava,它将始终注入在需要时定义的参数