Search code examples
javascriptbackbone.js

Show/hide div - DRY


I have 3 views, SectionAView, SectionBView and SectionCView. Each view has 2 radio buttons, Yes and No.

When I select Yes in SectionAView, it should display SectionBView. Selecting ‘No’ should display SectionCView (and hide SectionBView)

The application could have many views, so I guess my question is to keep things a little bit more DRY and possibly the best way to approach this?

I have something like this:

var Section = Backbone.Model.extend({
    defaults: {
        block: null
    }
});

var List = Backbone.Collection.extend({
    model: Section
});

var SectionAView = Backbone.View.extend({
    el: 'body',

    initialize: function() {
        this.model = new Section();
        this.collection = new List();
        this.listenTo(this.model, "change", this.render);
        this.render();
    },
    events: {
         'click .section-a': 'updateElement'
    },
    render: function(e) {
         this.$el.find('.section-b').hide();
         return this;
    },
    updateElement: function(e) {
        var $target = $(e.target);
        var activeValue = $target.val();
        // Default - SectionA is displayed (at all times)
       this.model.set('block', 'section-a');
       this.collection.push(this.model);
       if (activeValue == 'no') {
           this.$el.find('.section-b').show();
           this.$el.find('.section-c').hide();
       } else {
           this.$el.find('.section-c').show();
           this.$el.find('.section-b').hide();
       }
     }
   });

   var SectionBView = Backbone.View.extend({
        el: 'body',
        model: Section,

        initialize: function() {
             this.render();
        },
        render: function(e) {
            this.$el.find('.section-b').hide();
            return this;
        },
      });

      var SectionCView = Backbone.View.extend({
            el: 'body',
            initialize: function() {
                this.render();
            },
            render: function(e) {
                this.$el.find('.section-c').hide();
                return this;
            }

        });

HTML:

    <div class="section-a" data-active-value="true">
        <h2>Section A</h2>
        <label>Yes<input type="radio" name="section-a" class="section-a" value="yes" /></label>
        <label>No<input type="radio" name="section-a" class="section-a" value="no" /></label>
    </div>

    <div class="section-b" data-active-value="">
        <h2>Section B</h2>
        <label>Yes<input type="radio" name="section-b" class="section-b" value="yes" /></label>
        <label>No<input type="radio" name="section-b" class="section-b" value="no" /></label>
    </div>

    <div class="section-c">
        <h2>Section C</h2>
        <label>Yes<input type="radio" name="section-c" class="section" value="yes" /></label>
        <label>No<input type="radio" name="section-c" class="section" value="no" /></label>
    </div>

Solution

  • It is better if you cache elements and use toggleClass:

    render: function(e) {
        //cache        
        var elemB = this.$el.find('.section-b')
        var elemC = this.$el.find('.section-c')
        elemB.toggleClass('show', false);//remove 'show' class if any
             return this;
        },
    updateElement: function(e) {
        var $target = $(e.target);
        var activeValue = $target.val();
        // Default - SectionA is displayed (at all times)
        this.model.set('block', 'section-a');
        this.collection.push(this.model);
        elemB.toggleClass('show', (activeValue === 'no'));
        elemC.toggleClass('show', (activeValue === 'yes'))
        }
    

    Additionally if you set activeValue to true or false, you will not have to check for 'no' value and code becomes shorter

    elemB.toggleClass('show', activeValue);