javascript - Исключить свойства модели при синхронизации(Backbone.js)




underscore.js (10)

Если это одноразовый случай, вы можете использовать mode.unset('selected', { silent:true }) (тихий установлен только во избежание срабатывания события изменения), чтобы удалить атрибут ... У этого есть не так что неплохой эффект от повторного набора после сохранения.

При этом я полностью поддерживаю одно из решений выше. Более того, если это то, что вам нужно на регулярной основе.

Есть ли способ исключить определенное свойство из моей модели при синхронизации?

Например, я сохраняю в своей модели информацию о каком-либо состоянии представления. Предположим, у меня есть модуль выбора, и этот модуль просто переключает selected атрибуты на мою модель. Позже, когда я вызываю .save() в своей коллекции, я бы хотел проигнорировать значение selected и исключить его из синхронизации на сервер.

Есть ли чистый способ сделать это?

( Дайте мне знать, если вы хотите получить более подробную информацию )


Основываясь на нескольких ответах, это учитывает случаи нулевых объектов и условные условия в Backbone, которые не отправляют contentType если options.data уже установлен:

EDITABLE_ATTRIBUTES = ["name", "birthdate", "favoriteFood"];

...

save: function(attrs, options) {
  // `options` is an optional argument but is always needed here
  options || (options = {});

  var allAttrs = _.extend({}, this.attributes, attrs);
  var allowedAttrs = _.pick(allAttrs, EDITABLE_ATTRIBUTES);

  // If `options.data` is set, Backbone does not attempt to infer the content
  // type and leaves it null. Set it explicitly as `application/json`.
  options.contentType = "application/json";
  options.data = JSON.stringify(allowedAttrs);

  return Backbone.Model.prototype.save.call(
    this, allowedAttrs, options);
},

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

если вы посмотрите на строку backbone.js 1145, вы увидите, что

// Ensure that we have the appropriate request data.
    if (options.data == null && model && (method === 'create' || method === 'update' || method === 'patch')) {
      params.contentType = 'application/json';
      params.data = JSON.stringify(options.attrs || model.toJSON(options));
    }

Это означает, что вы можете переопределить часть данных xhr путем помещения данных в ваши параметры

Поскольку для поддержки магистральной системы требуется model.save ([attributes], [options])

Но помните, что атрибуты, такие как id, могут быть необходимы для правильной экономии

пример

model.save( {}, { data: JSON.stringify(data) } ) ; 

Поэтому вы должны делать что-то подобное

var data = { id : model.id , otherAttributes : 'value' }  ;  
model.save( {}, { data : JSON.stringify(data) } );

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


Я нашел некоторые проблемы с принятым решением, так как options.data изменяет способ вызова Backbone. Лучше использовать options.attrs следующим образом:

Backbone.Model.extend({
    save: function (attrs, options) {
        options = options || {};
        attrs = _.extend({}, _.clone(this.attributes), attrs);

        // Filter the data to send to the server
        delete attrs.selected;
        options.attrs = attrs;
        // Proxy the call to the original save function
        return Backbone.Model.prototype.save.call(this, attrs, options);
    }
});

мое решение объединяет все вышеперечисленное. просто используйте белый список вместо черного. Это хорошее правило вообще

определять

          attrWhiteList:['id','biography','status'],

а затем перезаписать сохранение

  save: function(attrs, options) {
    options || (options = {});

 //here is whitelist or all
    if (this.attrWhiteList != null )
          // Filter the data to send to the server
             whitelisted =  _.pick(this.attributes, this.attrWhiteList);
    else  
        whitelisted =this.attributes;
    /* it seems that if you override save you lose some headers and the ajax call changes*/
    // get data
    options.data = JSON.stringify(whitelisted);

    if ((this.get('id') == 0) || (this.get('id') == null)) 
        options.type = "POST"
    else
        options.type = "PUT";


    options.contentType = "application/json";
     //        options.headers =  { 
     //            'Accept': 'application/json',
     //            'Content-Type': 'application/json' 
     //        },

    // Proxy the call to the original save function
   return  Backbone.Model.prototype.save.call(this, attrs, options);
},

Имея эту же проблему, я решил создать небольшой модуль, который может помочь: https://github.com/lupugabriel1/backbone-model-save

Так вы можете использовать его в своих моделях:

var myModel = new Backbone.ModelSave.extend({
    notSync: ['name', 'age']
});

Поскольку save использует toJSON мы переопределяем его:

    toJSON: function(options) {
        var attr = _.clone(this.attributes);
        delete attr.selected;
        return attr;
    },

Но это может не сработать, если вы используете toJSON и, например, должны быть selected в виде. В противном случае вам, вероятно, придется переопределить метод save .


Чтобы установить только нужные значения, используйте HTTP PATCH insead HTTP POST. На стороне основы просто добавьте атрибут patch к методу сохранения:

entity.save(data,{patch:true})

Используя save с этим атрибутом, на сервер отправляются только те поля, которые передаются как data .


Это похоже на лучшее решение (на основе вопроса, связанного с @nikoshr)

Backbone.Model.extend({

    // Overwrite save function
    save: function(attrs, options) {
        options || (options = {});
        attrs || (attrs = _.clone(this.attributes));

        // Filter the data to send to the server
        delete attrs.selected;
        delete attrs.dontSync;

        options.data = JSON.stringify(attrs);

        // Proxy the call to the original save function
        return Backbone.Model.prototype.save.call(this, attrs, options);
    }
});

Таким образом, мы перезаписываем функцию сохранения в экземпляре модели, но мы просто отфильтровываем данные, которые нам не нужны, а затем мы прокси-сервер для функции родительского прототипа.


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

objs.sort((a,b)=> fn1(a,b) || fn2(a,b) || fn3(a,b) )

Где fn1 , fn2 , ... - функции сортировки, которые возвращают [-1,0,1]. Это приводит к «сортировке по fn1», «сортировке по fn2», которая в значительной степени равна ORDER BY в SQL.

Это решение основано на поведении || оператор, который оценивает первое оцениваемое выражение, которое может быть преобразовано в true .

Простейшая форма имеет только одну встроенную функцию:

// ORDER BY last_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) )

Имея два шага с last_nom , first_nom сортировки first_nom будет выглядеть так:

// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> a.last_nom.localeCompare(b.last_nom) || 
                  a.first_nom.localeCompare(b.first_nom)  )

Общая функция сравнения может быть примерно такой:

// ORDER BY <n>
let cmp = (a,b,n)=>a[n].localeCompare(b[n])

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

Вы можете использовать их с привязкой к ним по приоритету сортировки:

// ORDER_BY last_nom, first_nom
objs.sort((a,b)=> cmp(a,b, "last_nom") || cmp(a,b, "first_nom") )
// ORDER_BY last_nom, first_nom DESC
objs.sort((a,b)=> cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )
// ORDER_BY last_nom DESC, first_nom DESC
objs.sort((a,b)=> -cmp(a,b, "last_nom") || -cmp(a,b, "first_nom") )

Дело в том, что чистый JavaScript с функциональным подходом может пройти долгий путь без внешних библиотек или сложного кода. Это также очень эффективно, так как не нужно проводить синтаксический анализ строк







javascript backbone.js underscore.js