Share async data between controllers without making multiple requests

后端 未结 4 1232
盖世英雄少女心
盖世英雄少女心 2021-02-14 20:21

I\'m trying to make a single $http request to get one of my JSON files and use the data across all my controllers.

I saw on egghead.io how to share data acr

相关标签:
4条回答
  • 2021-02-14 20:31

    Since you are using a promise, to access the data returned by promise use the callback syntax

    function appInstallerDetailCtrl($scope, $routeParams, Data) {
      $scope.appId = $routeParams.appId;
       Data.then(function(returnedData) {
            $scope.apps=returnedData;
            console.log($scope.apps);
            for (var i in $scope.apps)
               console.log(i)   
       });   
    }
    

    Make sure this

    defer.resolve(result.data.versions.version);
    

    resolve returns array, for the above code to work. Or else see what is there in data and ajust the controller code.

    0 讨论(0)
  • 2021-02-14 20:32

    My issue was that I didn't want to wait for resolve before loading another controller because it would show a "lag" between controllers if the network is slow. My working solution is passing a promise between controllers via ui-router's params and the data from promise can be loaded asynchronously in the second controller as such:

    app.route.js - setting the available params to be passed to SearchController, which shows the search results

            .state('search', {
                url: '/search',
                templateUrl: baseDir + 'search/templates/index.html',
                controller: 'SearchController',
                params: {
                    searchPromise: null
                }
            })
    

    landing.controller.js - controller where the user adds search input and submits

        let promise = SearchService.search(form);
        $state.go('search', {
            searchPromise: promise
        });
    

    search.service.js - a service that returns a promise from the user input

        function search(params) {
            return new Promise(function (resolve, reject) {
                $timeout(function() {
                    resolve([]) // mimic a slow query but illustrates a point
                }, 3000)
            })
        }
    

    search.controller.js - where search controller

        let promise = $state.params.searchPromise;
    
        promise.then(r => {
            console.log('search result',r);
        })
    
    0 讨论(0)
  • 2021-02-14 20:34

    I found the way not sure weather it is a best approach to do it or not.

    In HTML

    <body ng-app="myApp">
      <div ng-controller="ctrl">{{user.title}}</div>
      <hr>
      <div ng-controller="ctrl2">{{user.title}}</div>
    </body>
    

    In Javascript

     var app = angular.module('myApp', []);
       app.controller('ctrl', function($scope, $http, userService) {
          userService.getUser().then(function(user) {
            $scope.user = user;
          });
        });
    
       app.controller('ctrl2', function($scope, $http, userService) {
          userService.getUser().then(function(user) {
            $scope.user = user;
          });
        });
    
       app.factory('userService', function($http, $q) {
        var promise;
        var deferred = $q.defer();
          return {
            getUser: function() {
              if(!promise){     
              promise = $http({
                  method: "GET",
                  url: "https://jsonplaceholder.typicode.com/posts/1"
                }).success(function(res) {
                    data = res.data;
                  deferred.resolve(res);
                })
                .error(function(err, status) {
                  deferred.reject(err)
                });
              return deferred.promise;
              }
              return deferred.promise;
            }
          }
        });
    

    This will exactly make only 1 HTTP request.

    0 讨论(0)
  • 2021-02-14 20:47

    I like to store my data in the service, and return a promise to the controllers, because usually you need to deal with any errors there.

    app.factory('Data', function($http, $q) {
       var data = [],
           lastRequestFailed = true,
           promise;
       return {
          getApps: function() {
             if(!promise || lastRequestFailed) {
                // $http returns a promise, so we don't need to create one with $q
                promise = $http.get('apps.json')
                .then(function(res) {
                    lastRequestFailed = false;
                    data = res.data;
                    return data;
                }, function(res) {
                    return $q.reject(res);
                });
             }
             return promise;
          }
       }
    });
    
    .controller('appInstallerListCtrl', ['$scope','Data',
    function($scope, Data) {
        Data.getApps()
        .then(function(data) {
            $scope.data = data;
        }, function(res) {
            if(res.status === 500) {
                // server error, alert user somehow
            } else { 
                // probably deal with these errors differently
            }
        });
    }]);
    

    Any callbacks that are registered after a promise has been resolved/rejected will be resolved/rejected immediately with the same result/failure_reason. Once resolved/rejected, a promise can't change (its state). So the first controller to call getApps() will create the promise. Any other controllers that call getApps() will immediately get the promise returned instead.

    0 讨论(0)
提交回复
热议问题