Skip to main content

Search and Top Navigation

#10623 closed feature (wontfix)

Opened September 25, 2014 09:47PM UTC

Closed September 26, 2014 01:41AM UTC

Last modified October 01, 2014 07:25PM UTC

A way to access original options object on widget's creation

Reported by: sparkybg Owned by: sparkybg
Priority: minor Milestone: none
Component: ui.widget Version: 1.11.1
Keywords: Cc:
Blocked by: Blocking:
Description

As stated in documentation, the widget options, provided when widget is instantiated, is deep copied and "extended" with default options and options, provided from _getCreateOptions. But sometimes, a widget may need some of the properties in the original options as an object, not a deep copy.

For example, imagine a group of data widgets (inputs for example), storing their values in different properties of common plain object. For the moment this common data storage object cannot be provided in widgets creation options. The only way is to use $(someting).widget("option",{"dataStore": commonObject}) after the widget is already created.

There is workaround for this, overloading the _createWidget method but this method is not mentioned in API documentation at all, so I consider this as unacceptable.

One way it can be implemented is passing the options object to the _create method, or storing it somewhere, for example in "_options" variable in widget's instance. Both ways will preserve compatibility with current implementation of $.widget.

Attachments (0)
Change History (7)

Changed September 25, 2014 10:58PM UTC by scottgonzalez comment:1

owner: → sparkybg
status: newpending

Why are you setting a default value for the data store? You'll need to provide realistic use cases for us to even consider this.

Changed September 26, 2014 12:18AM UTC by sparkybg comment:2

_comment0: Ok, I will try to be as specific as I can. \ \ Here is a hypothetic case: \ \ 1. We have, for example a "commonDataStore" object: \ \ {{{ \ var commonDataStore={name: "Steven", age:15, location: "USA"} \ }}} \ \ 2. We have 3 "myInput" widgets bound to this data store object, created as follows: \ {{{ \ $("#nameInput").myInput({field:"name", dataStore:commonDataStore}); \ $("#ageInput").myInput({field:"age", dataStore:commonDataStore}); \ $("#locationInput").myInput({field:"location", dataStore:commonDataStore}); \ }}} \ 3. The widgets purpose is to save their value to the common data store object for further processing, either by a web application itself, or to send the entire object to the server via AJAX request or whatever. The widgets themselves are doing this for example every time they loose focus. In order to do so, the widgets must know what common object they are using, and I think the most obvious way to do this is to provide this common data store object when they are created. But, with current implementation of widget factory, when "_create" method is invoked, all pure objects in "this.options" are already deep copied, and extended with default options if available. So, the widgets receive a copy or the "commonDataStore" object instead of the object itself. And, I cannot find any "legal" way to get access to the original data store object other than, for example providing it explicitly with $("#nameInput").myInput("option","dataStore",commonDataStore) after the widgets are created. \ \ So, I think it will be a nice feature if at least the widget's "_create" method has access to the options as provided on creation, not only the copied and extended version of them. For the moment, the internal "_createWidget" method for example has access to them. In fact this method itself is making the copy of the options and extends them with defaults. \ \ For example, this overload works, but _createWidget is internal non-documented function, and I think it is not a good practice to use it: \ \ {{{ \ _createWidget: function(options){ \ this._options = options; //alt: this.dataStore=options.dataStore; \ this._superApply(arguments); \ }, \ \ }}} \ 1411691570253249
_comment1: Ok, I will try to be as specific as I can. \ \ Here is a hypothetic case: \ \ 1. We have a "commonDataStore" object: \ \ {{{ \ var commonDataStore={name: "Steven", age:15, location: "USA"} \ }}} \ \ 2. We have 3 "myInput" widgets bound to this data store object, created as follows: \ {{{ \ $("#nameInput").myInput({field:"name", dataStore:commonDataStore}); \ $("#ageInput").myInput({field:"age", dataStore:commonDataStore}); \ $("#locationInput").myInput({field:"location", dataStore:commonDataStore}); \ }}} \ 3. The widgets purpose is to save their value to the common data store object for further processing, either by a web application itself, or to send the entire object to the server via AJAX request or whatever. The widgets themselves are doing this for example every time they loose focus. In order to do so, the widgets must know what common object they are using, and I think the most obvious way to do this is to provide this common data store object when they are created. But, with current implementation of widget factory, when "_create" method is invoked, all pure objects in "this.options" are already deep copied, and extended with default options if available. So, the widgets receive a copy or the "commonDataStore" object instead of the object itself. And, I cannot find any "legal" way to get access to the original data store object other than providing it explicitly with \ {{{ \ $("#nameInput").myInput("option","dataStore",commonDataStore); \ }}} \ after the widgets are created. \ \ So, I think it will be a nice feature if at least the widget's "_create" method has access to the options as provided on creation, not only the copied and extended version of them. For the moment, only the internal "_createWidget" method has access to them. In fact this method itself is making the copy of the options and extends them with defaults. \ \ This overload works and solves the problem, but _createWidget is internal non-documented function, and I think it is not a good practice to use it: \ \ {{{ \ _createWidget: function(options){ \ this._options = options; //alt: this.dataStore=options.dataStore; \ this._superApply(arguments); \ }, \ \ }}} \ 1411691724008566
status: pendingnew

Ok, I will try to be as specific as I can.

Here is a hypothetic case:

1. We have a "commonDataStore" object:

    var commonDataStore={name: "Steven", age:15, location: "USA"}

2. We have 3 "myInput" widgets bound to this data store object, created as follows:

    $("#nameInput").myInput({field:"name", dataStore:commonDataStore});    
    $("#ageInput").myInput({field:"age", dataStore:commonDataStore});
    $("#locationInput").myInput({field:"location", dataStore:commonDataStore});

3. The widgets purpose is to save their value to the common data store object for further processing, either by a web application itself, or to send the entire object to the server via AJAX request or whatever. The widgets themselves are doing this for example every time they loose focus. In order to do so, the widgets must know what common object they are using, and I think the most obvious way to do this is to provide this common data store object when they are created. But, with current implementation of widget factory, when "_create" method is invoked, all pure objects in "this.options" are already deep copied, and extended with default options if available. So, the widgets receive a copy or the "commonDataStore" object instead of the object itself. And, I cannot find any "legal" way to get access to the original data store object other than providing it explicitly after the widgets are created:

   $("#nameInput").myInput("option","dataStore",commonDataStore);
   ....

So, I think it will be a nice feature if at least the widget's "_create" method has access to the options as provided on creation, not only the copied and extended version of them. For the moment, only the internal "_createWidget" method has access to them. In fact this method itself is making the copy of the options and extends them with defaults.

This overload works and solves the problem, but _createWidget is internal non-documented function, and I think it is not a good practice to use it:

        _createWidget: function(options){
            this._options = options; //alt: this.dataStore=options.dataStore;
            this._superApply(arguments);
        },

Changed September 26, 2014 01:41AM UTC by scottgonzalez comment:3

resolution: → wontfix
status: newclosed

Just make your data store use a real constructor and you won't have a problem. Only plain objects are extended.

Changed September 26, 2014 07:48AM UTC by sparkybg comment:4

_comment0: Replying to [comment:3 scott.gonzalez]: \ > Just make your data store use a real constructor and you won't have a problem. Only plain objects are extended. \ \ I cannot. The data store object in my case is part of array of records, and the array is a result of AJAX response which the browser itself already parsed. Changing records in the array to use constructors will may be a performance penalty - there may be thousands of record in the array. \ \ Anyway it was just a proposition. I think it would be a good practice to give a way for widget instance to decide how to extend it's options out of the default behavior. \ 1411717843012205
_comment1: Replying to [comment:3 scott.gonzalez]: \ > Just make your data store use a real constructor and you won't have a problem. Only plain objects are extended. \ \ \ For several reasons, I cannot. The data store object in my case is a part of array of plain object, and the array is a result of AJAX response which the browser itself already parsed. Changing records in the array to use constructors may be a performance penalty - there may be thousands of record in the array. \ \ Anyway it was just a proposition. I think it would be a good practice to give a way for widget instance to decide how to extend it's options out of the default behavior. \ 1411717867947991
_comment2: Replying to [comment:3 scott.gonzalez]: \ > Just make your data store use a real constructor and you won't have a problem. Only plain objects are extended. \ \ \ For several reasons, I cannot. The data store object in my case is a part of array of plain objects, and the array is a result of AJAX response which the browser itself already parsed. Changing records in the array to use constructors may be a performance penalty - there may be thousands of record in the array. \ \ Anyway it was just a proposition. I think it would be a good practice to give a way for widget instance to decide how to extend it's options out of the default behavior. \ 1411717894394708
_comment3: Replying to [comment:3 scott.gonzalez]: \ > Just make your data store use a real constructor and you won't have a problem. Only plain objects are extended. \ \ \ For several reasons, I cannot. The data store object in my case is a part of array of plain objects, and the array is a result of AJAX response which the browser itself already parsed. Changing records in the array to use constructors may be a performance penalty - there may be thousands of records in the array. \ \ Anyway it was just a proposition. I think it would be a good practice to give a way for widget instance to decide how to extend it's options out of the default behavior. \ 1411721112297561
_comment4: Replying to [comment:3 scott.gonzalez]: \ > Just make your data store use a real constructor and you won't have a problem. Only plain objects are extended. \ \ \ For several reasons, I cannot. The data store object in my case is a part of array of plain objects, and the array is a result of AJAX response which the browser itself already parsed. Changing records in the array to use constructors may be a performance penalty - there may be thousands of records in the array. \ \ Anyway it was just a proposition. I think it would be a good practice to give a way for widget instance to decide how to extend it's options out of the default behavior. \ \ P.S.: Another possible way to do this is to make _createWidget function to use "this._extendOptions" instead of "$.widget.extend", This way, it will be possible to overload the default behavior in widget's definition. Another possible way is to make "_createWidget" to call "_this._extendOptions" which then will be able to decide if and when to use "$.widget.extend". \ \ As far as I can see, up to version 1.8, the options are copied with "$.extend(true,...)" instead which creates copies of Arrays also. Then, in 1.9 and up to 1.11 it uses "$.widget.extend" which does not copy Arrays. This creates incompatibility issues. All this can be avoided in future versions just by providing a documented way for a widget to decide what to do with it's options on creation.1411721433355154

Replying to [comment:3 scott.gonzalez]:

Just make your data store use a real constructor and you won't have a problem. Only plain objects are extended.

For several reasons, I cannot. The data store object in my case is a part of array of plain objects, and the array is a result of AJAX response which the browser itself already parsed. Changing records in the array to use constructors may be a performance penalty - there may be thousands of records in the array.

Anyway it was just a proposition. I think it would be a good practice to give a way for widget instance to decide how to extend it's options out of the default behavior.

P.S.: Another possible way to do this is to make _createWidget function to use "this._extendOptions" instead of "$.widget.extend", This way, it will be possible to overload the default behavior in widget's definition. Another possible way is to make "_createWidget" to call "this._extendOptions", defined in Widget prototype, which then, if overloaded, will be able to decide if and when to use "$.widget.extend".

As far as I can see, up to version 1.8, the options are copied with "$.extend(true,...)" instead which creates copies of Arrays also. Then, in 1.9 and up to 1.11 it uses "$.widget.extend" which does not copy Arrays. This creates incompatibility issues. All this can be avoided in future versions just by providing a documented way for a widget to decide what to do with it's options on creation.

Changed October 01, 2014 04:28PM UTC by scottgonzalez comment:5

So provide the array, that also won't get clobbered. There are already two ways to handle this, we're not going to add a third.

Changed October 01, 2014 07:15PM UTC by sparkybg comment:6

Replying to [comment:5 scott.gonzalez]:

So provide the array, that also won't get clobbered. There are already two ways to handle this, we're not going to add a third.

Forget about the exact case I provided. My proposal was not to create a third or fourth way to do something, but to think about how/if it is possible to overcome this restriction once and for all for any case in any future versions of the widget factory.

Changed October 01, 2014 07:25PM UTC by scottgonzalez comment:7

Replying to [comment:6 sparkybg]:

Forget about the exact case I provided.

Sorry, without specific use cases, nothing ever gets added.