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 comment:1
owner: | → sparkybg |
---|---|
status: | new → pending |
Changed September 26, 2014 12:18AM UTC by 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: | pending → new |
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 comment:3
resolution: | → wontfix |
---|---|
status: | new → closed |
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 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 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 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 comment:7
Replying to [comment:6 sparkybg]:
Forget about the exact case I provided.
Sorry, without specific use cases, nothing ever gets added.
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.