35 votes

Backbone.js Gestion des attributs qui sont des tableaux

J'aime vraiment la colonne vertébrale, mais je suis le plus de temps à faire ce qui semble être des choses simples. J'ai apprécier l'aide de l'exemple suivant.

J'ai un modèle, les Critères, que je veux utiliser pour stocker l'état de certains éléments dans mon INTERFACE. il ya un couple de simples attributs, et un attribut qui est un tableau d'Id utilisé pour stocker les Id des balises que l'utilisateur a sélectionné dans l'INTERFACE utilisateur.

Donc, j'ai créer une nouvelle instance. J'ai ajouter quelques éléments pour les balises de tableau. Alors, je veux repartir de zéro, créer une nouvelle instance, affecté à la même variable. Mais, mes balises de tableau continue à détenir des informations, j'ai ajouté comme une partie de la première instance de Critères.

J'ai documenté les cas de test ci-dessous.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Test</title>
    <script src="Scripts/Libraries/jquery-1.6.1.js" type="text/javascript"></script>
    <script src="Scripts/Libraries/underscore.js" type="text/javascript"></script>
    <script src="Scripts/Libraries/backbone.js" type="text/javascript"></script>

    <script language="javascript" type="text/javascript">

        $(function () {

            // Simple model to hold some state about my UI.
            var Criteria = Backbone.Model.extend({

                defaults: {
                    "status": "Normal",
                    "priority": "Normal",
                    "tags": new Array()
                }

            });

            // Create new criteria.
            window.criteria = new Criteria();

            // The length of the tags array should be 0. PASSES
            console.log("Expect 0: Actual " + window.criteria.get("tags").length);

            // Add a tag id to the tags array.
            window.criteria.get("tags").push(5); // Tag with ID of 5.

            // The length of the tags array should be 1. PASSES
            console.log("Expect 1: Actual " + window.criteria.get("tags").length);

            // Create a new instance of criteria.
            window.criteria = new Criteria();

            // The length of the tags array should be 0. FAILS
            // CONFUSED. I thought this is now a new instance with a new set of attributes.
            // Why does the tags collection still have an item in it.
            console.log("Expect 0: Actual " + window.criteria.get("tags").length);

            // OK. So, I will call the clear method on the model. This is supposed to remove all attributes
            // from the model.
            // Then, I will create it again.
            window.criteria.clear();
            window.criteria = new Criteria();

            // The length of the tags array should be 0. FAILS. Still 1.
            console.log("Expect 0: Actual " + window.criteria.get("tags").length);

            // ARGH!
            console.log("HELP!");

        });

    </script>

</head>
<body>
    <h1>Test</h1>
    <p>Backbone test page.</p>
</body>
</html>

Suis-je tout simplement de la marque ici? Suis-je en train d'utiliser l'épine Dorsale de choses qu'il n'a pas été prévu? Ou ai-je raté quelque chose de plus général en javascript programmation OO?

P. S. j'ai d'abord utilisé un Backbone de collecte de tags, mais qui a présenté toute une autre série de questions relatives au fait d'avoir une Étiquette de modèle référencé dans plusieurs collections et comment l'épine Dorsale de la méthode remove unsets la "collection" de référence lorsqu'un élément est supprimé à partir de n'importe quelle collection. Un autre jour, une autre question.

70voto

btford Points 4373

"default" peut aussi être une fonction.

 var Criteria = Backbone.Model.extend({
    defaults: function () {
        return {
            "status": "Normal",
            "priority": "Normal",
            "tags": new Array()
        }
    }
});
 

Cela créerait un nouveau tableau lorsqu'un nouveau critère est instancié. Voir: http://backbonejs.org/#Model-defaults

34voto

Derick Bailey Points 37859

Thom Blake a raison de savoir pourquoi il garde les mêmes valeurs pour le tableau. une option pour résoudre ceci consiste à définir la valeur par défaut dans l'initialiseur

         var Criteria = Backbone.Model.extend({

            defaults: {
                "status": "Normal",
                "priority": "Normal"
            },

            initialize: function(){
              if( !this.get('tags') ){ 
                this.set({tags: new Array()});
              }
            }

        });
 

13voto

Thom Blake Points 1618

Lorsque vous définissez les "balises" sous "par défaut", vous créez un nouveau tableau et le définissez sur la valeur par défaut de cette classe. Ensuite, lorsque vous créez une nouvelle instance, elle a la même référence de tableau, qui contient toujours les éléments que vous avez insérés.

Plutôt que de définir une valeur par défaut pour les balises, vous devriez pouvoir la définir à [] avant de l'utiliser pour la première fois:

 window.criteria = new Criteria()
window.criteria.set({'tags', []})  //you can use new Array() if you want
window.criteria.get('tags').push(5)

window.criteria = new Criteria()
console.log(window.criteria.get('tags'))   //should be undefined
window.criteria.set({'tags', []})
 

3voto

Chris M Points 51

Pour être clair, la dernière option offerte par Maksym H. ne résoudra pas le problème. Les valeurs par défaut de la propriété est fourni en supposant que toutes les valeurs sont immuables. Un tableau, cependant, est mutable, qui signifie que sa valeur peut être modifiée (par exemple, les balises[0] = "bonjour" peut être changé avec les balises[0] = "salut").

En utilisant btford réponse, vous forçant une nouvelle instance de toute mutable objet/propriété d'être créé sur chaque nouvelle instance du modèle, de sorte qu'il n'est jamais partagée, parce que l'objet est créé avec une fonction d'étendue variable.

De même, Derick Bailey réponse est correcte, il utilise juste la méthode initialize à la place des valeurs par défaut de la méthode.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X