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!
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");