web-dev-qa-db-fra.com

Backbone JS: peut-on afficher des mises à jour déclenchées dans d'autres vues?

Dans mon projet simple, j'ai 2 vues - une vue d'élément de ligne (marque) et une application. J'ai joint une fonction qui permet de sélectionner plusieurs éléments:

 var BrandView = Backbone.View.extend ({
 ... du code ... 
 toggle_select: function () {
 this.model.selected = ! this.model.selected; 
 if (this.model.selected) $ (this.el) .addClass ('selected'); 
 else $ (this.el) .removeClass (' sélectionné '); 
 renvoie ceci; 
} 
}); 
 
 var AppView = Backbone.View.extend ({
 ... du code ... 
 delete_selected: function () {
 _.each (Brands.selected (), function (model) {
 model.delete_selected () ; 
}); 
 retourne faux; 
}, 
}); 

La chose est, je veux savoir combien d'articles sont sélectionnés. Dans cette configuration, la sélection n'affecte PAS le modèle et ne déclenche donc aucun événement. Et à partir du concept MVC, je comprends que les vues ne doivent pas être directement liées à d'autres vues. Alors, comment AppView peut-il savoir que quelque chose est sélectionné dans BrandViews?

Et plus précisément, je AppView pour savoir combien d'éléments ont été sélectionnés, donc si plus de 1 est sélectionné, je montre un menu pour la sélection multiple.

45
mvbl fst

Vous voudrez peut-être lire cette discussion sur les événements Backbone pub/sub:

http://lostechies.com/derickbailey/2011/07/19/references-routing-and-the-event-aggregator-coordinating-views-in-backbone-js/

J'aime l'ajouter en tant que mécanisme d'événement global:

Backbone.pubSub = _.extend({}, Backbone.Events);

Ensuite, dans une vue, vous pouvez déclencher un événement:

Backbone.pubSub.trigger('my-event', payload);

Et dans un autre, vous pouvez écouter:

Backbone.pubSub.on('my-event', this.onMyEvent, this);
73
stusmith

J'utilise ce que Addy Osmani appelle le modèle de médiateur http://addyosmani.com/largescalejavascript/#mediatorpattern . L'article dans son ensemble vaut bien une lecture.

Fondamentalement, c'est un gestionnaire d'événements qui vous permet de vous abonner et de publier des événements. Votre AppView serait donc en indice d'un événement, c'est-à-dire `` sélectionné ''. Ensuite, BrandView publierait l'événement "sélectionné".

La raison pour laquelle j'aime cela est qu'il vous permet d'envoyer des événements entre les vues, sans que les vues soient directement liées entre elles.

Par exemple

var mediator = new Mediator(); //LOOK AT THE LINK FOR IMPLEMENTATION

var BrandView = Backbone.View.extend({
    toggle_select: function() {
        ...
        mediator.publish('selected', any, data, you, want);
        return this;
    }
});

var AppView = Backbone.View.extend({
    initialize: function() {
        mediator.subscribe('selected', this.delete_selected)
    },

    delete_selected: function(any, data, you, want) {
        ... do something ...
    },
});

De cette façon, la vue de votre application ne se soucie pas s'il s'agit d'un BrandView ou FooView qui publie l'événement `` sélectionné '', seulement que l'événement s'est produit. Par conséquent, je trouve que c'est un moyen maintenable de gérer les événements entre les parties de votre application, pas seulement les vues.

Si vous lisez plus sur la "façade", vous pouvez créer une structure d'autorisations Nice. Cela vous permettrait de dire que seul un "AppView" peut s'abonner à mon événement "sélectionné". Je trouve cela utile car il indique très clairement où les événements sont utilisés.

7
John McKim

Voici mon cas avec un besoin similaire: Backbone listenTo semblait être une solution pour rediriger vers la page de connexion pour les demandes expirées ou non authentifiées.

J'ai ajouté un gestionnaire d'événements à mon routeur et l'ai fait écouter l'événement global tel que:

Backbone.Router.extend({
    onNotAuthenticated:function(errMsg){
        var redirectView = new LoginView();
        redirectView.displayMessage(errMsg);
        this.loadView(redirectView);
    },
    initialize:function(){
        this.listenTo(Backbone,'auth:not-authenticated',this.onNotAuthenticated);  
    },
    .....
});

et dans mon gestionnaire d'erreur jquery ajax:

$(document).ajaxError(
    function(event, jqxhr, settings, thrownError){
        .......
        if(httpErrorHeaderValue==="some-value"){
             Backbone.trigger("auth:not-authenticated",errMsg);
        }
    });     
1
gunalmel

En ignorant les problèmes que vous mentionnez déjà dans votre message, vous pouvez lier et déclencher des événements vers/depuis l'objet global Backbone.Event, ce qui permettra à n'importe quoi de parler à autre chose. Ce n'est certainement pas la meilleure solution, et si vous avez des vues discutant entre vous, vous devriez envisager de refactoriser cela. Mais voilà! J'espère que cela t'aides.

1
soundslikeneon

Vous pouvez utiliser l'objet Backbone comme bus d'événements.

Cette approche est quelque peu plus propre mais repose toujours sur l'objet Global Backbone

var view1 = Backbone.View.extend({

  _onEvent : function(){
    Backbone.trigger('customEvent');
  }

});


var view2 = Backbone.View.extend({

  initialize : function(){
    Backbone.on('customEvent', this._onCustomEvent, this);
  },

  _onCustomEvent : function(){
    // react to document edit.
  }

});
1
francesca

Comme John l'a suggéré ci-dessus, le modèle de médiateur fonctionne très bien dans ce scénario, car Addy Osmani résume à nouveau ce problème dans Fondamentaux du backbone .

Terminé en utilisant le plugin Backbone.Mediator qui est simple et génial, et permet à mes modules AMD View de fonctionner ensemble de manière transparente =)

0
gsklee

Utilisez les mêmes objets de modèle. AppView peut être initialisé avec une collection et BrandView initialisé avec un modèle de cette collection. Lorsque les attributs d'un objet branche changent, tout autre code ayant une référence à ce modèle peut le lire.

Permet donc d'avoir quelques marques que vous récupérez via une collection:

var brands = new Brands([]);
brands.fetch();

Vous créez maintenant une AppView et un tableau de BrandView pour chaque modèle.

var appView = new AppView({brands: brands});
var brandViews = brands.map(function(brand) {
  return new BrandView({brand: brand});
});

AppView et brandViews ont désormais accès aux mêmes objets de modèle, donc lorsque vous en modifiez un:

brands.get(0).selected = true;

Il change ensuite lorsqu'il est accessible par les vues qui le référencent également.

console.log(appView.brands.get(0).selected); // true
console.log(brandViews[0].brand.selected)    // true
0
Alex Wayne