简体   繁体   中英

Angular Factory and Service work but not as expected

My app is looking up google place details and displaying some of the information. I have a list of place id's in a json file broken down by type of establishment. A factory accesses and makes available the ids to the controller. I also have a service that loops through all the id's, looking up the details and adding them to an object that is made available to the controller.

I can get it to work in the sense that I can access the json data, look up the details, and return the object. However, no matter how I do it, if I try and return multiple objects, one for each type of business, I get all the businesses together or an error (more on that in a minute).

I have structured this a number of ways but I will show the code for 2 ways that I have tried. I'm new to Angular so I may have this completely wrong and not even using services and factories correctly so please go easy on me.

locations.json

{
  "restaurants": {
    "Michaels": "ChIJwaTJAL4n5IgRgyJupbpQhjM",
    "Collage": "ChIJw5HgNzAm5IgRqbkEqKXIpC4",
    "Scarlet": "ChIJT9ImkZUn5IgREb1hYwKA1Nc",
    "Maya": "ChIJofgqBJYn5IgRVa-HQvp6KDk",
    "Ice": "ChIJnXpQpewn5IgR7k9yxWXUu1M",
    "Sangrias": "ChIJITcc_ZUn5IgR90iEna6FRGM",
    "Columbia": "ChIJ8xR18JUn5IgRfwJJByM-quU",
    "Harrys": "ChIJ8aLBaJYn5IgR60p2CS_RHIw"
  },
  "bars":
    {
      "Scarlet": "ChIJT9ImkZUn5IgREb1hYwKA1Nc",
      "Lion": "ChIJqVCL_b0n5IgRpVR5CFZWi4o",
      "Tradewinds": "ChIJpwF4ZJYn5IgRTDzwBWvlSIE",
      "Ice": "ChIJnXpQpewn5IgR7k9yxWXUu1M",
      "Stogies": "ChIJlwkiApYn5IgR6XVFMyqLAS4",
      "Rondeazvous": "ChIJkz3V7pUn5IgRQhui26imF1k",
      "Meehan": "ChIJK8NZGZYn5IgRA91RrGETwrQ",
      "Sangrias": "ChIJITcc_ZUn5IgR90iEna6FRGM",
      "NoName": "ChIJA-VeCb4n5IgRmbuF8wdOGaA",
      "StGeorge": "ChIJ4yo36JUn5IgRXgiRD7KMDe0"
    }
}

Method 1

locations.js

angular.module('app.locations', [])
  .factory('restsFact', function($http){
    var restaurants = [];

    return {
      getRests: function(){
        return $http.get('locations.json').then(function(response){
          restaurants = response.data.restaurants;
          return restaurants;
        });
      }
    };
  })
  .factory('barsFact', function($http){
    var bars = [];

    return {
      getBars: function() {
        return $http.get('locations.json').then(function(response){
          bars = response.data.bars;
          return bars;
        });
      }
    };
  })
  .service('locationsService', function (ngGPlacesAPI) {
    var x, id, details, push,  placeDetails = [];

    // Takes list of specific type of locations as argument and looks up Place details for each location
    this.details = function(type) {
      for (x in type) {
        if (type.hasOwnProperty(x)) {
          id = type[x];
          ngGPlacesAPI.placeDetails({placeId: id}).then(push);
        }
      }
      return placeDetails;
    };

    push = function (data) {
      details = data;
      placeDetails.push(details);
    };

  });

Controllers

.controller('RestCtrl', function($scope, locationsService, restsFact) {

  // Location Details Object
  restsFact.getRests().then(function(locs){
    $scope.restaurants= locationsService.details(locs);
  });

})

//
// Bar Controller
//
.controller('BarsCtrl', function($scope, locationsService, barsFact){

  // Locations Details Object
  barsFact.getBars().then(function(locs){
    $scope.bars = locationsService.details(locs);
  });

})

Method 2

With this method I can load one page but if I move to the next I get an error: [$rootScope:inprog] $digest already in progress. I read up on the error and get the idea of why I get it but just not sure how to go about fixing it.

locations.js

angular.module('app.locations', [])
  .factory('locationsFact', function($http){
    var locations = [];

    return {
      getlocations: function(){
        return $http.get('locations.json').then(function(response){
          locations = response;
          return locations;
        });
      }
    }
  })
  .service('locationsService', function (ngGPlacesAPI) {
    var x, id, details, push,  placeDetails = [];

    // Takes list of specific type of locations as argument and looks up Place details for each location
    this.details = function(type) {
      for (x in type) {
        if (type.hasOwnProperty(x)) {
          id = type[x];
          ngGPlacesAPI.placeDetails({placeId: id}).then(push);
        }
      }
      return placeDetails;
    };

    push = function (data) {
      details = data;
      placeDetails.push(details);
    };

  });

Controller

.controller('locationsCtrl', function($scope, locationsService, locationsFact){

  // Locations Details Object
  locationsFact.getlocations().then(function(locs){
    $scope.restaurants = locationsService.details(locs.data.restaurants);
    $scope.bars = locationsService.details(locs.data.bars);
  });

})

So I read a lot over the last week and learned a lot as well. I completely rewrote that mess up above into something resembling decent code, there were a lot of problems with it originally. I got everything working anyway. Here is how it looks now.

Factory

angular.module('app.factories', [])

  .factory('data', function($http){
    // Get JSON With Place ID's and create array of
    // place id objects for each category
    var places = {};

    places.ids = function(){
      return $http.get('locations.json')
        .success(function(data){
          places.rests = data.restaurants;
          places.bars = data.bars;
          places.lodg = data.lodging;
          places.att = data.attractions;
        });
    };
    return places;
  })

  .factory('details', function(ngGPlacesAPI, $q){
    var details = {};

    // Split ID Array into array of arrays <= 10.
    // Google won't return more than 10 details request at one time.
    details.process = function(type) {
      var idSets = {},
          size = 10,
          i, j, k;

      for (i=0, j=type.length, k=0; i<j; i+=size){
        idSets[k] = type.slice(i, i+size);
        k++;
      }
      return idSets;
    };

    // Lookup Details by Place ID
    // Loop through ID array and return array of details objects
    details.getDetails = function(idSet, pageNum) {
      var page = idSet[pageNum],
          promises = [];

      for(var i=0; i<page.length; i++) {
        promises.push(ngGPlacesAPI.placeDetails({placeId: page[i][i]}));
      }
      return $q.all(promises);
    };

    // Return Details Object
    return details;
  });

Controller

//
// Restaurants Controller
//
.controller('restaurantsCtrl', function(details, data, $scope) {
  var vm = this;

  // Get JSON file with placeIds and set some variables
  data.ids().then(function() {
    var page = details.process(data.rests),
        pageNum = 0,
        numPages = page.length;
    vm.moreData = true;


    // Loads more place details on scroll down
    vm.loadMore = function() {
      if (pageNum <= numPages - 1) {
        pageNum++;
        details.getDetails(page, pageNum).then(function(response) {
          vm.rests.push(response);
          vm.$broadcast('scroll.infiniteScrollComplete');
        });
      }else{vm.moreData=false}
    };

    // Load first page of place details
    details.getDetails(page, pageNum).then(function(response){
      vm.rests = response;
      console.log(vm.rests);
    });

    // Watches for when to load more details
    $scope.$on('$stateChangeSuccess', function(){
      vm.loadMore();
    });

  });
})

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM