jqueryjquery-uijquery-ui-widget-factory

JQuery UI widget chaining: After a Widget Factory widget is initialised, how do I change what is returned by the initialising function?


I have written a JQuery UI widget with the Widget Factory which I plan to call on new, empty elements, which are then replaced by a new HTML structure based on a template in a private function in the widget.

The elements I want to call the widget's constructor on look like this:

<span id="b-accordion-1" class="b-accordion" data-accordion-title="Accordion 1"></span>

The widget constructor then runs and replaces this element with new HTML.

However, I want this new HTML to be available immediately to be chained after I call this code:

$("#b-accordion-1").bAccordion();

At the moment, though, calling this constructor will just return the original DOM element, even though this element isn't on the page anymore.

Here is the widget code as I have it at the moment:

;
(function($, window, document, undefined)
{

    $.widget("b.bAccordion", {

        options: {
            // id: "myID",
            // title: "Accordion",
            // content: HTML, 
            // actions: HTML, 
        },

        /*  ==============================
            Private Methods
            ============================== */

                _create: function() {

                    // Create a widget from a non-widget element.

                    this.options.id = this.options.id || null;
                    this.options.title = this.options.title || this.element.attr("data-accordion-title") || "";
                    this.options.content = this.options.content || this.element.attr("data-accordion-content") || null;

                    if (this.element.hasClass("b-accordion-active") === true) {

                    }
                    else
                    if (this.element.hasClass("b-accordion-active") === false) {

                        console.log(this);

                        $.event.trigger({
                            type: "bAccordion.beforeCreate"
                        });

                        var myOptions = {
                            title: this.options.title
                        };

                        // Construct new accordion.
                        var myHTML = $(this._templateAccordion(myOptions));
                        myHTML.data(this.element.data());

                        // Save original element for the accordion's content.
                        if ( !this.options.content ) {
                            this.options.content = this.element;
                        }

                        // If ID is passed, use the passed ID, else use the original element's ID for the accordion if it is set.
                        if ( this.options.id ) {
                            myHTML.attr("id", this.options.id);
                        }
                        else
                        if ( this.element.prop("id") ) {
                            myHTML.attr("id", this.element.prop("id"));
                            this.element.attr("id", null);
                        }

                        // Remove the accordion class from any initialising elements.
                        if ( this.element.hasClass("b-accordion") ) {
                            this.element.removeClass("b-accordion");
                        }

                        // Replace the original element with the accordion.
                        this.element.replaceWith(myHTML);
                        this.element = myHTML;
                        // console.log($(myHTML)[0]);
                        // this.bindings[0] = $(myHTML)[0];
                        // console.log(this.bindings[0]);
                        // this.bindings = myHTML;

                        // console.log(this.data("b-bAccordion").bindings);

                        // Enable the accordion's events.
                        this._addEventListeners();

                        $.event.trigger({
                            type: "bAccordion.onCreate"
                        });


                    }

                },

                _init: function() {

                    // Initialise this instance of the active dashboard widgets.

                    this.options.title = this.options.title || this.element.attr("data-accordion-title") || null;
                    this.options.content = this.options.content || this.element.attr("data-accordion-content") || null;
                    this.options.actions = this.options.actions || this.element.attr("data-accordion-actions") || null;

                    this.addContent(this.options.content);
                    this.addActions(this.options.actions);

                    $.event.trigger({
                        type: "bAccordion.onInit",
                    });

                },

                _destroy: function() {

                    this._removeEventListeners();

                    $.event.trigger({
                        type: "bAccordion.onDestroy",
                    });

                },

                _load: function() {

                    // Method for loading content into the widget. (Not currently used.)

                    $.event.trigger({
                        type: "bAccordion.onLoad",
                    });

                },

                _addEventListeners: function() {

                    // Add default event listeners to this instance of the plugin.
                    this.element.find('[data-action="Accordion_Expander_Toggle"]').on("click", this.expanderToggle);

                },

                _removeEventListeners: function() {

                    // Remove all event listeners from this instance of the plugin.


                },

        /*  ------------------------------
            Templates
            ------------------------------ */


                _templateAccordion: function(options) {


                    /*
                    options = {
                        title
                    }
                    */

                    var returnHML = "";

                    var myTitle = options.title;
                    var myTitleHTML = myTitle;

                    returnHML +=    '<div class="b-accordion b-accordion-collapsed b-accordion-active">';
                    returnHML +=        '<div class="b-accordion-header">';
                    returnHML +=            '<div class="b-accordion-expander">';
                    returnHML +=                '<div class="b-accordion-expander-container">';
                    returnHML +=                    '<button type="button" class="b-accordion-expander-button" data-action="Accordion_Expander_Toggle">';
                    returnHML +=                        '<span class="b-accordion-expander-button-icon glyphicons circle_plus"></span>';
                    returnHML +=                    '</button>';
                    returnHML +=                '</div>';
                    returnHML +=            '</div>';
                    returnHML +=            '<div class="b-accordion-heading">';
                    returnHML +=                '<div class="b-accordion-heading-container">';
                    returnHML +=                    '<h2 class="b-accordion-heading">' + myTitleHTML + '</h2>';
                    returnHML +=                '</div>';
                    returnHML +=            '</div>';
                    returnHML +=            '<div class="b-accordion-actions">';
                    returnHML +=                '<div class="b-accordion-actions-container">';
                    returnHML +=                    '<!-- Accordion Actions -->>';
                    returnHML +=                '</div>';
                    returnHML +=            '</div>';
                    returnHML +=        '</div>';
                    returnHML +=        '<div class="b-accordion-content b-accordion-content-collapsed">';
                    returnHML +=            '<!-- Accordion Content -->';
                    returnHML +=        '</div>';
                    returnHML +=    '</div>';

                    return returnHML;

                },




    /*  ==============================
        Public Methods
        ============================== */

            addContent: function(content, unwrap) {

                var myContent;

                if (content) {
                    myContent = $(content);
                }
                else
                {
                    myContent = $(this.options.content);

                }

                myContent = $(myContent).remove().html();
                // myContent = $(myContent).remove().html();

                this.element.find(".b-accordion-content").html(myContent);

            },

            addActions: function(actions) {

                var myActions;

                if (actions) {
                    myActions = $(actions);
                }
                else
                {
                    myActions = $(this.options.actions);
                }

                this.element.find(".b-accordion-actions-container").html(myActions);

            },

    /*  ------------------------------
        Event Handlers
        ------------------------------ */

            expanderToggle: function(event) {

                var $this = $(event.currentTarget).closest(".b-accordion");

                if ( $this.find(".b-accordion-content").is(":visible") === true) {

                    // Collapse

                    $this.removeClass("b-accordion-expanded");
                    $this.addClass("b-accordion-collapsed");

                    $this.find(".b-accordion-content").removeClass("b-accordion-content-expanded");
                    $this.find(".b-accordion-content").addClass("b-accordion-content-collapsed");

                    $this.find(".b-accordion-expander-button-icon").addClass("circle_plus");
                    $this.find(".b-accordion-expander-button-icon").removeClass("circle_minus");

                }
                else
                if ( $this.find(".b-accordion-content").is(":visible") === false) {

                    // Expand

                    $this.addClass("b-accordion-expanded");
                    $this.removeClass("b-accordion-collapsed");

                    $this.find(".b-accordion-content").addClass("b-accordion-content-expanded");
                    $this.find(".b-accordion-content").removeClass("b-accordion-content-collapsed");

                    $this.find(".b-accordion-expander-button-icon").removeClass("circle_plus");
                    $this.find(".b-accordion-expander-button-icon").addClass("circle_minus");                       

                }

            },

    });

})(jQuery, window, document);

Thanks in advance!


Solution

  • Many thanks to Taplar over at the #jquery IRC channel who provided this suggestion:

    Instead of chaining the function somehow, I used the instance() function of the widget, like so:

    HTML

     <span id="b-accordion-1"></span>
    

    JS

     $("#b-accordion-1").bAccordion();
    
     var myInstance = myElement.bAccordion("instance").element;
    
     $(myInstance).attr("id", "myNewID");