Working with variable out of scope by AJAX call

I have the following code:

var User = {
  get: function (options) {
    var self = this;

    $.ajax({
      url: options.url,
      success: function (data, response) {
        self.nextPageUrl = data.pagination.next_page;
        options.success(data, response);
      }
    });
  },
  nextPage: function (success) {
    this.get({
      url: this.nextPageUrl, 
      success: success
    });
  }
}

User.get({
  url: 'https://cache.getchute.com/v2/albums/aus6kwrg/assets',
  success: function (data, response) {
    // Through `data.pagination.next_page` I can get the URL
    // of the next page.
  }
});

User.nextPage({
  success: function (data, response) {
    // Here I want to make the same request but using the next_page
    // based on the next related to the previous' one.
  }
});

      

Problem

Basically, I want to perform an operation nextPage()

based on an antecessor ( User.get()

) request , but because of its asynchrony, the method nextPage()

doesn't know the property this.nextPageUrl

- it returns undefined

> as expected.

Finally, the question is, could someone think to keep the current syntax flow, but solve this approach? Actually, is there a way?

And no, I cannot make a synchronous request.

General knowledge

I was thinking of using an event mechanism to deal with this: when the request is done and .nextPage()

called, try listening to the event that should be fired for x seconds , then I expect the property to this.nextPageUrl

be available in that event scope.

What do you guys think?

DISCLAIMER: The logic is next_page

pre-processed by the server and only then sent to the client. I have no way to use a behavioral increment / decrement operation.


If you'd like to play around with this issue, click here for the jsFiddle .

+3


source to share


3 answers


jsFiddle Demo

There are several options. You could bind the property setter to call as well nextPage

, you could poll from the call nextPage

every n milliseconds until the nextPageUrl property is full, you could use a promise, you could use nextPageQueue.

I think a queue might be the simplest form of completing this. I also think it might be helpful for the user to save some local variables in this situation and that the use of a function object might be stricter with that.

It will look like



var User = new function(){
  var pageQueue = [];
  var get = this.get = function (options) {
    $.ajax({
      url: options.url,
      dataType: 'JSON',
      success: function (data, response) {
        options.success(data, response);
        var nextPageUrl = data.pagination.next_page;
        if( pageQueue.length > 0 ){
         pageQueue[0](nextPageUrl);
         pageQueue.splice(0,1);
        }
      }
    });
  };
  var nextPage = this.nextPage = function (options) {
    pageQueue.push(function(nextPageUrl){
      get({
        url: nextPageUrl,
        success: options.success
      });
    });
  };
};

      

and your challenges won't change.

User.get({
  url: 'https://cache.getchute.com/v2/albums/aus6kwrg/assets',
  success: function (data, response) {
    // Through `data.pagination.next_page` I can get the URL
    // of the next page.
      console.log('get');
      console.log(data);
      console.log(response);
  }
});

User.nextPage({
  success: function (data, response) {
    // Here I want to make the same request but using the next_page
    // based on the next related to the previous' one.
    console.log('next');
    console.log(data);
    console.log(response);
  }
});

      

+1


source


You can get a reference to the user object before making the asynchronous request.



var User = { get: function (options) { var self = this; $.ajax({ url: options.url, success: function (data, response) { self.nextPageUrl = data.pagination.next_page; options.success(data, response); } }); },

+1


source


You can change your getter and exclude your nextPage method entirely:

var User = {
  url: 'https://cache.getchute.com/v2/albums/aus6kwrg/assets',
  get: function (options) {
    var self = this;

    self.pageXhr = $.ajax({
      url: self.nextPageUrl ? self.nextPageUrl : self.url,
      dataType: 'JSON',
      success: function (data, response) {
        self.nextPageUrl = data.pagination.next_page;
        self.pageXhr = false;
        options.success(data, response);
      }
    });
  }
}

      

Then whenever you call User.get it will either call the current page or the next page. I'm not sure about the context of when you want subsequent pages, but if you need requests to be queued, you can wait for the existing request to complete before starting the next request. For example:

if (self.pageXhr) {
   self.pageXhr = self.pageXhr.then(function() {
      return $.ajax({
          url: self.nextPageUrl ? self.nextPageUrl : self.url,
          dataType: 'JSON',
          success: function (data, response) {
            self.nextPageUrl = data.pagination.next_page;
            options.success(data, response);
          }
      });
   });
}

      

0


source







All Articles