4

I am totally new to angularjs and ionic. I try to store 4 values which i receive from a factory call into 4 variables which i need to use as parameters for my $http get call in another function:

here are the 4 variables defined at the beginning of my controller:

var firstId;
var firstTimestamp;
var lastId;
var lastTimestamp; 

I receive the data from the following call to my factory and assign the data to the variables:

ContentFactory.getAlbums().then(function(albums){

   $scope.albums = albums;

   firstId = albums.first_id;
   firstTimestamp = albums.first_timestamp;
   lastId = albums.last_id;
   lastTimestamp = albums.last_timestamp;
});

I try then to use these variables as parameters for another call to my factory (loadOlderAlbums is called in the view):

$scope.loadOlderAlbums = function(lastId, lastTimestamp) {
 ContentFactory.getOlderAlbums(lastId, lastTimestamp).then(function(albums){
    $scope.albums = $scope.albums.concat(albums);
    $scope.$broadcast('scroll.infiniteScrollComplete');
 });
};

The variables lastId & lastTimestamp are undefined when checking my factory:

getOlderAlbums : function(lastId, lastTimestamp){
        console.log(lastId); // lastId is undefined
        return $http.get('http://api.domain.xxx/albums/city/1? &direction=before&id=' + lastId + '&time=' + lastTimestamp + '&api_key=******&lang=en').then(function(response) {
                albums = response.data;
                return albums;
        });
    }

in the console i see the following error:

GET http://api.domain.xxx/albums/city/1?&direction=before&id=undefined&time=undefined&api_key=***&lang=en 500 (Internal Server Error)

because id & time are undefined.

here is the complete controller:

.controller('PicturesCtrl', function($scope, $ionicLoading,  ContentFactory) {

$scope.albums = [];

var firstId;
var firstTimestamp;
var lastId;
var lastTimestamp; 

ContentFactory.getAlbums().then(function(albums){
  $scope.albums = albums;
  firstId = albums.first_id;
  firstTimestamp = albums.first_timestamp;
  lastId = albums.last_id;
  lastTimestamp = albums.last_timestamp;

  // console.log(firstId);  -> values are correctly stored
  // console.log(firstTimestamp); -> values are correctly stored
  // console.log(lastId); -> values are correctly stored
  // console.log(lastTimestamp); -> values are correctly stored

 });


$scope.loadOlderAlbums = function(lastId, lastTimestamp) {
 ContentFactory.getOlderAlbums(lastId, lastTimestamp).then(function(albums){
    $scope.albums = $scope.albums.concat(albums);
    $scope.$broadcast('scroll.infiniteScrollComplete');
 });
};

})

and the factory:

.factory('ContentFactory', function($http) {

var albums = [];

return {



    getAlbums : function(){
        return $http.get('http://api.domain.xxx/albums/city/1?lang=en&api_key=***').then(function(response) {
                albums = response.data;
                return albums;
        });
    },


    getOlderAlbums : function(lastId, lastTimestamp){
        console.log(lastId); // lastId is undefined
        return $http.get('http://api.domain.xxx/albums/city/1?&direction=before&id=' + lastId + '&time=' + lastTimestamp + '&api_key=***&lang=en').then(function(response) {
                albums = response.data;
                return albums;
        });
    }
   }
})

Any help to figure out why the value of the variables are not passed to the second factory call are really appreciated. Its probably a logical issue as i'm a total newbie ;)

UPDATE:

Please find below a sample response which I received from my first $http GET call in Content.Factory.getAlbums

{
"city_id": 1,
"total_pages": 199,
"total_results": 3977,
"first_id": 15448,
"first_timestamp": 1437230820,
"results": [
    {
        "album_id": "15448",
        "title": "MAD pres. Splash The Madness Party at Aftermoon",
        "description": "The MAD crew is back and returned to Aftermoon for a night of Melbourne Bounce, Hip Hop, Big Room, Electro- and Progressive House. At the decks were Dam-Sib-Dao, Beatender, Madz Mellow & Odyszey, supported by Mc Ben10.",
        "photographer_id": "8",
        "photographer_name": "ploy",
        "image_count": "88",
        "cover_image": "5dd26da7f37da641d775568d2e98ae44.jpg",
        "date": "2015-07-18 21:47:00",
        "location_id": "705",
        "location_name": "Aftermoon"
    },
    {
        "album_id": "15446",
        "title": "Superhero Charity Party at KU DÉ TA Bangkok",
        "description": "KU DÉ TA Bangkok and the charity organisation \"Habitat for Humanity Thailand\" joined forces for the SUPERHERO “CHARITY PARTY\". Habitat for Humanity Thailand improves the quality of Thai people’s lives through building homes and transforming communities. Entry is Free, but there guests are invited to do a FREE-WILL DONATION of which 100% will go to Habitat for Humanity Thailand to build houses under the program “Make Her Day” in Pathumthani.",
        "photographer_id": "15",
        "photographer_name": "win",
        "image_count": "176",
        "cover_image": "742a0065d046418041175ff8005d7174.jpg",
        "date": "2015-07-18 18:46:00",
        "location_id": "809",
        "location_name": "KU DÉ TA"
    }
],
"last_id": 15427,
"last_timestamp": 1437062520
}

The $scope.loadOlderAlbums is called in my view (Ionic infinite scroll)

<ion-infinite-scroll
  on-infinite="loadOlderAlbums()"
  distance="1%">
</ion-infinite-scroll>
5
  • Does $scope.albums actually get loaded? It would help if you could show us what actually gets loaded into $scope.albums. Commented Jul 19, 2015 at 14:32
  • Where are you actually calling $scope.loadOlderAlbums()? Would be first place to look if arguments are undefined when you call it Commented Jul 19, 2015 at 14:35
  • Install batarang so that you can inspect and compare the scopes. Commented Jul 19, 2015 at 15:05
  • @Daniel Cottone Thanks for trying to help me out. I have updated my question with a sample response from my GET call. $scope.albums is loaded correctly Commented Jul 20, 2015 at 9:33
  • @charlietfl [code]$scope.loadOlderAlbums() is called in my view. Commented Jul 20, 2015 at 9:34

1 Answer 1

1

Change your $scope method for fetching the older albums. You are expecting the parameters to be passed in - but by the time you call it they should already be defined in your controller scope, so there really isn't a need to do so.

And seeing as how you are not exposing the lastId or lastTImestamp onto this or $scope, that leads me to believe that in your view you are calling the method like so:

<button ng-click="loadOlderAlbums()">Load more albums</button>

In which case, lastId and lastTimestamp were never passed to your $scope function, and it just wont work.

Something like this should do it:

$scope.loadOlderAlbums = function() {
 ContentFactory.getOlderAlbums(lastId, lastTimestamp).then(function(albums){
    $scope.albums = $scope.albums.concat(albums);
    $scope.$broadcast('scroll.infiniteScrollComplete');
 });
};

Now, you won't have to pass lastId or lastTimestamp into your function (as you've previously required).


If you are certain that the getAlbums() call has fired before you start scrolling, the following should work just fine (redacted a bunch of code to highlight the main point):

var lastId, lastTimeStamp: 

getAlbums().then(function (res) {
  lastId = res.lastId;
  lastTimeStamp = res.lastTimeStamp;
});

/** Later, called from the view **/
function loadOlderAlbums () { // <-- Kill the arguments.
  $http.get('path' + lastId + lastTimeStamp).then(function (res) {
    /** woop woop! **/ 
  }); 
}

Otherwise - you would need to setup a failsafe for that scenario. You could either go with another promise, or something very simple like so for the time being to possibly rule it out:

var loaded = false;

function getAlbums () {
   $http.get('albums').then(function (res) {
     /** set the ID's and timestamps **/ 
     loaded = true;
   });
}

function loadOlderAlbums () {
  if (!loaded) {
    throw new Error('Yep, nope. We have to get some other albums first. Sorry!');
  }

  /** your old loadOlderAlbums implementation **/ 
}

By adding that throw statement in there, you can verify that there is:

  • Either a race condition in the storing(through getAlbums)/usage(through loadOlderAlbums) of the lastId and lastTimeStamp variables.
  • Or it magically started working.

Since you are using Ionic - which in turn uses ui-router; You could move the call to getAlbums into a resolve block and you would be ensured that the data is loaded into your controller before you start scrolling.

That could look something like:

.state('...', {
  controller: 'PicturesCtrl',
  resolve: {
    preloadedAlbums: function (ContentFactory) { // available for DI later into your controller.
      return ContentFactory.getAlbums().then(function (response) {
        return {
          albums:  response,
          firstId: response.first_id,
          firstTimeStamp: response.first_timestamp,
          lastId: response.last_id,
          lastTimeStamp: response.last_timestamp
        }; 
      });
    }
  }
}

Now, any time you try to navigate to said state - the resolve object will get its stuff before the controller gets invoked. As such, you are ensured that the data is present before the user starts scrolling away in the scope of your PicturesCtrl, and the parameters required for loadMoreAlbums will be there.

Your PicturesCtrl could now look something along the lines of:

.controller('PicturesCtrl', function ($scope, $ionicLoading,  ContentFactory, preloadedAlbums) {

  $scope.albums = preloadedAlbums;

  var lastId = preloadedAlbums.lastId;
  var lastTimeStamp = preloadedAlbums.lastTimeStamp; 
  /** etc **/ 
});

I would try out the first suggestion (with a throw) to ensure that it is a matter of the getAlbums promise not having been resolved that's causing your issue. Then I would consider moving onto a resolve block.


If that doesn't root out the cause of your problems, I would blast the codebase with debugger's and step through from start to finish to verify what is actually going on.

Sign up to request clarification or add additional context in comments.

5 Comments

Dear Kaspar, thank you for trying to help me, really appreciate it.
I just saw the edits you made to your question, it would appear that I was right on the money :) If you call the function like you have it implemented (in the controller) right now (from the view) without any passed parameters - lastId and lastTimestamp will be undefined.
Yes the method is called in my view (it's part of ionic infinite scroll). I updated my question to include the view part. lastId and lastTimestamp are part of the first GET response from ContentFactory.getAlbums(). I tried to change my code to include your suggestions but it's still not working. In the second call to my API lastId & lastTimestamp are still undefined. Any more help would be really appreciated.
See my latest edit. Some suggestions on how you can root out / localise the issue, and possibly fix it (depends on what the issue really is of course).
thanks a lot for your awesome update ;) I will have a look at it and play around. Promise to give you feedback as soon as possible.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.