Cum pot face vizualizări dependente de DOM într-o colecție CollectionView?

Am o Marionette.CollectionView care face o listă a ItemView s. În timpul render() , folosesc modelul al ItemView pentru a desena câteva SVG folosind Raphael .

Raphael requires that I specify a height and a width for its canvas, which I would normally grab from this.$el. However, $el (as an empty <div>) has no dimensions until it is added to the DOM and CSS rules are applied to it, so I need to delay rendering until I know that the view is in the DOM.

The problem is that Marionette.CollectionView doesn't add a child view to the DOM until after it has rendered. How can I override this behavior without re-implementing half of CollectionView?

Sample code

// Renders a single object.
var ItemView = Marionette.ItemView.extend({
    template: "#item-view-template",
    onRender: function() {
        var svgEl = this.$el.find("div.svg-canvas");
       //Raphael needs the element's width and height, which
       //is 0 until this.$el is in the DOM.
        var paper = Raphael(svgEl.get(0), svgEl.height(), svgEl.width());
       //... draw some SVG...
    }
});

// Renders a collection of objects.
var ListView = Marionette.CollectionView.extend({
    itemView: ItemView,
    model: MyModel
});

// Main point of entry.
MyApp.show = function() {
    var collection = new MyCollection();
    var listView = new ListView({ collection: collection });
    MyApp.mainRegion.show(listView);
    collection.fetch();
};
0

1 răspunsuri

onRender won't handle your needs, as this method gets called when the view has been rendered - but does not guarantee that the view has been added to the DOM yet.

Pentru a face acest lucru, veți avea nevoie de o metodă onShow care va fi apelată de regiune atunci când veți afișa vizualizarea în regiune. Problema este că implementarea actuală solicită numai onShow în vizualizarea pe care o transmiteți în mod direct - vizualizarea colecției în acest caz. Deci, va trebui să implementați onShow-ul într-un mod care îl face să se numească această metodă pe toți copiii din colecțiile de vizionări.


Marionette.CollectionView.extend({
 //...  

  onShow: function(){
    _.each(this.children, function(childView){
      if (childView.onShow){ childView.onShow(); }
    });
  }
});

Ar trebui să o facă. Când apelați MyApp.mainRegion.show (listView) , acesta va apela metoda onShow a vizualizării colecției, care va apela copiii (dacă este acolo).


După discuția din comentarii, este apelată o implementare care va garanta metoda onShow a vizualizărilor copil, chiar și după ce onShow din vizualizarea părinte a fost apelat și un element este adăugat la colecție mai târziu:


ItemView = Marionette.ItemView.extend({
 //...

  onShow: function(){
   //I am guaranteed to be called from the CollectionView
   //because the CollectionView registers me in a promise
  }
});

CollectionView = Marionette.CollectionView.extend({

  initialize: function(){
    this.onShowCallbacks = new Marionette.Callbacks();
  },

  onShow: function(){
    this.onShowCallbacks.run();
  },

  appendHtml: function(cv, iv){
    cv.append(iv.el);

   //promise to run 'onShow' if it exists
    if (iv.hasOwnProperty("onShow")){
      this.onShowCallbacks.add(iv.onShow);
    }
  }
});

Also available in this gist: https://gist.github.com/2872526

0
adăugat
ah, deci ai nevoie de o promisiune asupra metodelor tale onshow pentru vederile copilului. ceva care spune "Garantez că metoda de afișare a vizualizării copilului va fi apelată, chiar dacă vizualizarea copil este apelată după ce părintele a fost redat". Pot biciul asta pentru tine.
adăugat autor Derick Bailey, sursa
M-am gândit la asta, dar lucrurile pe care le-aș face în onShow utilizează modelul. Când se adaugă CollectionView în regiune, colecția este încă preluată. Am nevoie de o "render, cu excepția cazului în care nu sunteți încă în DOM, în care caz așteptați până când sunteți înainte de a proceda". Poate că ar trebui să aștept până când finalizarea inițială va fi finalizată înainte de a adăuga colecția mea CollectionView în regiune ...
adăugat autor Brant Bobby, sursa
Ah, nu m-am gândit la asta! Mare răspuns, mulțumesc din nou pentru ajutor. :)
adăugat autor Brant Bobby, sursa
Brilliant, acest lucru a fost foarte util- Multumesc, @DerickBailey!
adăugat autor Matt Fletcher, sursa
Vreau să menționez că versiunea curentă suportă acum acest eveniment pentru copii.
adăugat autor monokrome, sursa
Dacă cv.append trebuie să fie cv. $ El.append ?
adăugat autor Ian Mackinnon, sursa
M-am luptat cu ceva foarte asemănător, cu excepția faptului că trec peShow în itemViewOptions și încercând să obțină înălțimea fiecărui itemView's. Cu toate acestea, dacă urmăm acest lucru, înălțimea este întotdeauna 0.
adăugat autor Paul Young, sursa