TO DO - Uize.Class
- Contents
- 1. The bind Instance Method
- 2. Virtual Events
- 3. Properties Expressions
- 4. Derived Properties
- 5. Property Bindings
- 6. Copy Ability for State Properties
- 7. Handle Simple Type in Place of Constructor Properties
- 8. Improvements to Property Mechanism
- 9. constructed Property
- 10. Originator of a Set
This is a TO DO document for the Uize.Class
module.
1. The bind Instance Method
Would provide a convenient way to bind the instance as a context to an instance method and arguments.
INSTEAD OF...
setTimeout (function () {m.hideMenu ()},0);
USE...
setTimeout (m.bind ('hideMenu'),0);
IMPLEMENTATION
var _bind = Uize.nop.bind || function (_context) { var _args = [].slice.call (arguments,1), _function = this ; return function () { return _function.apply (_context,_args.concat (Uize.copyList (arguments))); }; }; _class.prototype.bind = function (_method) { var _context = this, _args = arguments ; _args = _args.length > 1 && [].slice.call (_args,1); if (typeof _function == 'string') _function = _context [_function] ; return _args ? _bind.apply (_function,[_context].concat (_args)) : _bind.call (_function,_context); };
1.1. Impact
Would add about 336 bytes to the size of the Uize.Class
module.
The main benefits would be a more elegant semantic for certain situations, and a tiny reduction in code size across the codebase. The savings would only balance out the added weight at large application scale, so the penalty is experienced mostly for smaller apps. Furthermore, most of the benefits would accrue to widget class modules in situations that will be avoided in future by more declarative binding logic. Finally, future versions of JavaScript will bring a bind
method for all functions (already present in most modern browsers), and fat arrow syntax would also help in such situations.
In conclusion, besides being kind of neat, there's negative value in adding this feature at this time.
2. Virtual Events
Similar to the system of virtual DOM events.
Virtual events can be parameterized. When multiple handlers are wired for the same virtual event, the setup for the event is shared amongst all handlers.
2.1. Representing Conditions as Virtual Events
2.1.1. The whenever Virtual Event
EXAMPLES
myWidget.wire ( Uize.Class.virtualEvent ('whenever','theme => theme == "bottle"'), function () { // do stuff whenever condition is met } ); myWidget.wire ( Uize.Class.virtualEvent ('whenever',function (theme) {return theme == 'bottle'}), function () { // do stuff whenever condition is met } ); myWidget.wire ( 'whenever("theme => theme == \'bottle\'")', function () { // do stuff whenever condition is met } );
2.2. The next Virtual Event
EXAMPLES
myWidget.wire ( 'next("Click")', function () { // do something for only the very next click } ); myWidget.onNext( 'Click', function () { // do something for only the very next click } );
3. Properties Expressions
SYNTAX
propertiesExpressionFUNC = Uize.propertiesExpression (expressionFUNC);
INSTEAD OF...
function (object) { return object.get ('width') * object.get ('height'); }
USE...
Uize.propertiesExpression ( function (width,height) {return width * height}; }
4. Derived Properties
A derived property is a special type of state property whose value is derived from the values of other state properties of the same instance.
EXAMPLE
_class.stateProperties ({ _allSelected:{ name:'allSelected', derived:'totalSelected,totalItems: totalSelected > 0 && totalSelected == totalItems' }, _oneSelected:{ name:'oneSelected', derived:'totalSelected: totalSelected == 1' }, _someSelected:{ name:'someSelected', derived:'totalSelected: totalSelected > 0' }, _totalSelected:{ name:'totalSelected', value:0 }, _totalItems:{ name:'totalItems', value:0 } });
In the above example, the allSelected
, oneSelected
, and someSelected
state properties are all derived properties. A state property is indicated as being a derived property by the presence of the derived
property in the property profile. The derived
property serves both to indicate that a state property is derived, as well to provide the deriver function that indicates from which other state properties the derived property is derived and how to calculate the derived value.
4.1. Implementation Questions
4.1.1. How Are Derived Properties Inherited
Currently, profiles for state properties are inherited through cloning of the definition objects.
If dynamically generated summary information is needed to improve the performance of derived properties, when will this summary information be generated for a class? And how is the information regenerated if it is invalidated by the subsequent declaration of more derived properties.
4.2. Implementation Approaches
4.2.1. Exploding Out the Properties Being Set
With this approach, setting values for derived state properties is worked into the process of setting values for properties that affect derived properties, by exploding out the properties being set to include all affected derived properties.
After setting values for the state properties that are being set explicitly, and before executing onChange handlers for any state properties whose values have changed, the declared state properties are scanned for derived state properties that may be affected by the properties being set explicitly. If any derived state properties are affected by any of the state properties whose values have changed, then values are computed for those derived properties and their values are set. This process is repeated to address state properties that are derived from derived properties whose values may have changed. The process is repeated until there are no longer any derived properties that are affected and that have not had new values computed.
4.2.1.1. Advantages
.
4.2.1.2. Disadvantages
.
4.2.2. Single Level Derived Property Batching
With this approach, values for all directly affected derived state properties are set in a batch set that occurs before onChange
handlers are executed for the state properties being explicitly set.
4.2.3. Using onChange Handler Mechanism
With this approach, when a derived state property is declared, an onChange handler is registered with any property from which the derived property is derived.
4.2.3.1. Advantages
uses the existing optimization built into the onChange handlers mechanism |
|
matches the way values for derived state properties are currently being updated |
4.2.3.2. Disadvantages
involves a separate set for each derived state property whose value changes | |
requires management of onChange handlers and dealing with situations where state properties are re-declared |
4.2.3.3. Issues to Deal With
4.2.3.3.1. Re-declaring a Non-derived State Property
How does one deal with re-declaring a state property that affects a derived state property?
Currently, everything gets blown away when re-declaring a state property. This means that the onChange
handler that was added to the state property at the time of declaring the state property that is derived from it will get blown away, and the relationship of the derived property to the property from which it is derived will get blown away.
4.2.3.3.2. Re-declaring a Derived State Property
How does one deal with re-declaring a derived state property, where the new profile for the derived property defines a different relationship properties from which it is derived?
5. Property Bindings
Provide a way in the Uize.Class
base class to bind two state properties together, in order to keep their values synchronized.
This would provide a more concise and lightweight way of binding properties than using an instance of the Uize.Util.PropertyAdapter
class.
INSTEAD OF...
Uize.Util.PropertyAdapter ({propertyA:[this,'prop'],propertyB:[slider,'prop']});
USE...
m.bindProperty ('prop',[slider,'prop']);
BENEFITS
The bindProperty instance method would be a core capability of the Uize.Class base class, and all classes would get to benefit from this. |
|
The bindProperty instance method should require a little less code to implement than the Uize.Util.PropertyAdapter class. |
NOTES
The bindProperty instance method would support an optional value adapter, just like the Uize.Util.PropertyAdapter class. |
|
The bindProperty instance method would return an array of all the wirings created, so that they could be unwired later. |
|
The bindProperty instance method should ideally be implemented by factoring some code out of the Uize.Util.PropertyAdapter class, and then the Uize.Util.PropertyAdapter class could be reduced in size and made to leverage the bindProperty implementation in the Uize.Class base class. |
6. Copy Ability for State Properties
Copy ability, for initial values of state properties that are arrays or objects.
Have a property that can be specified in a state property's profile, which can be used to cause properties whose initial values are object types to be initialized by cloning the initial value rather than simply setting a reference to a shared object.
7. Handle Simple Type in Place of Constructor Properties
Variation on constructor, where specifying a non-object for the properties has the effect of setting the value property.
For example, if Uize.Color
were to become a subclass of Uize.Class
...
EXAMPLE
Uize.Color ({value:'#ffffff'}); // old form Uize.Color ('#ffffff'); // new form
Or, in the case of an existing widget class that supports the value interface...
EXAMPLE
Uize.Widget.Bar.Slider ({value:50}); // old form Uize.Widget.Bar.Slider (50); // old form
8. Improvements to Property Mechanism
8.1. New Profile Features
8.1.1. type
Can be used by interpolation code (such as fades).
Basic types...
string (coerce with value + '', implicit initial value is '') | |
boolean (coerce with !!value, implicit initial value is false) | |
number (coerce with +value, implicit initial value is 0) | |
date (coerce with new Date (value), implicit initial value is now) |
Extended types (ideas for other useful types)...
switch (valid string values for true value, implicit initial value is false) | |
integer (coerce with Math.round (value)) |
8.1.2. validator
Different types of validators...
function that can return true or false | |
regular expression | |
array of valid values |
General ideas / principles for validators...
a validator is a test | |
a validator may run asynchronously | |
a validator may compose other validators | |
if a validation fails, there can be a summuary, and arbitrary details specific to the validation |
support for read-only properties (how would that work, exactly? Only settable through private name?) | |
problem: there's currently no way to use the set method to set the value for a state property to undefined. This is lame. The original reason for this had to do with the optimizing performance for the very first set during construction. This behavior is beneficial for state properties that have no initial value (what percentage of the overall is that?). |
9. constructed Property
to indicate that the instance has been constructed | |
can be used by onChange handlers for state properties to conditionalize actions | |
particularly compelling to widgets, since being completely constructed is a good indicator child widgets added during construction exist and can be accessed | |
some classes may already be doing this with their own private properties |
10. Originator of a Set
The originator of a property set knows that the property is being set, so doesn't want to be informed of a change in the value?
A way to provide an ID for the originator of a set? The basic ongoing problem is when multiple sources want to be able to change and also be informed of changes in a particular property. How does one make this more efficient and eliminate multiple redundant execution triggered by events?