Creating a layout that accepts a variable number of views (and hence regions)
Asked Answered
M

1

6

My goal I need to create a custom layout (a flow layout) that can receive a variable numbers of views and based on them, it creates regions as necessary and within those regions it shows the views that are passed in. The views can be arranged vertically or horizontally.

Requirement The layout has a template where initially regions are not defined. It only contains a wrapper (data-role="region-wrapper") where added regions will be rendered.

My approach.

1 - Extend a Marionette.Layout (obviously)

2 - Ovveride the construtor like the following

constructor: function(options) {
    // call super here...

    this.viewList= options.viewList || [];

    this._defineRegions(); // see 3
}            

3 - Define the regions dynamically

_defineRegions: function() {

    _.each(this.viewList, function(view, index) {               
    var name = 'flowRegion_' + index;
    var definition = { selector: "[data-region='flow-region-" + index + "']" };             
    this.addRegion(name, definition);

    }, this);
},

4 - Render regions and views in onRender method within the same layout

onRender: function() {

    _.each(this.viewList, function(view, index) {   
        // if the view has not been instantiated, instantiate it

        // a region is a simple div element
        var $regionEl = // creating a region element here based on the index

        // append the region here
        this.$el.find("[data-role='flow-wrapper']").append($regionEl); 

        var region = this.getRegion(index); // grab the correct region from this.regionManager
        region.show(view);              
    }, this);
}

This solution seems working but I would like to know if I'm following a valid one or not. Any other approach to follow?

Melissiamelita answered 13/12, 2013 at 15:37 Comment(0)
L
6

Maybe I'm not fully followed, but I can't see any reason a collectionView can't be used in this case.

The child views are all in same pattern, having data-region='flow-region-", and even have index. This is an obvious pattern of collection and its view.

With collectionView you can do things similar, adding/removing child views, fully reset, close etc.

If this is the case I would definitely recommend to use CollectionView or CompositeView, instead of overriding Region here.

Update

  1. About why removing a model will cause removing view.

    Because Marionette CollectionView has such listener in constructor:

    this.listenTo(this.collection, "remove", this.removeItemView, this);
    
  2. Add region in runtime.

    It's totally legit though I have not done that before. Layout has prototype method addRegion(name, definition), so any instance of layout should be able to add/remove region/regions in runtime. The usage would be like this:

    foo_layout.addRegion({region1: '#region-1'});
    
Lycaonia answered 13/12, 2013 at 17:44 Comment(8)
Thanks for your reply. I need to pass views that are not equal each others. Hence the custom layout. In addition, I would like to take advantage of layout show/close functionalities.Melissiamelita
I'm still not sold. A widget list may be similar to the case. Each widget is different from each other but they are still better be collection. show/close sub view can also be done in CollectionView cleanly, by removing the model. Forget this comment if this is still not the case.Lycaonia
I upvoted for your support. Thanks. Anyway, if it's possible to add regions during runtime, a reason would exist. Maybe I'm wrong but I like to explore new solutions. Why removing the model, will delete the single view?Melissiamelita
@flexaddicted, thanks, my last 10 points to 10k :) I've updated the answer 'cause it's rather long.Lycaonia
Base on point two, the addRegion method only add regions to the regionManager, but not creates or appends any element to the dom. Where with element I mean, for example, a div where the view will shown in.Melissiamelita
That can be done by using jQuery to create and append #region-1 dynamically before addRegion. Say $el.append('#region-1'). Once working such method can be added to this Layout's method so it's more beautiful and more dynamically.Lycaonia
Or override addRegion slightly by adding div first, then call super, the original method.Lycaonia
I'll waiting few days before marking your answer. Just waiting for other answers. Thanks for the availability.Melissiamelita

© 2022 - 2024 — McMap. All rights reserved.