Backbone + Promises - How to fetch after post

2019-09-10 00:43发布

问题:

I have a model which has two functions - one posts, and one gets.

The fetch:

fetch: function (options) {
  var self = this;

  return P1Comm.get({
    'dataType': 'json',
    'processAjaxResponse': self.processAjaxResponse,
    'onStatusInvalid': function (e) {
      P1.log(e, 'status');
    },
    'onSuccess': options.success,
    'onError': function (e) {
      P1.log(e);
    },
    'sourceURL': P1.API_APPS_ROOT + 'v1.0/accepted-terms'
  });
},

The post:

acceptTerms: function (appId) {
  var self = this;

  self.set({
    'app_id': parseInt(appId,10)
  });
  self.createEdit(self.toJSON(), {
  }).pipe(function () {
    var def = $.Deferred();
    var saveOpts = {
        dataType: 'json',
        stringify: true,
        contentType: 'application/json',
        processData: false,
        processAjaxResponse: self.processAjaxResponse
      };
    self.save(self.toJSON(), saveOpts);
    return def.promise();
  });
},

Calling the post from the view: acceptAppTerms.acceptTerms(1);

These both work in their own right but I want to change this so that: - Make the POST acceptTerms() - Then make the GET fetch() - Then call another function

I think it would be something like this (at least for the first two points):

acceptAppTerms.acceptTerms(id).then(function () {
  this.launchApp(event, id);
});

But I get the error of Uncaught TypeError: Cannot read property 'then' of undefined

I am not that good at front-end - can someone point me in the right direction?

Thanks

UPDATE:

fetchAcceptedTerms: function () {
  var self = this;
  this.appAcceptedTerms = new T1AppAcceptedTerms();
  this.acceptedTerms = new AppAcceptedTerms();

  this.acceptedTerms.fetch({
    success: function (data) {
      if (data.meta.status === 'success') {
        self.appAcceptedTerms.set(data.data);
      }
    }
  });
},

Example below works but it breaks the setting of the data into the model.

回答1:

The reason you get the error is because your acceptTerms doesn't return anything, or in other words returns undefined which doesn't have a then() method.

Your code should be something like:

fetch: function(options) {
    var self = this;
    return P1Comm.get({
      dataType: 'json',
      processAjaxResponse: self.processAjaxResponse,
      onStatusInvalid: function(e) {
        P1.log(e, 'status');
      },
      onSuccess: options.success,
      onError: function(e) {
        P1.log(e);
      },
      sourceURL: P1.API_APPS_ROOT + 'v1.0/accepted-terms'
    });
},

acceptTerms: function(appId) {
    var self = this;
    self.set({
      'app_id': parseInt(appId, 10)
    });

    return self.createEdit(self.toJSON(), {}).pipe(function() {
    //---------------------------------------^ better use .then()
      var saveOpts = {
        dataType: 'json',
        stringify: true,
        contentType: 'application/json',
        processData: false,
        processAjaxResponse: self.processAjaxResponse
      };
      return self.save(self.toJSON(), saveOpts);
    });
},

This code asummes that P1Comm.get, self.createEdit and self.save returns a promise object. If they don't then you need to create a Deferred object and return it's promise from these functions. And inside the success/error callbacks of their asynchronous actions you need to resolve/reject the promise accordingly.

I'd also like to mention that .pipe() is a deprecated method, you should use then() unless you're using ancient version of jQuery.