Backbone: ما هي أفضل طريقة لتصميم مجموعة داخل نموذج؟

تم إنشاؤها على ٤ نوفمبر ٢٠١٠  ·  11تعليقات  ·  مصدر: jashkenas/backbone

يعمل فريقي مع مخطط بيانات مثير للاهتمام. ما لدينا في الأساس هو مستند له اسم وإصدار ومجموعة من العناصر التي تنتمي إليه. العناصر نفسها ليس لها معرفات مرتبطة بها لأنها تنتمي إلى النموذج الأكبر ولكن يمكن إضافة العناصر / تحريرها / حذفها من المستند الرئيسي. النموذج يشبه ما يلي:
{
الاسم: "اختبار" ،
النسخة 1،
العناصر : [
{الاسم: "العنصر 1"،
المركز: 0} ،
{الاسم: "العنصر 2" ،
المركز: 1}]
}

سيكون من الرائع استخدام مجموعة للعناصر الأساسية في النموذج ولكن كلما تم تحديث المجموعة ، يجب على النموذج إعادة النشر إلى الخادم بعنوان url الخاص به. ما هي أفضل طريقة لتصميم هذا في العمود الفقري؟ سأكون سعيدًا لنشر المزيد في الخلاصة إذا كانت هناك حاجة إلى مزيد من المعلومات.

question

التعليق الأكثر فائدة

eranation : كلا ، يجب أن تكون هي نفسها إلى حد كبير. عند استخدام هذا النمط ، أود الاحتفاظ بـ items خارج تجزئة السمات الخاصة بي حتى لا أضطر إلى إبقائهم متزامنين. يتطلب هذا سحب الكائن items خارج الاستجابة للتحليل ، وإضافته مرة أخرى للتسلسل (انظر أدناه). بصرف النظر عن ذلك ، قد ترغب في وضع المنطق الذي وضعه rsim في initialize في طريقة constructor بدلاً من ذلك ، واستخدام on بدلاً من bind (وهو شبه مهمل).

أجد أنه من الأسهل بكثير أن تكون السمات عبارة عن تجزئة سطحية (لا توجد مجموعات أو نماذج متداخلة ، إلخ) ، حيثما أمكن ذلك.

var Document = Backbone.Model.extend({
  constructor: function() {
    this.items = new ItemSet(null, {document: this});
    this.items.on('change', this.save, this);
    Backbone.Model.apply(this, arguments);
  },
  parse: function(resp) {
    this.items.set(resp.items, {parse: true, remove: false});
    delete resp.items;
    return resp;
  },
  toJSON: function() {
    var attrs = _.clone(this.attributes);
    attrs.items = this.items.toJSON();
    return attrs;
  }
});
var ItemSet = Backbone.Collection.extend({
  model: Item,
  initialize: function(models, options) {
    this.document = options.document;
  }
});
var Item = Backbone.Model.extend({
  // access document with this.collection.document
});
var document1 = new Document({
  name: "Test",
  version: 1,
  items: [
    {name : "Item 1", position : 0},
    {name : "Item 2", position : 1}
  ]
});

يبدو أن هذا يعمل بشكل جيد حتى مع المخططات المتداخلة بعمق. (انظر المستندات )

ال 11 كومينتر

أود أن أقول أن لديك خياران رئيسيان ... الأول هو ترك العناصر كسمة فانيلا. يستخدم Backbone فحصًا عميقًا للمساواة عند تغيير السمات ، لذلك إذا تم تحديث عنصر داخلي ، فسيعرف المستند عنه.

الخيار الآخر هو سحب العناصر من المستند وإرفاقها كنماذج في حد ذاتها ، داخل مجموعة عالقة في المستند (نقوم بشيء على غرار هذه الأسطر في DocumentCloud). على سبيل المثال (بشكل تقريبي):

var Document = Backbone.Model.extend({
  initialize: function() {
    this.items = new ItemSet();
    this.items.bind('change', this.save);
  }
});

هل أي من هؤلاء يعمل بشكل جيد بالنسبة لك؟

أوصي أيضًا بإضافة خاصية "المستند" مرة أخرى إلى كائن المستند الذي يمكن الوصول إليه عند الحاجة من العناصر:

var Document = Backbone.Model.extend({
  initialize: function() {
    this.items = new ItemSet(this.get('items'), {document: this});
    this.items.bind('change', this.save);
  }
});
var ItemSet = Backbone.Collection.extend({
  initialize: function(models, options) {
    this.document = options.document;
  }
});
var Item = Backbone.Model.extend({
  // access document with this.collection.document
});
var document1 = new Document({
  name: "Test",
  version: 1,
  items: [
    {name : "Item 1", position : 0},
    {name : "Item 2", position : 1}
  ]
});

أعتقد أن ربط حدث تغيير العناصر بحفظ المستند هو القطعة المفقودة. على الرغم من أن إضافة المستند إلى ItemSet تبدو مفيدة جدًا أيضًا. سنحاول هذا اليوم وسأعلمكم يا رفاق كيف سيظهر ذلك.

هذا عمل بشكل جيد. أكبر مشكلة نواجهها الآن هي النمس. شكرا لمساعدة اللاعبين.

كيف سأقوم بحفظ جميع العناصر مرة واحدة؟ لا أرغب في تقديم طلب في كل مرة يتم فيها تغيير عنصر ولكني أرغب في حفظها جميعًا بطلب واحد على إجراء المستخدم. كنت أفكر في جمع كل شيء عند حفظ المستند وتحديث سمة "عناصر" المستند. هل هذا حل جيد؟

طالما تم تعيين العناصر الخاصة بك في المستند ، فعند قيامك بعمل document.save () ، سيتم إرسال العناصر إلى الخادم أيضًا.

ولكن لنفترض أنه إذا أضفت عنصرًا إلى مستند المجموعة document1.items في وقت التشغيل ، فلن تتم إضافته إلى سمة "العناصر" الخاصة بالمستند 1 أيضًا تلقائيًا. لذلك إذا قمت بعد ذلك بعمل document1.save () ، فلن يتم إرسال النموذج الجديد الذي أضفته إلى المجموعة إلى الخادم. لا أستطيع أن أرى كيف يمكن أن تنتشر التغييرات التي تم إجراؤها على المجموعة في سمات النموذج التي تم إرسالها مع الحفظ.

إذن ، إليك كيفية معالجتنا لها: يحتوي المستند على مصفوفة عناصر افتراضية. عند التهيئة ، في طريقة مجموعة محملة بشكل زائد ، أقوم بإنشاء مجموعة عناصر جديدة من السمات وقمت بتعيينها في المستند.

class Document extends Backbone.Model
  defaults:
    items: []

  set: (attrs, options) ->
    items = attrs['items']
    if _( items ).isArray()
      if _( items ).isEmpty()
        attrs['items'] = new DocumentItemsCollection
        newItem = new Item
        attrs['items'].add(newItem, { silent: true })
      else
        attrs['items'] = new DocumentItemsCollection items

في هذه المرحلة ، تتعامل فقط مع طرق جمع العناصر باستخدام "get" و "set" و "add" و "remove". أنت لا تعبث مع تدوين النقطة. لدي أيضًا طرق في فئة المستند تسمى addItem و deleteItem لإطلاق أحداث التغيير على المستند نفسه. عندما تقوم بحفظ () في المستند ، فإنه سيتصل بـ JSON في مجموعة العناصر الخاصة بك.

بصراحة ، هذه مجرد حالة بسيطة لمستنداتنا ولدينا مستندات فرعية أعمق. التعامل مع هذا القدر من التعقيد مع العمود الفقري ، والإفراط في تحميل العديد من الأساليب على النماذج ، هو ألم كبير حقيقي في المؤخرة. نحن نتطلع الآن إلى استبدال العمود الفقري بـ sproutcore في المستقبل.

إذا كنت مضطرًا للتعامل مع مستندات معقدة حقًا ، فأقترح البحث في ExtJS أو sproutcore. يعد Backbone رائعًا لمشروع صغير بنماذج بسيطة ولكنه يتفكك بسرعة كبيرة عندما تبدأ الكائنات / التفاعلات في الازدياد.

هل هناك أي "أفضل الممارسات" الجديدة لهذا الإصدار 1.0؟

eranation : كلا ، يجب أن تكون هي نفسها إلى حد كبير. عند استخدام هذا النمط ، أود الاحتفاظ بـ items خارج تجزئة السمات الخاصة بي حتى لا أضطر إلى إبقائهم متزامنين. يتطلب هذا سحب الكائن items خارج الاستجابة للتحليل ، وإضافته مرة أخرى للتسلسل (انظر أدناه). بصرف النظر عن ذلك ، قد ترغب في وضع المنطق الذي وضعه rsim في initialize في طريقة constructor بدلاً من ذلك ، واستخدام on بدلاً من bind (وهو شبه مهمل).

أجد أنه من الأسهل بكثير أن تكون السمات عبارة عن تجزئة سطحية (لا توجد مجموعات أو نماذج متداخلة ، إلخ) ، حيثما أمكن ذلك.

var Document = Backbone.Model.extend({
  constructor: function() {
    this.items = new ItemSet(null, {document: this});
    this.items.on('change', this.save, this);
    Backbone.Model.apply(this, arguments);
  },
  parse: function(resp) {
    this.items.set(resp.items, {parse: true, remove: false});
    delete resp.items;
    return resp;
  },
  toJSON: function() {
    var attrs = _.clone(this.attributes);
    attrs.items = this.items.toJSON();
    return attrs;
  }
});
var ItemSet = Backbone.Collection.extend({
  model: Item,
  initialize: function(models, options) {
    this.document = options.document;
  }
});
var Item = Backbone.Model.extend({
  // access document with this.collection.document
});
var document1 = new Document({
  name: "Test",
  version: 1,
  items: [
    {name : "Item 1", position : 0},
    {name : "Item 2", position : 1}
  ]
});

يبدو أن هذا يعمل بشكل جيد حتى مع المخططات المتداخلة بعمق. (انظر المستندات )

@ akre54 شكرًا ، هذا مثال رائع ، أقدر كثيرًا

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات