Skip to main content

Search and Top Navigation

#15279 closed feature (wontfix)

Opened March 08, 2018 08:28AM UTC

Closed October 25, 2018 01:57PM UTC

Support for private fields and methods within widgets

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

I've been working lately on a framework of common jQuery widgets, built through the Widget Factory, for use in a larger application, and I've got a lot of widget inheritance going on. I've found myself wishing for a way to have a particular widget define private members that can't accidentally be overridden by another widget, because that implementer didn't realize he defined a field or method with the same name as an existing one on the base widget. In other words, I need a solution for namespace conflicts.

I've got one that works by adding some additional new functions to $.Widget.prototype, and using a custom wrapper functions for $.widget(), but it's rather cumbersome to use, as it requires widgets to call these additional functions at the beginning of almost every regular function call.

I took a shot at integrating the "tacked-on" code into the widget component itself, and it's a lot nicer to use. I'm ready to submit a pull request with the code, if there's interest.

Conceptually, the solution is as follows:

First, each widget prototype can define a field named "_privates", in the same fashion as the "options" field. When prototypes are merged, however, any "_privates" fields are not simply merged together, but are re-organized into an object structure of the following form:

_privates: {
    Namespace1: {
        Widget1: {},
        Widget2: {}
    },
    Namespace2: {
        Widget1: {},
        Widget2: {}
    }
}

Second, the proxy methods that define "_super" and "_superApply" for every method call on the widget instance now also define a "_myPrivates" field, which extracts the appropriate sub-object from the "_privates" object, based on the namespace and name of the prototype that is being proxied.

Finally, when a new instance of the widget is created, the "_privates" object on the merged prototype is cloned anew for the new instance, similar to the "options" object.

I also added the step of searching for any functions in the cloned "_privates" object and binding them to the widget instance, so they can access other fields and methods of the widget. Requiring the widget to do this manually seems like pointless boilerplate, but I'm open to discussion.

Ultimately, you get a system that looks like this:

https://jsfiddle.net/pz0bk85r/10/

Attachments (0)
Change History (3)

Changed March 08, 2018 08:37AM UTC by JakenVeina comment:1

description: I've been working lately on a framework of common jQuery widgets, built through the Widget Factory, for use in a larger application, and I've got a lot of widget inheritance going on. I've found myself wishing for a way to have a particular widget define private members that can't accidentally be overridden by another widget, because that implementer didn't realize he defined a field or method with the same name as an existing one on the base widget. In other words, I need a solution for namespace conflicts. \ \ I've got one that works by adding some additional new functions to $.Widget.prototype, and using a custom wrapper functions for $.widget(), but it's rather cumbersome to use, as it requires widgets to call these additional functions at the beginning of almost every regular function call. \ \ I took a shot at integrating the "tacked-on" code into the widget component itself, and it's a lot nicer to use. I'm ready to submit a pull request with the code, if there's interest. \ \ Conceptually, the solution is as follows: \ \ First, each widget prototype can define a field named "_privates", in the same fashion as the "options" field. When prototypes are merged, however, any "_privates" fields are not simply merged together, but are re-organized into an object structure of the following form: \ \ \ {{{ \ _privates: { \ Namespace1: { \ Widget1: {}, \ Widget2: {} \ }, \ Namespace2: { \ Widget1: {}, \ Widget2: {} \ } \ } \ }}} \ \ Second, the proxy methods that define "_super" and "_superApply" for every method call on the widget instance now also define a "_myPrivates" field, which extracts the appropriate sub-object from the "_privates" object, based on the namespace and name of the prototype that is being proxied. \ \ Finally, when a new instance of the widget is created, the "_privates" object on the merged prototype is cloned anew for the new instance, similar to the "options" object. \ \ I also added the step of searching for any functions in the cloned "_privates" object and binding them to the widget instance, so they can access other fields and methods of the widget. Requiring the widget to do this manually seems like pointless boilerplate, but I'm open to discussion. \ \ Ultimately, you get a system that looks like this. \ \ {{{ \ (function () { \ let counter = 0; \ \ $.widget("Test.WidgetA", { \ _create: function () { \ this._myPrivates.count = ++counter; \ }, \ _privates: { \ count: 0, \ common: "WidgetA", \ print: function () { \ this.element.append("<div>WidgetA#" + this._myPrivates.count + "</div>") \ }, \ }, \ print: function () { \ this._myPrivates.print(); \ }, \ }); \ })(); \ \ (function () { \ let counter = 0; \ \ $.widget("Test.WidgetB", $.Test.WidgetA, { \ _create: function () { \ this._myPrivates.count = ++counter; \ this._super(); \ }, \ _privates: { \ count: 0, \ print: function () { \ this.element.append("<div>WidgetB#" + this._myPrivates.count + "</div>") \ }, \ }, \ print: function () { \ this._super(); \ this._myPrivates.print(); \ }, \ }); \ })(); \ \ $(document).ready(function () { \ $("<h1></h1>") \ .appendTo($("body")) \ .text("Hello World!"); \ \ let widget1 = $("<div></div>") \ .appendTo($("body")) \ .WidgetA() \ .WidgetA("instance"); \ \ let widget2 = $("<div></div>") \ .appendTo($("body")) \ .WidgetB() \ .WidgetB("instance"); \ \ let widget3 = $("<div></div>") \ .appendTo($("body")) \ .WidgetA() \ .WidgetA("instance"); \ \ let widget4 = $("<div></div>") \ .appendTo($("body")) \ .WidgetB() \ .WidgetB("instance"); \ \ widget1.print(); \ widget2.print(); \ widget3.print(); \ widget4.print(); \ }); \ }}} \ \ ... which produces ... \ \ {{{ \ WidgetA#1 \ WidgetA#2 \ WidgetB#1 \ WidgetA#3 \ WidgetA#4 \ WidgetB#2 \ }}} \ \ \ I've been working lately on a framework of common jQuery widgets, built through the Widget Factory, for use in a larger application, and I've got a lot of widget inheritance going on. I've found myself wishing for a way to have a particular widget define private members that can't accidentally be overridden by another widget, because that implementer didn't realize he defined a field or method with the same name as an existing one on the base widget. In other words, I need a solution for namespace conflicts. \ \ I've got one that works by adding some additional new functions to $.Widget.prototype, and using a custom wrapper functions for $.widget(), but it's rather cumbersome to use, as it requires widgets to call these additional functions at the beginning of almost every regular function call. \ \ I took a shot at integrating the "tacked-on" code into the widget component itself, and it's a lot nicer to use. I'm ready to submit a pull request with the code, if there's interest. \ \ Conceptually, the solution is as follows: \ \ First, each widget prototype can define a field named "_privates", in the same fashion as the "options" field. When prototypes are merged, however, any "_privates" fields are not simply merged together, but are re-organized into an object structure of the following form: \ \ \ {{{ \ _privates: { \ Namespace1: { \ Widget1: {}, \ Widget2: {} \ }, \ Namespace2: { \ Widget1: {}, \ Widget2: {} \ } \ } \ }}} \ \ Second, the proxy methods that define "_super" and "_superApply" for every method call on the widget instance now also define a "_myPrivates" field, which extracts the appropriate sub-object from the "_privates" object, based on the namespace and name of the prototype that is being proxied. \ \ Finally, when a new instance of the widget is created, the "_privates" object on the merged prototype is cloned anew for the new instance, similar to the "options" object. \ \ I also added the step of searching for any functions in the cloned "_privates" object and binding them to the widget instance, so they can access other fields and methods of the widget. Requiring the widget to do this manually seems like pointless boilerplate, but I'm open to discussion. \ \ Ultimately, you get a system that looks like this: \ \ https://jsfiddle.net/pz0bk85r/8/ \

Changed March 08, 2018 08:38AM UTC by JakenVeina comment:2

description: I've been working lately on a framework of common jQuery widgets, built through the Widget Factory, for use in a larger application, and I've got a lot of widget inheritance going on. I've found myself wishing for a way to have a particular widget define private members that can't accidentally be overridden by another widget, because that implementer didn't realize he defined a field or method with the same name as an existing one on the base widget. In other words, I need a solution for namespace conflicts. \ \ I've got one that works by adding some additional new functions to $.Widget.prototype, and using a custom wrapper functions for $.widget(), but it's rather cumbersome to use, as it requires widgets to call these additional functions at the beginning of almost every regular function call. \ \ I took a shot at integrating the "tacked-on" code into the widget component itself, and it's a lot nicer to use. I'm ready to submit a pull request with the code, if there's interest. \ \ Conceptually, the solution is as follows: \ \ First, each widget prototype can define a field named "_privates", in the same fashion as the "options" field. When prototypes are merged, however, any "_privates" fields are not simply merged together, but are re-organized into an object structure of the following form: \ \ \ {{{ \ _privates: { \ Namespace1: { \ Widget1: {}, \ Widget2: {} \ }, \ Namespace2: { \ Widget1: {}, \ Widget2: {} \ } \ } \ }}} \ \ Second, the proxy methods that define "_super" and "_superApply" for every method call on the widget instance now also define a "_myPrivates" field, which extracts the appropriate sub-object from the "_privates" object, based on the namespace and name of the prototype that is being proxied. \ \ Finally, when a new instance of the widget is created, the "_privates" object on the merged prototype is cloned anew for the new instance, similar to the "options" object. \ \ I also added the step of searching for any functions in the cloned "_privates" object and binding them to the widget instance, so they can access other fields and methods of the widget. Requiring the widget to do this manually seems like pointless boilerplate, but I'm open to discussion. \ \ Ultimately, you get a system that looks like this: \ \ https://jsfiddle.net/pz0bk85r/8/ \ I've been working lately on a framework of common jQuery widgets, built through the Widget Factory, for use in a larger application, and I've got a lot of widget inheritance going on. I've found myself wishing for a way to have a particular widget define private members that can't accidentally be overridden by another widget, because that implementer didn't realize he defined a field or method with the same name as an existing one on the base widget. In other words, I need a solution for namespace conflicts. \ \ I've got one that works by adding some additional new functions to $.Widget.prototype, and using a custom wrapper functions for $.widget(), but it's rather cumbersome to use, as it requires widgets to call these additional functions at the beginning of almost every regular function call. \ \ I took a shot at integrating the "tacked-on" code into the widget component itself, and it's a lot nicer to use. I'm ready to submit a pull request with the code, if there's interest. \ \ Conceptually, the solution is as follows: \ \ First, each widget prototype can define a field named "_privates", in the same fashion as the "options" field. When prototypes are merged, however, any "_privates" fields are not simply merged together, but are re-organized into an object structure of the following form: \ \ \ {{{ \ _privates: { \ Namespace1: { \ Widget1: {}, \ Widget2: {} \ }, \ Namespace2: { \ Widget1: {}, \ Widget2: {} \ } \ } \ }}} \ \ Second, the proxy methods that define "_super" and "_superApply" for every method call on the widget instance now also define a "_myPrivates" field, which extracts the appropriate sub-object from the "_privates" object, based on the namespace and name of the prototype that is being proxied. \ \ Finally, when a new instance of the widget is created, the "_privates" object on the merged prototype is cloned anew for the new instance, similar to the "options" object. \ \ I also added the step of searching for any functions in the cloned "_privates" object and binding them to the widget instance, so they can access other fields and methods of the widget. Requiring the widget to do this manually seems like pointless boilerplate, but I'm open to discussion. \ \ Ultimately, you get a system that looks like this: \ \ https://jsfiddle.net/pz0bk85r/10/ \

Changed October 25, 2018 01:57PM UTC by scottgonzalez comment:3

resolution: → wontfix
status: newclosed

Use the language as intended.