Backbone.js - правильная инициализация модели

Вопросы:. Каков правильный способ инициализации модели backbone.js, когда есть атрибуты, которые необходимо хранить определенным образом? Нужно ли сопоставлять атрибуты, которые не требуют специального форматирования? Я думал, что backbone.js сделал какое-то автоматическое отображение.

Пример:

var MyModel = Backbone.Model.extend({

    initialize: function (options) {

        // These attributes need to be stored in a different format
        // Dates
        this.startYear = new Date(options.startTime).getFullYear();
        // Rounding numbers
        this.wholeNumber = Math.Round(options.numberWithDecimals);
        // Storing empty strings as nulls
        if (options.fullName == null || options.fullName == "") {
            this.fullName == null;
        } else {
            this.fullName = options.fullName;
        }

        // These are fine as they are
        this.fieldA = options.fieldA;
        this.fieldB = options.fieldB;
        this.fieldC = options.fieldC;
    },
});

Ответ 1

Сначала вы должны различать attributes и instance variables.

Атрибуты: IMHO, это должны быть простые объекты как String или Integer. Они перемещаются по клиенту и серверу через REST API. Они управляются с помощью Model.get()/Model.set(). Они отправляются на сервер через Model.toJSON() (также они используются для отправки в template с использованием того же .toJSON() Если они каким-то образом меняются, то запускаются события базовой линии. Вы можете настроить инициализацию этого attributes, обрабатывая информацию JSON на стороне сервера, до того, как она будет отправлена ​​в Model, переопределяя Model.parse(), как предположил @muistooshort.

Переменные экземпляра: (объект this.myAttribute) Они могут быть сложными объектами. Не запускайте какое-либо неявное событие в их изменении, и они не отправляются на сервер в вызовы save и update, и стандартным образом они не отправляются в шаблон.

В вашем примере вы не храните какой-либо сложный объект, и если вы не боитесь, что ваша модель отправит на сервер больше атрибутов, чем получает с сервера, вы можете пойти на предложение @muistooshort:

// code no tested
var MyModel = Backbone.Model.extend({
  parse: function(resp, xhr) {
    resp.startYear = new Date( resp.startTime ).getFullYear();
    resp.wholeNumber = Math.Round( resp.numberWithDecimals );
    if( resp.fullName == "" ) resp.fullName == null;

    return resp;
  },
});

Просто помните, что это атрибуты, и вы должны обращаться к ним таким образом my_model.get( "startYear" )

Единственная проблема с этим решением заключается в том, что производные атрибуты не будут обновляться, если исходный атрибут изменится. Итак, вы можете прийти с другой реализацией:

// code no tested
var MyModel = Backbone.Model.extend({
  initialize: function(){
    this.updateAttributes();
    this.on( "change", this.updateAttributes, this );
  },

  updateAttributes: function() {
    this.set( "startYear", new Date( this.get( "startTime" ) ).getFullYear() );
    this.set( "wholeNumber", Math.Round( this.get( "numberWithDecimals" ) ) );
    if( this.get( "fullName" ) == "" ) this.set( "fullName", null );
  },
});

Обновление

Поскольку @TomTu предлагает, чтобы ваши атрибуты onlive были необходимы только для подачи шаблонов, лучшим решением является декоратор: fooobar.com/questions/304921/...

Ответ 2

Если все, что вам нужно, это вспомогательные значения, которые будут использоваться в шаблонах, вы можете вычислить их в перезаписанном методе toJSON, который добавит все дополнительные атрибуты, которые могут вам понадобиться при представлении модели в представлении.

Как сказано в документации для Backbone.js:

model.toJSON()

Верните копию атрибутов модели для строкой JSON. Это можно использовать для сохранения, сериализации или для увеличенияперед тем как быть переданным к представлению....

как я упомянул в комментарии к другому ответу - изменение модели в методе parse приведет к созданию накладных расходов, которые будут отправляться на сервер при каждой сохраненной модели и должны считаться неаккуратной и плохой практикой

Так как инициализация модели не привязывает параметры к экземпляру модели аналогично тому, как это делается для представлений, вы всегда можете сделать это в методе инициализации, а затем ссылаться на параметры из перезаписанного метода toJSON по мере необходимости тем, что вы хотите достичь

Ответ 3

Уже был дан ответ, но он просто немного опрятный:

var contact = Backbone.Model.extend({
       parse: function (response) { 
           response.newAttribute = response.alreadyProvidedAttribute; 
           return response;
      }
 });