0

I have a MarionetteJS application that utilizes a CompositeView to show a table of data. What I'd like to do is hide the "Remove" button from all of the ItemViews based on whether a related model is in a specific state. I can do this easily with LayoutView, since in my program flow I can simply put a check like so (where menu is another view with some button(s).

   if (ModelIsEditable)
   {
       myLayout.menuRegion.show(menu);
   }

How might I accomplish the same thing with a CompositeView / ItemViews?

My code so far:

CompositeView:

(template)

<script type="text/template" id="data-items-table">
    <thead>
        <tr>
            <th>Title</th>
            <th>Number</th>
            <th>Default</th>
            <th class="no-sort">Actions</th>
        </tr>
    </thead>
    <tbody></tbody>
    <tfoot></tfoot>

</script>

(view)

List.DataItems = Marionette.CompositeView.extend({
    className: "table table-condensed",
    tagName: "table",
    template: "#data-items-table",
    childView: List.DataItem,
    childViewContainer: "tbody"
}

ItemView (template):

<script type="text/template" id="data-item-row">
    <td><%= Title%></td>
    <td><%= Number%></td>
    <td>
    <label class="checkbox-inline">
        <input type="checkbox" value="<%= IsDefault %>">
    </label>

    </td>
    <td class="js-menu-region">
        <a class="btn btn-danger btn-x">
            <i class="fa fa-trash-o"></i> Remove
       </a>
    </td>
</script>

(view)

List.CostCenterFundNumber = Marionette.ItemView.extend({
    tagName: "tr",
    template: "#data-item-row",

    ui: {
        "confirm": ".js-behavior-confirmable",
        isdefault: "input[type=checkbox]"
    },

    events: {
        "change @ui.isdefault": "toggleDefault"
    },

    toggleDefault: function () {
        if (this.ui.isdefault.prop('checked') == true) {
            this.model.set("IsDefault", true);

        } else if (this.ui.isdefault.prop('checked') == false) {
            this.model.set("IsDefault", false);
        }

        this.trigger("item:toggleDefault", this.model);
    },

    onRender: function () {

        if (this.model.get('IsDefault')) {
            this.ui.isdefault.prop('checked', true);
        }

    }

});
Matt Koch
  • 181
  • 3
  • 14
  • "What I'd like to do is hide the "Remove" button from all of the ItemViews based on whether a related model is in a specific state" Are you talking about the model of the itemView or another model ? – k2ndlab Aug 22 '15 at 06:02
  • I am referring to another model somewhere else in my code. – Matt Koch Aug 23 '15 at 11:19

1 Answers1

0

if you want to hide the remove button based on the state of the model of the itemView or the state of another model.

You could encapsulate your remove button in your template with a if statement. "if showRemove" for example. You provide the showRemove variable to your template by overriding the serializeData method of itemView. http://marionettejs.com/docs/v2.4.2/marionette.itemview.html#itemview-serializedata

Basically it will look like this

serializeData: function () {
    var data = this.model.toJSON();
    data.showRemove = this.model.get('is_editable'); // or anotherModel.get('is_editable');
    return data;
}

Now to also update your itemView in realtime when the model is modified, you need to listen for change of your itemView's model and trigger a re-render. Something like that in your itemView

modelEvents: {
    "change:is_editable": "render"
},

If the change you are listening is coming from another model, in the initialize method of your itemView you could use http://backbonejs.org/#Events-listenTo

initialize: function (){
    this.listenTo(anotherModel, 'change', this.render);
}

As a side note, this is to get you started, but for performance issue, re-render the whole view to update only a portion of it, is not always the best option especially if this a big view. You might want to trigger a specific method instead inside your itemView that will take care of show/hide/destroy/restore the specific portion with the help of a selector, or toggeling a css class show/hide.

k2ndlab
  • 134
  • 4
  • Thanks for your comment. How would I get all of the ItemViews inside of a CompositeView to listen to a model that is not part of the CompositeView? I was thinking perhaps I could write some code along the lines of `collectionView.triggerMethod("hide:menu:items")` which would somehow propogate down to all of the itemViews. – Matt Koch Aug 23 '15 at 11:25
  • Actually, the more I think about it...perhaps it would be easier to simply set an attribute on the models in the item views. That way, I can control the UI based on that rather than some other model. – Matt Koch Aug 23 '15 at 14:31