Opened 8 years ago

Closed 8 years ago

Last modified 8 years ago

#8134 closed enhancement (worksforme)

new $.Widget and _creatWidget should not require an element

Reported by: fooblah Owned by:
Priority: minor Milestone: 1.9.0
Component: ui.widget Version: git (not yet released)
Keywords: Cc:
Blocked by: Blocking:

Description

It would be nice if $.Widget.prototype._createWidget did not require an element if none is provided.

Then if there was a $.Widget.prototype.setElement() that did the $.data setup and binding to remove so a preexisting element isn't assumed. The element could be defined programmatically, set later (or changed).

$.Widget.prototype._setElement: function (element) {
  this.element.unbind( "remove." + this.widgetName, $.proxy(this.destroy, this));
  this.element = $(element);
  $.data(this.element[0], this.widgetName, this);
  this.element.bind( "remove." + this.widgetName, $.proxy(this.destroy, this));
}

It would make things a lot nicer for people inserting widgets into the dom instead of just adding behavior to existing elements. This way widgets could be responsible for creating their own dom instead of requiring scaffolding already exist in the dom.

Another option would be to have a _buildDom method which is called before _create which by default assumes an element gives developers a chance to do something totally custom for generating the dom.

Since the default $.widget.bridge always has an element to pass to _createWidget, this would not impact $(selector).myWidget() type instantiation.

Current workaround:

  var w = new $.custom.myWidget(options, $('<div>'));

Define _setElement and in myWidget.prototype._create

  this._setElement(JST[this.options.template](this.options));

I know I could just insert my template into a div or something but that somewhat defeats the purpose of using templates since I then have to manually add classes to element, know external to the widget the element type, etc.

Change History (7)

comment:1 Changed 8 years ago by Scott González

Resolution: worksforme
Status: newclosed

comment:2 Changed 8 years ago by Scott González

comment:3 Changed 8 years ago by Scott González

I'm not sure what you're trying to gain here. Are you trying to avoid invoking your template directly? You're not going to have default options or _getCreateOptions() mixed in by the time your template runs, so you're not really gaining much.

I don't follow your statement of "I know I could just insert my template into a div or something but that somewhat defeats the purpose of using templates since I then have to manually add classes to element, know external to the widget the element type, etc." You have to insert your template into the DOM at some point no matter what. Invoking your template _createWidget() instead of before the call to your widget doesn't change that at all.

We will also not support something like what you've suggested with _setElement() since we wouldn't support it ever being called after create.

comment:4 Changed 8 years ago by fooblah

That code hasn't been merged into 1.8 so I didn't see that.

However, defaultElement doesn't accomplish what I'm suggesting anyway. The widget should be able to define its own markup *on instantiation* as *a function* its options.

Setting defaultWidget can only be done via options (which means something other than the widget handles its rendering) or by subclassing and overriding defaultElement. However then you can't render the dom as a function of options during instantiation.

This basically mandates a poor separation of concerns. If you are doing server side rendering, bad separation of concerns is the norm. However with client side templating, there is an opportunity to have the widget handle all it's own business but the way defaultElement works, that isn't an option.

About your concern with _setElement, I'm not sure why rerendering is such a big deal, it is pretty essential for staying synchronized with external events. render() is one of the key features of Backbone.View for example (although it doesn't allow you to replace the top level element either). I understand there is some bookkeeping involved with this.element but that bookkeeping can just get updated right?

In any case, something like _render that is called automatically before _init would at least allow for the widget to manage its own layout concerns.

About your question about my statement saying I could insert my updated markup into a div, yes I do have to do that call no matter what, the point is the widget should be able to make that call itself, not some external code.

Last edited 8 years ago by fooblah (previous) (diff)

comment:5 Changed 8 years ago by Scott González

Nothing is stopping you from using a default element of <div> or whatever makes sense for the specific widget and just populating the contents using a template option on creation.

comment:6 in reply to:  5 Changed 8 years ago by fooblah

Replying to scott.gonzalez:

Nothing is stopping you from using a default element of <div> or whatever makes sense for the specific widget and just populating the contents using a template option on creation.

Absolutely, that's what I was saying earlier. However what if I don't want a div (at instantiation)? Or I want to set classes on that top level div (at instantiation)? I can't do that with a template.

Last edited 8 years ago by fooblah (previous) (diff)

comment:7 Changed 8 years ago by Scott González

Does this work for you? http://jsbin.com/uhuluj/edit#javascript

The one problem I see with that implementation is that you don't get the merged options.

Note: See TracTickets for help on using tickets.