2013-08-16 21 views
10

Tôi tò mò là lý do tại sao bản ghi chứa trong tập kết quả của phản hồi Model.save() không trả lại dữ liệu được liên kết cập nhật đúng cách, mặc dù dữ liệu cập nhật được chứa trong máy chủ phản ứng ...ExtJS 4.1 - Trả về dữ liệu được liên kết trong Model.Save() Response

Ví dụ mẫu & cửa hàng Định nghĩa:

Ext.define("App.model.test.Parent",{ 
    extend: 'Ext.data.Model', 
    requires: ['App.model.test.Child'], 
    fields: [ 
      {name: 'id', type: 'int' }, 
      {name: 'name', type: 'string'}, 
      {name: 'kids', type: 'auto', defaultValue: []} 
    ], 
    idProperty: 'id', 

    hasMany: [{ 
      foreignKey: 'parent_id', 
      model: 'App.model.test.Child', 
      associationKey: 'kids', 
      name: 'getKids' 
    }], 

    proxy: { 
     type: 'ajax', 
     api : { 
      create: '/service/test/create/format/json', 
      read : '/service/test/read/format/json', 
      update : '/service/test/update/format/json' 
     }, 

     reader: { 
      idProperty  : 'id', 
      type   : 'json', 
      root   : 'data',   
      successProperty : 'success',  
      messageProperty : 'message' 
     }, 

     writer: { 
      type   : 'json', 
      writeAllFields : true 
     } 
    } 
}); 

Ext.define("App.model.test.Child",{ 
    extend: 'Ext.data.Model', 
    fields: [ 
     {name: 'id', type: 'int' }, 
     {name: 'name', type: 'string'}, 
     {name: 'parent_id', type: 'int'} 
    ] 
}); 

Ext.define("App.store.test.Simpson",{ 
    storeId: 'TheSimpsons', 
    extend: 'Ext.data.Store', 
    model : 'App.model.test.Parent', 
    autoLoad: true, 
    autoSync: false 
}); 

ứng dụng máy chủ đáp ứng với yêu cầu READ của proxy với một mô hình duy nhất, và các dữ liệu liên quan của nó. Đây là tất cả làm việc hunky dory!

Server Response để ĐỌC Yêu cầu

{ 
"data":{ 
    "id":1, 
    "name":"Homer Simpson", 
    "children":{ 
     "1":{ 
      "id":1, 
      "name":"Bart Simpson" 
     }, 
     "2":{ 
      "id":2, 
      "name":"Lisa Simpson" 
     }, 
     "3":{ 
      "id":3, 
      "name":"Maggie Simpson" 
     } 
    } 
}, 
"success":true, 
"message":null 
} 

Như vậy đến nay, tất cả mọi thứ đang làm việc theo kế hoạch ...

store = Ext.create("App.store.test.Simpson"); 
homer = store.getById(1); 
kids = homer.getKids().getRange(); 
console.log("The Simpson Kids", kids); // [>constructor, >constructor, >constructor] 

CÁC HÀNH VI không mong muốn bắt đầu với lưu và cập nhật REQUESTS

Đây là phản ứng thử nghiệm của tôi cho CẬP NHẬT Yêu cầu ...

/** Server UPDATE Response */ 
{ 
"data":{ 
    "id":1, 
    "name":"SAVED Homer Simpson", 
    "kids":[{ 
     "id":1, 
     "name":"SAVED Bart Simpson", 
     "parent_id":1 
    },{ 
     "id":2, 
     "name":"SAVED Lisa Simpson", 
     "parent_id":1 
    },{ 
     "id":3, 
     "name":"SAVED Maggie Simpson", 
     "parent_id":1 
    }] 
}, 
"success":true, 
"message":null 
} 


/** Will call proxy UPDATE, response is above */ 
homer.save({ 
    success: function(rec, op){ 
     var savedRec = op.getRecords().pop(), 
      kidNames = ''; 
     console.log(savedRec.get('name')); // SAVED Homer Simpson = CORRECT! 
     Ext.each(savedRec.getKids().getRange(), function(kid){ 
      kidNames += kid.get('name') + ", "; 
     }); 
     console.log(kids); 
     //Outputs: Bart Simpson, Lisa Simpson, Maggie Simpson = WRONG!! 
    } 
}) 

Tôi nhận thấy rằng nếu tôi kiểm tra các hồ sơ được trả về bởi máy chủ, Hiệp hội Lưu trữ được tạo ra (ví dụ, getKidsStore) các hồ sơ chứa là bản gốc hồ sơ, tức là, họ không có "SAVED" trong tên của họ. Thuộc tính kids của bản ghi đã trả về, tuy nhiên, DOES thực sự chứa dữ liệu chính xác.

Nếu tôi hiểu vấn đề chính xác, đó là Ext.data.reader.Reader không cập nhật chính xác cửa hàng được liên kết với dữ liệu được liên kết có trong phản hồi .save(). Nếu vậy, theo ý kiến ​​của tôi, điều này là rất unintuitive như tôi mong đợi các hành vi tương tự như người đọc xử lý các yêu cầu store.load() và populates các cửa hàng hiệp hội được tạo ra để bắt đầu.

Có ai có thể chỉ cho tôi đúng hướng để đạt được hành vi mà tôi theo dõi không?

Tuyên bố từ chối trách nhiệm: Câu hỏi tương tự được hỏi tại đây: ExtJs 4 - Load nested data on record save nhưng không có phản hồi. Tôi cảm thấy câu hỏi của tôi phải được triệt để hơn một chút ..

EDIT: Tôi đã đăng câu hỏi này qua trên các diễn đàn Sencha: http://www.sencha.com/forum/showthread.php?270336-Associated-Data-in-Model.save()-Response

EDIT (8/23/13): tôi tái viết bài này với một ví dụ COMPLETE, cũng như phát hiện thêm ...

Trả lời

6

tôi đã tìm thấy vấn đề này, hay đúng hơn, nhầm lẫn nằm trong phương pháp getRecords() của Ext.data.Operation. Phương thức này trả về "hồ sơ được cấu hình ban đầu của hoạt động sẽ được trả lại, mặc dù proxy có thể sửa đổi dữ liệu của các bản ghi này tại một số điểm sau khi thao tác được khởi tạo." theo tài liệu.

IMO khá khó hiểu, vì bản ghi trả về thực sự được cập nhật, tuy nhiên cửa hàng liên kết được tạo và do đó dữ liệu được liên kết, không phải! Đây là những gì dẫn đến sự nhầm lẫn của tôi, nó xuất hiện như thể hồ sơ chứa dữ liệu cập nhật từ máy chủ ứng dụng, nhưng điều này không đúng.

Để hỗ trợ suy nghĩ đơn giản của tôi trong việc lấy dữ liệu được cập nhật từ HOÀN TOÀN, tôi đã thêm phương thức vào lớp Ext.data.Operation ... Tôi vừa viết phương pháp này và chưa thử nghiệm nhiều hơn đảm bảo chức năng tôi đang tìm kiếm, vì vậy hãy tự chịu rủi ro!

Hãy ghi nhớ rằng tôi không gọi store.sync(), chứ không phải tôi nhanh chóng một mô hình và gọi phương thức model.save(), vì vậy ResultSet tôi thường chỉ bao giờ chứa một hồ sơ duy nhất ...

Ext.override(Ext.data.Operation,{ 
    getSavedRecord: function(){ 
     var me = this, // operation 
      resultSet = me.getResultSet(); 

     if(resultSet.records){ 
      return resultSet.records[0]; 
     }else{ 
      throw "[Ext.data.Operation] EXCEPTION: resultSet contains no records!"; 
     } 

    } 
}); 

Bây giờ tôi có thể đạt được các chức năng sau tôi đã ...

// Get the unsaved data 
store = Ext.create('App.store.test.Simpson'); 
homer = store.getById(1); 
unsavedChildren = ''; 

Ext.each(homer.getKids().getRange(), function(kid){ 
    unsavedChildren += kid.get('name') + ","; 
}); 

console.log(unsavedChildren); // Bart Simpson, Lisa Simpson, Maggie Simpson 

// Invokes the UPDATE Method on the proxy 
// See original post for server response 
home.save({ 
    success: function(rec, op){ 
     var savedRecord = op.getSavedRecord(), // the magic! /sarcasm 
      savedKids = ''; 

     Ext.each(savedRecord.getKids().getRange(), function(kid){ 
      savedKids += kid.get('name') + ','; 
     }); 

     console.log("Saved Children", savedKids); 

     /** Output is now Correct!! 
      SAVED Bart Simpson, SAVED Lisa Simpson, SAVED Maggie Simpson 
      */ 
    } 
}); 

Sửa 12/10/13 tôi cũng đã thêm một phương pháp để Ext.data.Model mà tôi gọi là updateTo nơi quản lý việc cập nhật một kỷ lục vào cung cấp hồ sơ, cũng xử lý các liên kết. Tôi sử dụng điều này cùng với phương pháp trên getSavedRecord. Xin lưu ý rằng điều này không xử lý bất kỳ hiệp hội nào belongsTo vì tôi không sử dụng chúng trong ứng dụng của tôi, nhưng chức năng đó sẽ dễ dàng thêm vào.

/** 
* Provides a means to update to the provided model, including any associated data 
* @param {Ext.data.Model} model The model instance to update to. Must have the same modelName as the current model 
* @return {Ext.data.Model} The updated model 
*/ 
updateTo: function(model){ 
    var me = this, 
    that = model, 
    associations = me.associations.getRange(); 

    if(me.modelName !== that.modelName) 
    throw TypeError("updateTo requires a model of the same type as the current instance ("+ me.modelName +"). " + that.modelName + " provided."); 

    // First just update the model fields and values 
    me.set(that.getData()); 

    // Now update associations 
    Ext.each(associations, function(assoc){ 
    switch(assoc.type){ 
     /** 
     * hasOne associations exist on the current model (me) as an instance of the associated model. 
     * This instance, and therefore the association, can be updated by retrieving the instance and 
     * invoking the "set" method, feeding it the updated data from the provided model. 
     */ 
     case "hasOne": 
      var instanceName = assoc.instanceName, 
       currentInstance = me[instanceName], 
       updatedInstance = that[instanceName]; 

      // Update the current model's hasOne instance with data from the provided model 
      currentInstance.set(updatedInstance.getData()); 

      break; 

     /** 
     * hasMany associations operate from a store, so we need to retrieve the updated association 
     * data from the provided model (that) and feed it into the current model's (me) assocStore 
     */ 
     case "hasMany": 
      var assocStore = me[assoc.storeName], 
       getter  = assoc.name, 
       newData = that[getter]().getRange(); 

      // Update the current model's hasMany association store with data from the provided model's hasMany store 
      assocStore.loadData(newData); 
      break; 

     // If for some reason a bogus association type comes through, throw a type error 
     // At this time I have no belongsTo associations in my application, so this TypeError 
     // may one day appear if I decide to implement them. 
     default: 
      throw TypeError("updateTo does not know how to handle association type: " + assoc.type); 
      break; 
    } 
    }); 

    // Commit these changes 
    me.commit(); 

    return me; 
} 

Vì vậy, về cơ bản tôi làm điều gì đó như thế này (điều này về mặt lý thuyết sẽ là ở bộ điều khiển thứ tự)

doSaveOrder: function(order){ 
    var me = this,      // order controller 
     orderStore = me.getOrderStore(); // magic method 

    // Save request 
    order.save({ 
     scope: me, 
     success: function(responseRecord, operation){ 
      // note: responseRecord does not have updated associations, as per post 
      var serverRecord = operation.getSavedRecord(), 
       storeRecord = orderStore.getById(order.getId()); 

      switch(operation.action){ 
       case 'create': 
        // Add the new record to the client store 
        orderStore.add(serverRecord); 
       break; 

       case 'update': 
        // Update existing record, AND associations, included in server response 
        storeRecord.updateTo(serverRecord); 
       break; 
      } 
     } 
    }); 
} 

Tôi hy vọng điều này sẽ giúp ai đó đã nhầm lẫn như tôi đã!

3

Hoàn toàn đồng ý với bạn. Hành vi thực sự kỳ quặc. Nó sẽ cập nhật các cửa hàng liên kết trên hồ sơ. Đây là cách tôi nhận được xung quanh vấn đề này (về cơ bản chỉ cần chạy phản ứng thông qua người đọc!):

success: function(record, operation) { 
    var newRecord= me.getMyModel().getProxy().reader.read(operation.response).records[0]; 
} 
+0

Giải pháp tốt! Vì lý do nào đó, tôi thấy rằng Store không phải lúc nào cũng cập nhật khi tự gọi thủ tục đọc của Proxy từ Model ... Vì vậy, tôi đã thêm phương thức 'updateTo' vào lớp Model, nó xử lý việc cập nhật một cá thể thành bản ghi (lấy từ phản hồi của máy chủ), bao gồm các cửa hàng liên kết. Cùng một ý tưởng, cách tiếp cận khác nhau :) –

+0

Đã thêm phương thức 'updateTo' vào câu trả lời của tôi để rõ ràng hơn/hữu ích hơn. –

-1

Nếu trường ID của bạn có giá trị thì ExtJS sẽ luôn cập nhật. Nếu bạn không viết bất kỳ giá trị nào cho trường id của bạn hoặc đặt nó thành null, nó sẽ gọi tạo. Tôi đoán bạn đang cố gắng gọi lưu với một bản ghi hiện có để nó sẽ luôn luôn gọi cập nhật. Đây là một hành vi mong muốn.

+1

Câu hỏi không liên quan gì đến việc tạo/cập nhật yêu cầu ... chỉ có liên quan đến việc trả lại dữ liệu liên quan và ExtJS cập nhật hồ sơ của cửa hàng cho phù hợp, mà KHÔNG làm việc gì cả ... như được minh chứng. Bản ghi phải được tải lại hoàn toàn từ máy chủ (buộc một chuyến đi khứ hồi vô dụng) hoặc cập nhật theo cách thủ công bằng cách sử dụng dữ liệu được cung cấp trong phản hồi của máy chủ, quá trình được mô tả kỹ trong câu trả lời của tôi. –

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