Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 从指令更新值时,$rootScope上的Angularjs$watchCollection未触发_Javascript_Angularjs_Events_Angularjs Directive_Angularjs Watch - Fatal编程技术网

Javascript 从指令更新值时,$rootScope上的Angularjs$watchCollection未触发

Javascript 从指令更新值时,$rootScope上的Angularjs$watchCollection未触发,javascript,angularjs,events,angularjs-directive,angularjs-watch,Javascript,Angularjs,Events,Angularjs Directive,Angularjs Watch,我在使用Angularjs功能解决问题时遇到了一些问题 基本思想是,我有一个系统,在允许用户进入应用程序的下一部分之前,必须满足某些标准。这方面的一个例子是,用户必须添加评论,并单击链接(在真正的应用程序中,这是文件下载)才能前进 您可以在此处查看完整示例: 我将假设HTML是非常自解释的,然后继续讨论我正在使用Angular模块做什么。我的应用声明和初始化如下: var myApp = angular.module('myApp', ['ngRoute']); myApp.run(funct

我在使用Angularjs功能解决问题时遇到了一些问题

基本思想是,我有一个系统,在允许用户进入应用程序的下一部分之前,必须满足某些标准。这方面的一个例子是,用户必须添加评论,并单击链接(在真正的应用程序中,这是文件下载)才能前进

您可以在此处查看完整示例:

我将假设HTML是非常自解释的,然后继续讨论我正在使用Angular模块做什么。我的应用声明和初始化如下:

var myApp = angular.module('myApp', ['ngRoute']);

myApp.run(function ($rootScope) {
    // Both of these must be met in order for the user to proceed with 'special-button'
    $rootScope.criteria = {
        criteria1: false,
        criteria2: false
    };
});
这很简单。我将一个名为criteria的对象附加到应用程序的根作用域,以使我的指令和控制器可以访问它。我有一个指示,呈现的链接,允许用户前进,一旦标准得到满足。在本例中,链接的文本从“等待…”更改为“单击继续”,表示我们可能会前进

myApp.directive('specialButton', function ($rootScope) {
    return {
        scope: true,
        template: "<a href='#'>{{ linkText }}</a>",
        replace: true,
        link: function (scope, el, attrs) {
            scope.linkText = 'Waiting...';

            var setLinkState = function(currentCriteria) {
                var criteriaMet = true;

                for(var k in $rootScope.criteria) {
                    if($rootScope.criteria[k] == false) {
                        criteriaMet = false;
                    }
                }

                if(criteriaMet) {
                    scope.linkText = 'Click to proceed';
                }
            };

            // Watch for changes to this object at the root scope level
            $rootScope.$watchCollection('criteria', function(newValues) {
                setLinkState(newValues);
            });
        }
    };
});
前一个是我的控制器,用于显示/添加注释。我在这里将criteria1设置为true,以指示用户添加了注释。这实际上工作得很好,specialButton指令中的$watchCollection按预期调用

当我试图从必须单击才能前进的链接执行相同的操作时,问题就出现了。这是用指令呈现的,因为我的理解是,在这种情况下,指令比控制器更有意义,这与注释列表/表单不同

myApp.directive('requiredLink', function($rootScope) {
    return {
        scope: true,
        template: "<a href='#'>Click me!</a>",
        replace: true,
        link: function(scope, el, attrs) {
            el.bind('click', function(evt) {
                evt.preventDefault();

                // When the user clicks this link they have met the second criteria
                $rootScope.criteria.criteria2 = true;
            });
        }
    };
});
myApp.directive('requiredLink',function($rootScope){
返回{
范围:正确,
模板:“”,
替换:正确,
链接:功能(范围、el、属性){
el.bind('click',函数(evt){
evt.preventDefault();
//当用户单击此链接时,他们已满足第二个标准
$rootScope.criteria.criteria2=true;
});
}
};
});
正如您在这里看到的,我传入$rootScope就像传入控制器一样。但是,当我将criteria2设置为true时,不会触发$watchCollection

因此,如果我先添加一条注释,然后单击另一个按钮,我不会看到specialButton更新其文本,因为第二个更改不会触发手表。但是,如果我先单击链接,然后添加注释,则specialButton会按预期更新。单击requiredLink会更新数据,但不会触发手表。因此,当我添加一条评论并触发$watch时,它会看到这两个选项都被设置为true


提前感谢您为解决此问题提供的任何帮助;感谢您的时间。

您的实际问题是您正在从角度上下文之外的事件更新
$rootScope
,因此很明显角度绑定不会更新,因为在这种情况下不会触发摘要循环。您需要使用
$rootScope

el.bind('click', function(evt) {
    evt.preventDefault();
    // When the user clicks this link they have met the second criteria
    $rootScope.criteria.criteria2 = true;
    $rootScope.$apply(); //this will run digest cycle & will fire `watchCollection` `$watcher`
});

虽然这个解决方案有效,但我建议您改用服务 使用
$rootScope

el.bind('click', function(evt) {
    evt.preventDefault();
    // When the user clicks this link they have met the second criteria
    $rootScope.criteria.criteria2 = true;
    $rootScope.$apply(); //this will run digest cycle & will fire `watchCollection` `$watcher`
});
对于使用服务的实现,您需要遵循以下有助于您的事项

您的服务应该使用对象形式的
标准
变量,应该遵循,以便使用JavaScript原型更新相应的引用

服务

app.service('dataService', function(){
    this.criteria = {
        criteria1: false,
        criteria2: false
    };
    //...here would be other sharable data.
})
myApp.directive('specialButton', function (dataService) {
    return {
        scope: true,
        template: "<a href='#'>{{ linkText }}</a>",
        replace: true,
        link: function (scope, el, attrs) {
            //.. other code

            // deep watch will watch on whole object making last param true
            scope.$watch(function(){ 
                return dataService.criteria //this will get get evaluated on criteria change
            }, function(newValues) {
                setLinkState(newValues);
            }, true);
        }
    };
});
无论何时,只要您想在任何需要的地方使用它,就可以将它注入控制器、指令、过滤器的功能中

在监视指令中的服务变量时,您需要执行如下操作

指令

app.service('dataService', function(){
    this.criteria = {
        criteria1: false,
        criteria2: false
    };
    //...here would be other sharable data.
})
myApp.directive('specialButton', function (dataService) {
    return {
        scope: true,
        template: "<a href='#'>{{ linkText }}</a>",
        replace: true,
        link: function (scope, el, attrs) {
            //.. other code

            // deep watch will watch on whole object making last param true
            scope.$watch(function(){ 
                return dataService.criteria //this will get get evaluated on criteria change
            }, function(newValues) {
                setLinkState(newValues);
            }, true);
        }
    };
});
myApp.指令('specialButton',函数(数据服务){ 返回{ 范围:正确, 模板:“”, 替换:正确, 链接:功能(范围、el、属性){ //…其他代码 //深度监视将监视整个对象,使最后一个参数为真 作用域.$watch(函数(){ return dataService.criteria//将在条件更改时对其进行评估 },函数(新值){ setLinkState(新值); },对); } }; });
谢谢,这就解决了问题。我曾考虑过使用一个服务,但问题是我需要能够从外部监视数据,以便根据specialButton指令进行更改。我如何才能设法查看服务数据?