当从指令

问题描述:

更新值时,$ rootScope上的Angularjs $ watchCollection不会触发我遇到了一些问题,解决了我正在使用的一些Angularjs功能的问题。当从指令

基本的想法是,我有一个系统,在允许用户前进到应用程序的下一部分之前必须符合某些标准。其中一个例子是,用户必须同时添加评论,并点击链接(在真实应用中,这是一个文件下载),以便他们前进。

您可以在这里完整的例子来看看:https://jsfiddle.net/d81xxweu/10/

我会假设HTML是非常自我解释,并移动到什么,我用我的角模块做。我的应用程序声明和初始化如下:

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); 
      }); 
     } 
    }; 
}); 

所以为了引发我们对这个指令设置表的语句,我可以添加评论所允许的该控制器:

myApp.controller('comments', function ($scope, $rootScope) { 
    $scope.commentText = ''; 
    $scope.comments = []; 

    $scope.addComment = function() { 
     $scope.comments.push({ commentText: $scope.commentText }); 
     $scope.commentText = '' 

     // When the user adds a comment they have met the first criteria 
     $rootScope.criteria.criteria1 = true; 
    }; 
}); 

以前是我的显示/添加注释控制器。我在此处将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; 
      }); 
     } 
    }; 
}); 

正如你在这里看到的,我在$ rootScope中传递,就像在控制器中一样。但是,当我将criteria2设置为true时,$ watchCollection不会被触发。

那么最终发生的是如果我先添加注释,然后单击其他按钮,我没有看到specialButton更新其文本,因为第二次更改从不触发手表。但是,如果我先点击链接,然后添加一条评论,按照预期更新specialButton。 requiredLink的点击是更新数据,但不触发手表。因此,当我添加注释并触发$ watch时,会看到BOTH已设置为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` 
}); 

Demo Plunkr

虽然这个解决方案工作$apply()方法手动启动它,但我会建议你使用使用$rootScope

代替 服务对于使用服务的实现,您需要遵循以下对您有帮助的事情。

您的服务应该使用criteria变量对象的形式,应该遵循dot rule,这样每当你想使用它的相应的参考将更新使用JavaScript原型

SEVICE

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); 
     } 
    }; 
}); 
+0

谢谢,这样可以解决问题。我想过使用服务,但问题是我需要能够从我的specialButton指令外部观察数据以进行更改。我该如何设法观看服务数据? – slave2zeros

+0

@ slave2zeros让我更新我的答案..这也会帮助你.. –

+0

@ slave2zeros看看我的更新答案.. \ –