2015-07-28 16 views
7

Tôi có một trường hợp trong đó cuộc gọi fetch() của mô hình sẽ trả về dữ liệu mà từ đó một thuộc tính sẽ được chuyển đến API khác và loại trả về từ API đó sẽ là dữ liệu thực sự cần thiết.Mô hình xương sống: Yêu cầu Ajax trong ghi đè phân tích

var Issue = Backbone.Model.extend({ 
    urlRoot: 'https://api.github.com/repos/ibrahim-islam/ibrahim-islam.github.io/issues', 
    parse: function(response, options){ 
     var markdown = new Markdown({ text : response.body }); 
     markdown.fetch({ 
      contentType: 'application/json', 
      type: 'POST', 
      data: JSON.stringify(markdown.toJSON()), 
      success: function(data){ 
       response.body = data; 
      } 
     }); 
     return response; 
    } 
}); 

var Markdown = Backbone.Model.extend({ 
    defaults:{ 
     'text': '', 
     'mode' : 'markdown' 
    }, 
    url: 'https://api.github.com/markdown' 
}); 

Vì vậy, khi một Issue sẽ được lấy:

var issue = new Issue({id: 1}); 
issue.fetch().then(function(){ 
    //do stuff 
}); 

Nó sẽ có một tài sản của body chứa văn bản cú pháp markdown do đó tôi cần phải vượt qua để API khác và nhận được câu trả lời rằng đó sẽ được chuyển xuống để xem.

Như đã thấy ở trên, tôi đã thử ghi đè parse nhưng loại trả về phải là đối tượng và fetch sẽ là async vì vậy tôi có thể làm gì ở đây để thực hiện công việc này?

LƯU Ý: Tôi biết tổng hợp dữ liệu trong máy chủ và sau đó nhận dữ liệu sẽ là ý tưởng tốt nhất nhưng điều đó không thể thực hiện được.

+0

'JSON.stringify (markdown.toJSON()) '- đó sẽ là đôi mã hóa, bạn có chắc bạn muốn điều đó? – Tomalak

+0

@Tomalak Chỉ sau đó yêu cầu của tôi đi qua. Nhưng tôi sẽ thử lại. Cảm ơn lời nhắc. – lbrahim

Trả lời

4

Bạn có thể ghi đè số sync method trong mô hình Issue để kết nối các yêu cầu của mình.

var Issue = Backbone.Model.extend({ 
    urlRoot: 'https://api.github.com/repos/ibrahim-islam/ibrahim-islam.github.io/issues', 

    sync: function(method, model, options) { 
     if (method !== 'read') 
      return Backbone.sync.apply(this, arguments); 

     // first request 
     var xhr = Backbone.ajax({ 
      type: 'GET', 
      dataType: 'json', 
      url: _.result(model, 'url') 
     }); 

     // second request 
     return xhr.then(function (resp1) { 
      var markdown = new Markdown({text : resp1.body || 'body'}); 
      var data = markdown.toJSON(); 

      // the callback to fill your model, will call parse 
      var success = options.success; 

      return Backbone.ajax({ 
       url: _.result(markdown, 'url'), 
       dataType: 'html', 
       contentType: 'application/json', 
       type: 'POST', 
       data: data 
      }).then(function(resp2) { 
       // sets the data you need from the response 
       var resp = _.extend({}, resp1, { 
        body: resp2 
       }); 

       // fills the model and triggers the sync event 
       success(resp); 

       // transformed value returned by the promise 
       return resp; 
      }); 
     }); 
    } 
}); 

Các tùy chọn băm truyền cho Model.sync chứa callbacks để model.parse, bạn có thể sử dụng nó để thiết lập các thuộc tính trên mô hình của bạn khi bạn hài lòng với dữ liệu của bạn.

Và một bản demo http://jsfiddle.net/puwueqe3/5/

+0

Điều này có vẻ tốt hơn đề xuất của tôi. +1 từ tôi. – ivarni

+0

@nikoshr Tôi cần cả đối tượng chính và sau đó là kết quả phân tích cú pháp markdown để tôi có thể thay thế thuộc tính 'body'. Xin vui lòng xem fiddle này: http: // jsfiddle.net/ibrahimislam/puwueqe3/2/ – lbrahim

+1

@lbrahim Tôi bằng cách nào đó đã bỏ lỡ rằng yêu cầu thứ hai đã trả về HTML chứ không phải JSON. Đã cập nhật – nikoshr

2

Tôi nghĩ rằng bạn sẽ phải ghi đè lên fetch của mô hình để có được điều này để làm việc

Hãy xem xét những gì mặc định lấy trông giống như:

fetch: function(options) { 
    options = _.extend({parse: true}, options); 
    var model = this; 
    var success = options.success; 
    options.success = function(resp) { 
    var serverAttrs = options.parse ? model.parse(resp, options) : resp; 
    if (!model.set(serverAttrs, options)) return false; 
    if (success) success.call(options.context, model, resp, options); 
    model.trigger('sync', model, resp, options); 
    }; 
    wrapError(this, options); 
    return this.sync('read', this, options); 
}, 

(github)

Đó thực hiện sẽ không hỗ trợ một phiên bản async của model.parse, nhưng vì bạn tạo một lớp mô hình bằng cách sử dụng .extend, bạn có thể ghi đè lên điều này bằng cách triển khai của riêng bạn để cho phép xem xét những gì nó làm. Phải mất một đối tượng options, tạo một cuộc gọi lại success và sau đó ủy quyền cho Backbone.Sync.

Đó là cuộc gọi lại gọi parse và đó là những gì cần phải được thực hiện để hỗ trợ async.

Cách nhanh nhất, bẩn nhất để thực hiện việc này có lẽ là chỉ sao chép và sửa đổi lần tìm nạp mặc định hiện có.

var MyModel = Backbone.Model.extend({ 

    fetch: function(options) { 
     options = _.extend({parse: true}, options); 
     var model = this; 
     var success = options.success; 
     options.success = function(resp) { 

     function parser(resp, options, cb) { 
      ...do your async request stuff and call cb with the result when done... 
     } 

     parser(resp, options, function(result) { 
      if (!model.set(result, options)) return false; 
      if (success) success.call(options.context, model, resp, options); 
      model.trigger('sync', model, resp, options); 
     }); 

     }; 
     wrapError(this, options); 
     return this.sync('read', this, options); 
    } 

}); 

Đây chỉ là ví dụ về cách bạn có thể thử giải quyết vấn đề này. Tôi đã không thử nghiệm nó và nó có thể không hoạt động nhưng tôi không thấy bất kỳ lý do rõ ràng ngay lập tức tại sao nó không nên.

Các vấn đề liên quan