Program Tip

서비스 데이터 변경시 범위 값 업데이트

programtip 2020. 10. 20. 08:02
반응형

서비스 데이터 변경시 범위 값 업데이트


내 앱에 다음 서비스가 있습니다.

uaInProgressApp.factory('uaProgressService', 
    function(uaApiInterface, $timeout, $rootScope){
        var factory = {};
        factory.taskResource = uaApiInterface.taskResource()
        factory.taskList = [];
        factory.cron = undefined;
        factory.updateTaskList = function() {
            factory.taskResource.query(function(data){
                factory.taskList = data;
                $rootScope.$digest
                console.log(factory.taskList);
            });
            factory.cron = $timeout(factory.updateTaskList, 5000);
        }

        factory.startCron = function () {
            factory.cron = $timeout(factory.updateTaskList, 5000);
        }

        factory.stopCron = function (){
            $timeout.cancel(factory.cron);
        }
        return factory;
});

그런 다음 다음과 같은 컨트롤러에서 사용합니다.

uaInProgressApp.controller('ua.InProgressController',
    function ($scope, $rootScope, $routeParams, uaContext, uaProgressService) {
        uaContext.getSession().then(function(){
            uaContext.appName.set('Testing house');
            uaContext.subAppName.set('In progress');
            uaProgressService.startCron();

            $scope.taskList = uaProgressService.taskList;
        });
    }
);

그래서 기본적으로 내 서비스 업데이트 factory.taskList5 초마다 나는이 연결 factory.taskList$scope.taskList. 나는 다음과 같은 여러 가지 방법을 시도했다 $apply, $digest그러나에 변경 factory.taskList내 컨트롤러와 뷰에 반영되지 않습니다 $scope.taskList.

내 템플릿에서 비어 있습니다. 이러한 변경 사항을 어떻게 전파 할 수 있는지 알고 있습니까?


사용 $watch하면 문제가 해결 될 수 있지만 가장 효율적인 솔루션은 아닙니다. 서비스에 데이터를 저장하는 방식을 변경할 수 있습니다.

문제는 taskList스코프가 이전 위치를 가리키고있는 동안 새 값을 할당 할 때마다 연결된 메모리 위치를 교체한다는 것 입니다. 이 plunk 에서 이런 일이 일어나는 것을 볼 수 있습니다 .

플렁크를 처음로드 할 때 Chrome으로 힙 스냅 샷을 찍고 버튼을 클릭하면 목록이 다른 메모리 위치를 가리키는 동안 범위가 가리키는 메모리 위치가 업데이트되지 않음을 알 수 있습니다.

변경 될 수있는 변수 (예 :)가 포함 된 객체를 서비스에 보유하도록하여이 문제를 쉽게 해결할 수 있습니다 data:{task:[], x:[], z:[]}. 이 경우 "데이터"는 변경되어서는 안되지만 필요할 때마다 해당 멤버를 변경할 수 있습니다. 그런 다음이 데이터 변수를 범위에 전달하고 "데이터"를 다른 항목에 할당하여 재정의하지 않는 한 데이터 내부의 필드가 변경 될 때마다 범위가 이에 대해 인식하고 올바르게 업데이트합니다.

이 plunk 는 위에서 제안한 수정을 사용하여 실행되는 동일한 예제를 보여줍니다. 이 상황에서 감시자를 사용할 필요가 없으며 뷰에서 무언가 업데이트되지 않은 경우 뷰 $apply를 업데이트 하는 범위 실행하기 만하면 됩니다.

이렇게하면 변수를 자주 비교하는 감시자가 변경 사항과 많은 변수를 감시해야하는 경우에 관련된 추악한 설정이 필요하지 않습니다. 이 접근 방식의 유일한 문제는 뷰 (html)에 "데이터"가 있다는 것입니다. 변수 이름을 사용하는 모든 곳에 접두사를 붙입니다.


Angular (Ember 및 기타 프레임 워크와 달리)는 반마 법적 으로 동기화 상태를 유지 하는 특수 래핑 된 개체를 제공하지 않습니다 . 당신이 조작 된 개체는 일반 자바 스크립트 객체 그냥 말처럼 하지 않는 링크 변수 말, 이 두 값을 연결하지 않습니다.var a = b;ab$scope.taskList = uaProgressService.taskList

이러한 종류의 link-ing에 대해 다음을 angular제공합니다 $watch.$scope . 의 값을보고 값이 변경되면 uaProgressService.taskList업데이트 할 수 있습니다 $scope.

$scope.$watch(function () { return uaProgressService.taskList }, function (newVal, oldVal) {
    if (typeof newVal !== 'undefined') {
        $scope.taskList = uaProgressService.taskList;
    }
});

$watch함수에 전달 된 첫 번째 표현식은$digest 루프에서 두 번째 인수는 새 값과 이전 값으로 호출되는 함수입니다.


그게 도움이되는지 확실하지 않지만 내가하고있는 일은 함수를 $ scope.value에 바인딩하는 것입니다. 예를 들면

angular
  .module("testApp", [])
  .service("myDataService", function(){
    this.dataContainer = {
      valA : "car",
      valB : "bike"
    }
  })
  .controller("testCtrl", [
    "$scope",
    "myDataService",
    function($scope, myDataService){
      $scope.data = function(){
        return myDataService.dataContainer;
      };
  }]);

그런 다음 DOM에서 다음과 같이 바인딩합니다.

<li ng-repeat="(key,value) in data() "></li>

이렇게하면 코드에서 $ watch를 사용하지 않아도됩니다.


아니오 $watch등이 필요합니다. 다음을 간단히 정의 할 수 있습니다.

uaInProgressApp.controller('ua.InProgressController',
  function ($scope, $rootScope, $routeParams, uaContext, uaProgressService) {
    uaContext.getSession().then(function(){
        uaContext.appName.set('Testing house');
        uaContext.subAppName.set('In progress');
        uaProgressService.startCron();
    });

    $scope.getTaskList = function() {
      return uaProgressService.taskList;
    };
  });

함수 가 반환 값에 getTaskList속하기 때문에 $scope모든 변경 사항에 대해 평가 (및 업데이트)됩니다.uaProgressService.taskList


Lightweight alternative is that during controller initialization you subscribe to a notifier pattern set up in the service.

다음과 같은 것 :

app.controller('YourCtrl'['yourSvc', function(yourSvc){
    yourSvc.awaitUpdate('YourCtrl',function(){
        $scope.someValue = yourSvc.someValue;
    });
}]);

그리고 서비스는 다음과 같습니다.

app.service('yourSvc', ['$http',function($http){
    var self = this;
    self.notificationSubscribers={};
    self.awaitUpdate=function(key,callback){
        self.notificationSubscribers[key]=callback;
    };
    self.notifySubscribers=function(){
        angular.forEach(self.notificationSubscribers,
            function(callback,key){
                callback();
            });
    };
    $http.get('someUrl').then(
        function(response){
            self.importantData=response.data;
            self.notifySubscribers();
        }
    );
}]);

이렇게하면 컨트롤러가 서비스에서 새로 고쳐질 때보다 신중하게 조정할 수 있습니다.


Like Gabriel Piacenti said, no watches are needed if you wrap the changing data into an object.

BUT for updating the changed service data in the scope correctly, it is important that the scope value of the controller that uses the service data does not point directly to the changing data (field). Instead the scope value must point to the object that wraps the changing data.

The following code should explain this more clear. In my example i use an NLS Service for translating. The NLS Tokens are getting updated via http.

The Service:

app.factory('nlsService', ['$http', function($http) {
  var data = {
    get: {
      ressources        : "gdc.ressources",
      maintenance       : "gdc.mm.maintenance",
      prewarning        : "gdc.mobMaint.prewarning",
    }
  };
// ... asynchron change the data.get = ajaxResult.data... 
  return data;
}]);

Controller and scope expression

app.controller('MenuCtrl', function($scope, nlsService)
  {
    $scope.NLS = nlsService;
  }
);

<div ng-controller="MenuCtrl">
  <span class="navPanelLiItemText">{{NLS.get.maintenance}}</span>
</div>

The above code works, but first i wanted to access my NLS Tokens directly (see the following snippet) and here the values did not become updated.

app.controller('MenuCtrl', function($scope, nlsService)
  {
    $scope.NLS = nlsService.get;
  }
);

<div ng-controller="MenuCtrl">
  <span class="navPanelLiItemText">{{NLS.maintenance}}</span>
</div>

참고URL : https://stackoverflow.com/questions/19744462/update-scope-value-when-service-data-is-changed

반응형