Skip to main content

Search and Top Navigation

#8134 closed enhancement (worksforme)

Opened February 24, 2012 06:12AM UTC

Closed February 24, 2012 01:14PM UTC

Last modified February 27, 2012 07:11PM UTC

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.

Attachments (0)
Change History (7)

Changed February 24, 2012 01:14PM UTC by scottgonzalez comment:1

resolution: → worksforme
status: newclosed

Changed February 24, 2012 01:15PM UTC by scottgonzalez comment:2

Changed February 24, 2012 01:25PM UTC by scottgonzalez comment:3

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.

Changed February 27, 2012 06:18PM UTC by fooblah comment:4

_comment0: 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. \ \ 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). \ \ 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.1330366901661491
_comment1: 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). \ \ 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.1330367075653623

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.

Changed February 27, 2012 06:21PM UTC by scottgonzalez comment:5

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.

Changed February 27, 2012 06:25PM UTC by fooblah comment:6

_comment0: Replying to [comment:5 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? Or I want to set classes on that top level div? I can't do that with a template.1330367216938608

Replying to [comment:5 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.

Changed February 27, 2012 07:11PM UTC by scottgonzalez comment:7

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.