Last Updated: February 25, 2016
·
3.284K
· alettieri

Backbone View + Bootsrap PopOver

I am working on a view that displays a Bootstrap popover. The view contains two buttons, when either of the buttons is clicked, a popover displays beneath it. Whenever a popover is open and a user clicks outside of either the button or popover, the popover will close.

I left a lot of the code out for brevity.

/**
 * View
 */
App.View = Backbone.View.extend({

    // ... brevity

    events: {
        'click .js-popover-button': 'popoverClick',
    },

    /**
     *  Click event handler of the bookmark button
     */
    popoverClick: function(e) {

        e.preventDefault();

        this.target = e.currentTarget;

        this._showPopover();


    },

    _buildPopOver: function() {

        // Build Bootstrap Popover
        this.$button.popover({
            html: true,
            title: 'Sign in to Bookmark',
            content: '<p>Personalize your events</p><p><a href="#" class="js-facebook-signup fc-button fc-button-social fc-button-facebook"><i class="fc-icon fc-icon-facebook"></i>Sign in with facebook</a></p><p><small>why facebook?</small></p>',
            container: this.el,
            placement: 'bottom',
            trigger: 'manual'
        });

        // Register mouseup event on document
        $( document ).on( 'mouseup.popover', _.bind( this._checkPopOver, this ) );
    },

    _checkPopOver: function(e) {

        var $popovers = this.$el.find('.popover'), // This is a hack, to find open pop-overs on the page
            $el = this.$button,
            isButton = ( $el.is(e.target) || $el.has(e.target).length > 0 ),
            isPopover = ( $popovers.is(e.target) || $popovers.has(e.target).length > 0 ),
            isOutside = ( !isButton && !isPopover )
        ;

        if( isOutside ) {
            this.$button.popover('hide');
        }

    },

    _showPopOver: function() {

        var button = this.$button.filter(this.target);

        if( button ) {
            this.$button.popover('hide');
            button.popover('show');
        }

    },

    _destroyPopOver: function() {

        this.$button.popover('destroy'); // Destroy all popovers
        $( document ).off( 'mouseup.popover'); // unbind coument.mouseup event for popover namespace

    },


    _bind: function() {
            //
            // Destroy the popover
            //
        this.listenTo( this.model, 'action:that:destroys:popover',      this._destroyPopOver );

    },

    initialize: function( options ){

        this.$button = this.$el.find( '.js-popover-button' );

        this._bind();

        this._buildPopOver();

        return this;
    }

});