Javascript 角度:观察服务中的数据变化?

Javascript 角度:观察服务中的数据变化?,javascript,angularjs,Javascript,Angularjs,我的服务定义如下: appServices.service('SharedData', function() { var data = {}; function setContacts(contacts) { data.contacts = contacts; }; function getContacts() { return data.contacts; }; return { setCon

我的服务定义如下:

appServices.service('SharedData', function() {
    var data = {};

    function setContacts(contacts) {
        data.contacts = contacts;
    };

    function getContacts() {
        return data.contacts;
    };

    return {
        setContacts: setContacts,
        getContacts: getContacts
    };
});
在另一个控制器中,我访问数据如下:

$scope.contacts = SharedData.getContacts();
这一切都很好,但我希望当SharedData中的数据发生变化时,会提醒
$scope.contacts
,并更新其数据


如何实现这一点?

一种方法是在您的服务中定义一个函数,该函数允许您在调用
setContacts
时注册要调用的回调(
onContactsUpdated
)。这个解决方案并不完美(例如,它只允许您注册一个“处理程序”),但应该让您走上正确的道路。如果需要在多个地方使用,可以对其进行调整

appServices.service('SharedData', function() {
    var data = {};

    function setContacts(contacts) {
        data.contacts = contacts;
        if(typeof(data.contactsUpdatedCallback) !== "undefined"){
            data.contactsUpdatedCallback();
        }
    };

    function getContacts() {
        return data.contacts;
    };

    function onContactsUpdated(callback){
        data.contactsUpdatedCallback = callback;
    };

    return {
        setContacts: setContacts,
        getContacts: getContacts,
        onContactsUpdated: onContactsUpdated
    };
});
然后在控制器中:

SharedData.onContactsUpdated(function(){
    //do something with updated SharedData.getContacts()
});
尝试显式手表:

$scope.$watch(函数(){
返回SharedData.getContacts();
},功能(新联系人){
//对新联系人做些什么。
});

如果集合的元素可以在整个集合对象不更改标识的情况下更改(我假设是
数组
对象
),则需要使用
$scope.$watchCollection
,尽管这比普通的
$watch
要慢得多,因此如果可以立即更改整个集合,请避免

请注意,将函数公开到只返回当前联系人的作用域可能是更好的设计:

$scope.getContacts=function(){return SharedData.getContacts();}


如果您需要在
SharedData
中发出通知,您可以将
$rootScope
注入其中,并将
$watch
放在上面。

小心滥用它,但这正是
$rootScope
用于:

appServices.service('SharedData', function($rootScope) {
  var data = {};
  function setContacts(contacts) {
    data.contacts = contacts;
    $rootScope.$broadcast('contacts-changed', contacts);
  };
  ...
现在,在您想要的任何范围内,您都可以注册此事件:

function($scope) {
  $scope.$on('contacts-changed', function(eventObj) {...});
}

您可以使用一个事件…并警告如果个人联系人已更新,则不会触发简单的手表。如果你也对此感兴趣,你需要使用
$scope.$watchCollection
。@floribon我不喜欢这样使用
$watch
——在每个摘要周期上运行这样的方法似乎是错误的。但是,按照服务的编写方式,一个简单的
$watch
将起作用,因为每次使用
setContacts
都会重置整个集合。我希望您会同意,
$watchCollection
是一种非常痛苦的方式,因为它可能会在每个孩子身上迭代以寻找变化。美好的我对Angular很陌生,在不知道的情况下写下了我的答案。@MichaelHays我完全同意,并没有说你错了!我在jsut中添加了我的评论“作为警告”,以防OP希望单独更新联系人(在获得联系人后仍然可以)
watchCollection
是否进行浅层对象属性监视:这一成本稍高,但与深度监视(使用
$watch
并将最后一个参数设置为true)相比仍相差甚远,因此不应引起真正的关注。但我仍然同意你的观点,我个人也会采取倾听的方式。在发表我的评论之前,我向你投了赞成票:)哎呀,我想我最后回答的评论来自于答案海报(类似的名字)。我现在被说服了。无论如何,在评论之前,我把所有的答案都投了赞成票,因为它们都很好,所以不要被忽视。太棒了,谢谢。传入的var
nv
有什么特别的含义吗?哈!你犯了个错误。我使用
nv
来表示“新值”,但在本例中,它最好命名为
evt
,并且是事件对象:这更有意义,谢谢。另一个问题:什么会被视为滥用这种技术?我最终会用它来广播十几个或更多的“已更改”事件。我的第一个想法是,“您的技术是否增加了代码的可读性?”我的第二个想法是,“如果它降低了代码的可读性,那么维护的增加是否抵消了合理的性能提高?”如果其中一个问题的答案是“否,”那么您可能滥用了该功能。除非你处于一个紧张的动画循环中,否则你的建议听起来不错。终于有机会回应了。问题#1:起初是的,但最终它变成了意大利面代码,很难理解。我学习了如何使用controllerAs(
MainCtrl作为main
)语法,因为我的控制器是嵌套的,所以我可以轻松访问子控制器中的父模型(
main.customer
)。它干净多了,不需要特别的广播。谢谢你帮助我保持谨慎!