将指向服务对象属性的指针/引用添加到$scope变量

Add a pointer/reference to service object property to a $scope variable

本文关键字:添加 引用 变量 scope 指针 服务 对象 属性      更新时间:2023-09-26

我如何添加一个指针/引用对象属性(这也是一个对象)到角$范围?

考虑以下代码:

videosModule.factory('VideoManager', ['YtVideos', function(YtVideos){ 
    return {
        videos: [{}, {}, {}],
        currentVideo: {},
        counter: 0,
        setCurrentVideo: function(){
            this.currentVideo = this.videos[this.counter];
        }
    };
}]);

和控制器:

videosModule.controller('SelectVideoCtrl', ['VideoManager', '$scope', function(VideoManager, $scope){
    $scope.currentVideo = VideoManager.currentVideo;
    $scope.videomanager = VideoManager;
}]);

现在我希望控制器中的第一行指向属性currentVideo,这样当它在服务中被更改时,它将被更新到$作用域。

这是不工作,但是当我引用整个服务(第二行),并使用{{videommanager。currentVideo}}确实有效。

有人能解释一下吗?谢谢。

$scope.currentVideo = VideoManager.currentVideo;是对您的值的一种模仿。这意味着它永远不会改变。如果您做了这个更改,您就有了第二个语法:$scope.videomanager = VideoManager;,它类似于所有工厂。然后你可以找到currentVideo

但是,如果您想要类似于第一种语法的东西(并且避免使用墙壁工厂对象),您可以使用函数。getter就可以了:

videosModule.factory('VideoManager', ['YtVideos', function(YtVideos){ 
  return {
    videos: [{}, {}, {}],
    currentVideo: {},
    counter: 0,
    setCurrentVideo: function(){
        this.currentVideo = this.videos[this.counter];
    },
    getCurrentVideo : function(){
        return this.currentVideo;
    }
  };
}]);

然后你的控制器需要链接这个getter

videosModule.controller('SelectVideoCtrl', ['VideoManager', '$scope', function(VideoManager, $scope){
    $scope.currentVideo = VideoManager.getCurrentVideo;
    $scope.videomanager = VideoManager;
}]);

注意控制器中没有()。如果希望刷新值,则必须将它们放入DOM中。这里只是一个函数链接。在你的HTML中,它应该是这样的:

{{currentVideo()}}

在你的控制器中,你正在引用VideoManager。currentVideo到$scope.currentVideo

  $scope.currentVideo = VideoManager.currentVideo;

这很好,直到你不改变videomemanager . currentvideo的引用。当你改变服务中的currentVideo reference时,VideoManger。当前视频将指向新的引用,但你的$作用域。当前视频仍然指向旧的引用。

如果你使用一个对象并修改了它的属性,但是为了访问那个属性,你使用的是那个对象,那么它会工作得很好。下面的语句

也是如此
$scope.videomanager = VideoManager;

在这里你$scope。videomemanager指向你的服务videomemanager。你永远不会改变VideoManagaer引用。所以美元范围。videoomanger将在整个应用程序中始终指向相同的引用。如果你改变了VideoManager的任何属性,那么它会反映你的控制器,因为你正在使用service object访问它。

所以,在angularjs中,Service都是单例的,而且都是惰性实例化的。

Angular服务是:

惰性实例化——Angular只在应用组件依赖于它。

单例-每个组件依赖于服务获取对单个实例的引用由服务工厂生成。

服务

你可以不使用任何getter函数,只需要将你的服务包装到你的$scope中。

在你的例子中,$scope.currentVideo = VideoManager.currentVideo;只是指你的视频的名字,它的只是一个字符串,不是一个对象,不是你的服务

但是如果您执行$scope.videomanager = VideoManager;,您将把您的服务包装到$scope中。然后,当你要更新服务中的值时,作用域中的数据将发生变化,因为$scope.videomanager将是整个服务,并且你的作用域中的数据将发生变化,因为你的$scope指向服务

所以你可以这样做:

控制器

videosModule.controller('SelectVideoCtrl', ['VideoManager', '$scope', function(VideoManager, $scope){
    $scope.videomanager = VideoManager;
}]);

<div>{{videomanager.currentVideo}}<div>

Angular只跟踪那些在AngularJS的上下文中完成的模型更改(即,更改模型的代码被封装在$apply()中)。Angular的内置指令和控制器已经做到了这一点,所以你对模型所做的任何更改都会反映在视图中。然而,如果你改变了Angular上下文之外的任何模型(在这个例子中是service),那么你需要通过手动调用$apply()来通知Angular这些变化。这就像告诉Angular你正在改变一些模型,它应该触发观察者,这样你的改变才能正确传播。当你使用

$scope.currentVideo = VideoManager.currentVideo

Angular没有跟踪VideoManager,所以VideoManager内部的变化。setCurrentVideo方法不会触发模型更改。但是当你使用

$scope.videomanager = VideoManager;

Angular正在跟踪VideoManager,所以方法VideoManager。setCurrentVideo在控制器内置的$apply()中执行。

例如,下面的代码可以工作,但我不推荐这样做。

videosModule.factory('VideoManager', ['YtVideos', '$rootScope', function(YtVideos, $rootScope){ 
return {
    videos: [{}, {}, {}],
    currentVideo: {},
    counter: 0,
    setCurrentVideo: function(){
        this.currentVideo = this.videos[this.counter];
        $rootScope.$broadcast('scope.changed');
    }
};
}]);
videosModule.controller('SelectVideoCtrl', ['VideoManager', '$scope', function(VideoManager, $scope){
    $scope.$on('scope.changed', function () {
        if ($scope.apply) $scope.apply();
    });
    $scope.currentVideo = VideoManager.currentVideo;
}]);