Refresh of scope after remote change to data

旧城冷巷雨未停 提交于 2019-12-08 03:52:55

问题


In my controller for a mpbile app based on Angular1 is have (for example) the following function:

var getItem = function() {

    // Initialize $scope
    $scope.url = "(url to get my data)";

    $http.get($scope.url).success(function(data) {
        $scope.itemDetails = data; // get data from json
    });
};    

getItem();

and this works just fine.. with one problem.. it doesnt update. Even if I switch pages and come back, if the scope hasnt changed, it doesnt reflect new data in the scope.

So, i built in an $interval refresh to look for changes in the scope, this works fine EXCEPT, when i leave the page to go to another, that interval keeps polling. This is obviously a bad idea in a mobile app where data and battery usage may be an issue.

So.. how can I keep checking the scope for 'live changes' when ON that page only OR what is best practice for the scope to refresh on data changes.

I have read about digests and apply but these still seem to be interval checks which I suspect will keep operation after switching pages.

Or on angular apps with live data, is constantly polling the API the 'thing to do' (admittedly the data the page pulls is only 629 bytes, but i have a few pages to keep live data on, so it will add up)

Thanks


回答1:


When you create a controller, the function's in it are declared, but not run. and since at the end of the controller you are calling getItem(); it is run once. Moving to another page, and coming back is not going to refresh it.

The only way to refresh is to call that function again, In your HTML or JS.

For example:

<button ng-click="getItem()">Refresh</button>



回答2:


Really nice question, I have been wondering the same thing, so I checked a lot of related SO posts and wrote kind of a function that can be used.

Note: I am testing the function with a simple console.log(), please insert your function logic and check.

The concept is

$interval is used to repeatedly run the function($scope.getItem) for a period (in the below example for 1 second), A timeout is also actively running to watch for inactive time, this parameter is defined by timeoutValue (in the example its set to 5 seconds), the document is being watched for multiple events, when any event is triggered, the timeout is reset, if the timeoutValue time is exceeded without any events in the document another function is called where the interval is stopped. then on any event in the document after this, the interval is started back again.

var myModule = angular.module('myapp',[]);
myModule.controller("TextController", function($scope, $interval, $document, $timeout){
  //function to call
  $scope.getItem = function() {
    console.log("function");
  };
  
  //main function
  //functionName - specify the function that needs to be repeated for the intervalTime
  //intervalTime - the value is in milliseconds, the functionName is continuously repeated for this time.
  //timeoutValue - the value is in milliseconds, when this value is exceeded the function given in functionName is stopped
  
  monitorTimeout($scope.getItem, 1000 ,5000);
  	function monitorTimeout(functionName, intervalTime, timeoutValue){
      //initialization parameters
      timeoutValue = timeoutValue || 5000;
      intervalTime = intervalTime || 1000;
      // Start a timeout
      var TimeOut_Thread = $timeout(function(){ TimerExpired() } , timeoutValue);
      var bodyElement = angular.element($document);

      /// Keyboard Events
      bodyElement.bind('keydown', function (e) { TimeOut_Resetter(e) });  
      bodyElement.bind('keyup', function (e) { TimeOut_Resetter(e) });    

      /// Mouse Events    
      bodyElement.bind('click', function (e) { TimeOut_Resetter(e) });
      bodyElement.bind('mousemove', function (e) { TimeOut_Resetter(e) });    
      bodyElement.bind('DOMMouseScroll', function (e) { TimeOut_Resetter(e) });
      bodyElement.bind('mousewheel', function (e) { TimeOut_Resetter(e) });   
      bodyElement.bind('mousedown', function (e) { TimeOut_Resetter(e) });        

      /// Touch Events
      bodyElement.bind('touchstart', function (e) { TimeOut_Resetter(e) });       
      bodyElement.bind('touchmove', function (e) { TimeOut_Resetter(e) });        

      /// Common Events
      bodyElement.bind('scroll', function (e) { TimeOut_Resetter(e) });       
      bodyElement.bind('focus', function (e) { TimeOut_Resetter(e) });

      function TimerExpired(){
        if(theInterval) {
          $interval.cancel(theInterval);
          theInterval = undefined;
        }
      }

      function TimeOut_Resetter(e){
          if(!theInterval){
            theInterval = $interval(function(){
              functionName();
            }.bind(this), intervalTime);
          }

          /// Stop the pending timeout
          $timeout.cancel(TimeOut_Thread);

          /// Reset the timeout
          TimeOut_Thread = $timeout(function(){ TimerExpired() } , timeoutValue);
      }

      var theInterval = $interval(function(){
        functionName();
      }.bind(this), intervalTime);
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myapp">
    <div ng-controller="TextController">
    </div>
</div>



回答3:


Depending on the router you are using, you have to tell the controller to reload when the route changed or updated, because the function you pass when declaring a controller is only a factory, and once the controller is constructed it won't run again because the router caches it (unless you tell angularjs to do so, which is rarely a good idea).

So your best bet is to use the router to reload the state when the route changes. You can do this using the router event change and update that is broadcast in the scope.

If you are using angularjs' router (a.k.a., ngRoute):

$scope.$on('$routeChangeUpdate', getItem);
$scope.$on('$routeChangeSuccess', getItem);

If you are using ui.router:

$scope.$on('$stateChangeUpdate', getItem);
$scope.$on('$stateChangeSuccess', getItem);

Note: in ui.router you can add cache: false on the state declaration and it'll prevent the controller and the view to be cached.



来源:https://stackoverflow.com/questions/45740557/refresh-of-scope-after-remote-change-to-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!