Backbone: Ajoutez une méthode de «réinitialisation» à Backbone.Model

Créé le 31 juil. 2014  ·  22Commentaires  ·  Source: jashkenas/backbone

J'avais besoin de mettre à jour certaines des données d'un modèle provenant du serveur. Actuellement, il existe deux options: appeler Model.set , ou définir Model.attributes directement. Je ne voulais pas que les modifications soient enregistrées, mais je ne pouvais pas non plus utiliser silent car j'avais besoin des vues respectives à mettre à jour. Alors, j'ai écrit un patch de singe:

Backbone.Model.prototype.reset = (attributes, options) ->
    attrs = attributes || {};
    if options.parse
      attrs = this.parse(attrs, options) || {}

    @set(attrs, options);
    <strong i="9">@changed</strong> = {};

Vous vous demandez pourquoi Backbone.Model n'a pas de méthode de réinitialisation comme Backbone.Collection ?

question

Commentaire le plus utile

@thesmart , Model # set ne

Il devrait être obligatoire de donner une raison lors de la clôture d'un problème. J'aimerais savoir pourquoi @ akre54 a fermé ça. Les modèles de dorsale sont délibérément primitifs et sans opinion, cependant, l'absence de réinitialisation du numéro de modèle exprime une opinion sur la façon dont les modèles sont utilisés. Depuis http://backbonejs.org/#Getting -started

Philosophiquement, Backbone tente de découvrir l'ensemble minimal de primitives de structuration de données (modèles et collections) et d'interface utilisateur (vues et URL) qui sont généralement utiles lors de la création d'applications Web avec JavaScript.

Tous les 22 commentaires

Reset est une trappe d'échappement, qui vous permet d'effectuer facilement un rendu efficace en masse lorsque vous savez que vous en avez besoin.

Pour votre cas, utilisez simplement set .

Pouvez-vous définir sans rendre les modifications d'attributs sales?

Le 1er août 2014, à 7 h 28, Jeremy Ashkenas [email protected] a écrit:

Reset est une trappe d'échappement, qui vous permet d'effectuer facilement un rendu efficace en masse lorsque vous savez que vous en avez besoin.

Pour votre cas, utilisez simplement set.

-
Répondez directement à cet e-mail ou affichez-le sur GitHub.

Appeler Model.clear() avant Model.set({}) fonctionnera dans votre cas? De cette façon, vous n'étendez pas les attributs actuels, mais ils seront remplacés. Model.clear() prend également en charge l'option silencieuse si vous ne voulez pas déclencher deux événements de «modification» sur le modèle.

Je reconnais que cette méthode est absente. J'ai aussi pensé à utiliser conjointement model.clear() et model.set() . Ensuite, j'ai rencontré le problème, que je déclenche l'événement change deux fois maintenant.
L'utilisation de l'option silent lors de l'appel de model.clear() n'est pas une option, car je souhaite également qu'un événement change soit déclenché, lorsqu'une propriété n'est pas définie.

Une méthode model.reset() prendrait un nouveau hachage d'attributs et remplirait ce hachage avec des valeurs undefined pour les anciennes clés d'attributs non présentes dans le nouveau hachage d'attribut.

Model.prototype.reset = function(attrs, options) {
    for (var key in this.attributes) {
        if (key in attrs) continue;
        attrs[key] = void 0;
    }

    return this.set(attrs, options);
};

@lennerd

Qu'en est-il de:

Model.prototype.reset = function(attrs, options) {
    for (var key in this.attributes) {
        this.unset(key, {silent:true});
    }
    return this.set(attrs, options);
};

Non, cela n'aide pas. Imaginez que vous ayez une clé foo dans le hachage d'attributs actuel du modèle, qui n'est pas présente dans le nouveau hachage attrs vous passez à model.reset() . Lorsque j'écoute l'événement change:foo , il ne sera pas déclenché avec la nouvelle valeur undefined , car nous avons utilisé model.unset() en mode silencieux.

Backbone.Model.prototype.reset = function(attrs, options) {
    for (var key in this.attributes) {
        this.unset(key, {silent:true});
    }
    return this.set(attrs, options);
};

var bar = new Backbone.Model();

bar.on('change', function(model) {
    console.log('The model bar has been changed.');
});

bar.on('change:foo', function(model, foo) {
    console.log('Foo has been changed to: ' + foo);
});

bar.set(foo, 'test');
// => The model bar has been changed.
// => Foo has been changed to: test

bar.reset({ foo2: 'test2' });
// => The model bar has been changed.
// Foo was resetted but no change event has been triggered.

http://jsfiddle.net/lennerd/3s1Ltwgu/

Cool, je comprends ce que tu veux dire. J'opterais probablement pour l'utilisation de this.unset(key, options) plutôt que de remplacer explicitement this.attributes, mais ce n'est qu'une question d'échanger attrs[key] = void 0; : panda_face:

Pardonnez toute ignorance que je montre, car je suis encore relativement nouveau sur backbone.js, mais le comportement discuté ressemble à Model.fetch . La description dit:

Réinitialise l'état du modèle à partir du serveur

Il semble que les événements change soient toujours déclenchés mais ne rendent pas le modèle "sale". Y a-t-il une raison pour laquelle cette approche ne peut pas être adoptée lorsque vous cherchez à réinitialiser les attributs en fonction d'une réponse du serveur? J'imagine que la seule situation de ce genre qui pourrait se produire est lorsqu'un modèle change en tant qu'effet secondaire d'une autre opération, mais généralement de tels effets secondaires sont considérés comme une mauvaise programmation et devraient être évités si possible. Si l'effet secondaire ne peut pas être évité, il est peut-être plus logique d'envoyer un indicateur de réponse "update model XYZ" au lieu des nouveaux attributs de modèle et de déclencher un fetch chaque fois que vous voyez une telle réponse.

Encore une fois, pardonnez toute ignorance que je montre dans ce commentaire.

@kolorahl ,

Ce que l'OP souhaite réaliser, c'est d'effacer les attributs du modèle actuel et de transmettre un nouveau JSON qui devient les nouveaux attributs du modèle. De cette manière, nous ne voulons pas vraiment toucher le backend si vous avez déjà le JSON.

Je suis en quelque sorte d'accord avec @ lupugabriel1 avec sa méthode clear + set. Mais je pense que c'est une fonctionnalité qui doit être prise en compte. Quelque chose comme Backbone.Collection # reset

La raison pour laquelle j'en avais besoin est que le monde change. Backbone suppose que Model # fetch () XHR est la principale méthode de chargement de données à partir du serveur, mais nous faisons beaucoup plus de choses en utilisant des websockets. Lorsque les données sont transmises au client, il est redondant d'appeler .fetch et nous avons besoin d'un moyen décent de charger les données de manière latérale et d'obtenir un hook d'événement à déclencher.

Pourquoi n'utilisez-vous pas #set ?

@jridgewell car #set rendra les attributs sales. Essayons d'utiliser set et voyons ce qui se passe:

function callback(data_from_server) {
  console.info(data_from_server);
  m = new Backbone.Model(data_from_server);
  m.set('foo', 'what?', {silent: true});
  console.info(m.changedAttributes())
}

Résultat réel:

{foo: 'bar'}
{foo: "what?"}

Résultat souhaité:

{foo: 'bar'}
false

Définir convient lorsque l'état n'est pas synchronisé avec le serveur, mais la réinitialisation du numéro de modèle est nécessaire car il n'y a aucun moyen de marquer l'état comme synchronisé avec le serveur.

J'ai fini par écrire un patch de singe différent pour cette fonctionnalité:

/**
 * Allow for side-loading data from the server, calling the sync event afterwards.
 * <strong i="6">@param</strong> attributes
 * <strong i="7">@param</strong> options
 */
Backbone.Model.prototype.sync_set = function(attributes, options) {
  var attrs = attributes || {};
  if (options.parse) {
    attrs = this.parse(attrs, options) || {}
  }

  this.set(attrs, options);
  this.changed = {};
  this.trigger('sync', this, attributes, options);
  return this;
}
function callback(data_from_server) {
  console.info(data_from_server);
  m = new Backbone.Model(data_from_server);
  m.set('foo', 'what?', {silent: true});
  console.info(m.changedAttributes())
}
{foo: 'bar'}
false

Cela doit probablement également supprimer les éléments manquants. Je ne sais pas si le jeu de n ° de modèle (attributs) fait cela.

Comme @lennerd l'a souligné, appeler clear() suivi de set() n'est pas une bonne option, car

1) déclenche deux événements change et
2) Si vous utilisez silent:true sur l'appel clear , vous n'obtenez pas d'événements de modification sur les attributs qui n'ont pas été définis.

collection.reset() est très intuitif et je pense que Model pourrait vraiment bénéficier d'une méthode équivalente. Je me retrouve en train d'essayer d'utiliser model.reset(attrs) tout le temps, toujours déçu quand ce n'est pas là. :(

Je suis allé de l'avant et j'ai créé une petite extension pour ajouter une méthode reset à Backbone.Model: Backbone-Model-Reset

D'accord - serait utile d'avoir nativement. J'avais juste besoin de réinitialiser les attributs sans modifier l'attribut 'id', comme le faisait clear (). Voici l' essentiel .

@thesmart , Model # set ne

Il devrait être obligatoire de donner une raison lors de la clôture d'un problème. J'aimerais savoir pourquoi @ akre54 a fermé ça. Les modèles de dorsale sont délibérément primitifs et sans opinion, cependant, l'absence de réinitialisation du numéro de modèle exprime une opinion sur la façon dont les modèles sont utilisés. Depuis http://backbonejs.org/#Getting -started

Philosophiquement, Backbone tente de découvrir l'ensemble minimal de primitives de structuration de données (modèles et collections) et d'interface utilisateur (vues et URL) qui sont généralement utiles lors de la création d'applications Web avec JavaScript.

Pour autant que je sache, le modèle de données de Backbone est incompatible avec REST
car il n'y a aucun moyen de modéliser en toute sécurité l'état du serveur sur le client après un
modèle a été construit. Construire un nouveau modèle est le seul moyen d'obtenir
un état frais sans réinitialisation.

Le mardi 5 juillet 2016, pgifford [email protected] a écrit:

@thesmart https://github.com/thesmart , l'ensemble de n ° de modèle ne disparaît pas
attributs, c'est pourquoi je pense que la réinitialisation du modèle # est nécessaire.

Il devrait être obligatoire de donner une raison lors de la clôture d'un problème. Je
aimer savoir pourquoi @ akre54 https://github.com/akre54 a fermé cela.
Les modèles de base sont délibérément primitifs et sans opinion, cependant, le
l'absence de réinitialisation du numéro de modèle exprime une opinion sur la façon dont les modèles sont utilisés. De
http://backbonejs.org/#Getting -started

Philosophiquement, Backbone est une tentative de découvrir l'ensemble minimal de
structuration des données (modèles et collections) et interface utilisateur (vues et
URL) primitives qui sont généralement utiles lors de la création d'applications Web
avec JavaScript.

-
Vous recevez cela parce que vous avez été mentionné.
Répondez directement à cet e-mail, affichez-le sur GitHub
https://github.com/jashkenas/backbone/issues/3253#issuecomment -230586424,
ou couper le fil
https://github.com/notifications/unsubscribe/AARJLQ8-BGeV0X_owHVpyPQAdeiMweNMks5qSriDgaJpZM4CTBHH
.

J'avais besoin d'un modèle reset et je l'ai fait dans le _spirit_ de Backbone. J'utilise ceci dans mon extension personnelle de Backbone.

C'est mieux qu'un simple .clear suivi d'un .set car il fusionne les valeurs par défaut dans le modèle, laissant tous les attributs passés les remplacer comme lors de l'initialisation.

/**
 * Clears the model's attributes and sets the default attributes.
 * <strong i="10">@param</strong> {Object} attributes to overwrite defaults
 * <strong i="11">@param</strong> {Object} options  to pass with the "set" call.
 * <strong i="12">@return</strong> {Backbone.Model}  this object, to chain function calls.
 */
reset: function(attributes, options) {
    options = _.extend({ reset: true }, options);

    // ensure default params
    var defaults = _.result(this, 'defaults'),
        attrs = _.defaults(_.extend({}, defaults, attributes || {}), defaults);

    // apply
    this._reset(attrs, options);

    // triggers a custom event, namespaced to model in order
    // to avoid collision with collection's native reset event
    // when listening to a collection.
    if (!options.silent) this.trigger('model:reset', this, options);

    return this;
},

/**
 * Private method to help wrap reset with a custom behavior in child
 * classes.
 * <strong i="13">@param</strong>  {Object} attributes to overwrite defaults
 * <strong i="14">@param</strong>  {Object} options  to pass with the "set" call.
 */
_reset: function(attrs, options) {
    this.clear({ silent: true }).set(attrs, options);
},

Il déclenche des événements de changement ( change et change:attribute ) en plus de l'événement personnalisé model:reset sinon silent: true . Il pourrait facilement être personnalisé pour ne déclencher que l'événement model:reset mais je pense que les événements de changement devraient toujours se déclencher lors de la réinitialisation d'un modèle.

J'ai légèrement modifié la solution de lennerd https://github.com/jashkenas/backbone/issues/3253#issuecomment -58789524.

Backbone.Model.prototype.reset = function(attrs, options) {
    var missing = {};
    for (var key in this.attributes) {
        if (key in attrs) continue;
        attrs[key] = undefined;
        missing[key] = true;
    }
    // trigger all change events at the same time
    this.set(attrs, options);
    // remove missing attributes completely
    for (var key in missing) {
        // no silent option here in case  attributes changed again meanwhile (edge case)
        this.unset(key)
    }
    return this;
};
Cette page vous a été utile?
0 / 5 - 0 notes