web-dev-qa-db-fra.com

backbone.js structuration de vues et de modèles imbriqués

Utilisation de backbone.js:

J'ai un ModelA de niveau supérieur qui contient 2 attributs et 2 modèles imbriqués, ModelB et ModelC. ModelB et ModelC ont chacun 2 attributs comme suit:

ModelA
    attributeA1
    attributeA2
    ModelB
        attributeB1
        attributeB2
    ModelC
        attributeC1
        attributeC2

Il existe un ViewA pour ModelA et un ViewB pour ModelB. La fonction de rendu de ViewA place un nouveau div sur le corps, tandis que le rendu de ViewB crée un h1. L'initialisation de ViewA appelle le rendu de ViewB pour insérer ce h1 dans le nouveau div. La raison derrière cette séparation est que le h1 peut changer et nécessiter un nouveau rendu indépendant de ViewA.

ViewA
    initialise: 
        //call ViewA's own render function
        this.render() 

        //call ViewB's render function that further modifies the $("#new") div created earlier.
        $("#new").append(ViewB.render().el)

    //ViewA's own render function
    render: //place <div id="new"></div> onto 'body'

ViewB
    render: //create a <h1></h1>
    funcB1: //can this access it's parent ModelA's attributes and other objects?

Q1: ViewB a une fonction funcB1. Cette fonction peut-elle accéder aux attributs de son modèle parent? Des attributs tels que l'attribut A1, ou même l'attribut C1 (qui serait un frère ou un cousin)?

Q2: En tant qu'extension supplémentaire à Q1, funcB1 peut-il accéder aux éléments DOM associés à ViewA? (dans cet exemple, le #new div?)

Q3: En général, comment puis-je définir les associations entre les vues et les modèles comme décrit ci-dessus afin que tout soit correctement lié?

Je me rends compte que cette question est quelque peu abstraite mais tous apprécient toute aide ou directive appréciée.

71
fortuneRice

Pour pouvoir atteindre des attributs sur des modèles liés, le modèle doit avoir une sorte de connaissance sur les modèles auxquels il est lié. Backbone.js ne traite pas implicitement des relations ou de l'imbrication, ce qui signifie que vous devez vous assurer que les modèles se connaissent les uns les autres. Pour répondre à vos questions, une façon de procéder consiste à vous assurer que chaque modèle enfant possède un attribut "parent". De cette façon, vous pouvez d'abord parcourir l'imbrication jusqu'au parent, puis vers le bas pour tous les frères et sœurs que vous connaissez.

Pour être plus précis avec vos questions. Lors de l'initialisation de modelA, vous créez probablement modelB et modelC, je suggère de définir un lien vers le modèle parent lorsque vous faites cela, comme ceci:

ModelA = Backbone.Model.extend({

    initialize: function(){
        this.modelB = new modelB();
        this.modelB.parent = this;
        this.modelC = new modelC();
        this.modelC.parent = this;
    }
}

De cette façon, vous pouvez atteindre le modèle parent dans n'importe quelle fonction de modèle enfant en appelant this.parent.

En ce qui concerne vos vues, lorsque je fais des vues de dorsale imbriquées, je trouve plus facile de laisser chaque vue représenter une balise HTML en utilisant l'option tagName de la vue. J'écrirais vos opinions comme ceci:

ViewA = Backbone.View.extend({

    tagName: "div",
    id: "new",

    initialize: function(){
       this.viewB = new ViewB();
       this.viewB.parentView = this;
       $(this.el).append(this.viewB.el);
    }
});

ViewB = Backbone.View.extend({

    tagName: "h1",

    render: function(){
        $(this.el).html("Header text"); // or use this.options.headerText or equivalent
    },

    funcB1: function(){
        this.model.parent.doSomethingOnParent();
        this.model.parent.modelC.doSomethingOnSibling();
        $(this.parentView.el).shakeViolently();
    }

});

Ensuite, dans votre code d'initialisation d'application (par exemple dans votre contrôleur), j'initierais ViewA et placerais son élément à l'intérieur de l'élément body.

73
Jens Alm

La solution ci-dessus est sur la bonne voie mais a quelques problèmes.

initialize: function(){
  this.viewB = new ViewB();
  this.viewB.parentView = this;
  $(this.el).append(this.viewB.el);    
}

Principalement, le toJSON () du modèle renvoie désormais des données périmées. J'ai posté une solution pour résoudre ce problème dans un plugin backbone.js . Vous êtes invités à l'utiliser.

3
geddesign

La réponse générale à la question "Puis-je" est toujours "oui, tant que vous êtes prêt à écrire le code". Le point derrière Backbone est de fournir une forte séparation du modèle et de la vue. Si B1 a une référence à A1 et A1 a une référence à C1, alors vous êtes entièrement capable de créer des méthodes et de définir les règles par lesquelles B1 peut modifier A1 et C1 et ainsi de suite.

Les vues doivent être configurées pour recevoir les événements CRUD de leurs modèles respectifs. Si l'utilisateur fait quelque chose avec B1view qui modifie B1model, et B1model à son tour modifie A1model, alors A1model doit générer un événement qu'A1view reçoit et provoque un nouveau rendu de A1view, et ainsi de suite. Cela devrait arriver comme par magie. (En pratique, il faut un certain temps pour obtenir la bonne magie, mais j'ai trouvé que Backbone était vraiment puissant. Et BackboneRelational aide avec des choses comme ce que vous décrivez ici.)

3
Elf Sternberg

Vous pouvez utiliser certaines extensions, Backbone-Forms https://github.com/powmedia/backbone-forms par exemple. Pour suivre votre cas d'utilisation, définissez un schéma comme:

var ModelB = Backbone.Model.extend({
    schema: {
        attributeB1: 'Text',
        attributeB2: 'Text'
    }
});

var ModelC = Backbone.Model.extend({
    schema: {
        attributeC: 'Text',
    }
});

var ModelA = Backbone.Model.extend({
    schema: {
        attributeA1: 'Text',
        attributeA2: 'Text',
        refToModelB: { type: 'NestedModel', model: ModelB, template: 'templateB' },
        refToModelC: { type: 'NestedModel', model: ModelC, template: 'templateC' }
    }
});

Regardez https://github.com/powmedia/backbone-forms#customising-templates pour les modèles partiels.

Les pièces importantes ici sont type: 'NestedModel' et template: 'templateXXX'.

Ce plugin a quelques limitations mais vous pouvez en voir d'autres sur https://github.com/documentcloud/backbone/wiki/Extensions%2C-Plugins%2C-Resources .

2
Artem Oboturov

Il existe un plugin Backbone Backbone-relational.js qui fournit des relations un à un, un à plusieurs et plusieurs à un entre les modèles de Backbone.

Je pense que ce js répondra à vos besoins. Vist BackboneRelational pour plus de documentation.

0
Gagan