ampersand-state
Advanced tools
Comparing version 4.5.4 to 4.5.5
{ | ||
"name": "ampersand-state", | ||
"description": "An observable, extensible state object with derived watchable properties.", | ||
"version": "4.5.4", | ||
"version": "4.5.5", | ||
"author": "Henrik Joreteg <henrik@andyet.net>", | ||
@@ -6,0 +6,0 @@ "files": [ |
@@ -15,7 +15,2 @@ # ampersand-state | ||
## browser support | ||
[![browser support](https://ci.testling.com/ampersandjs/ampersand-state.png) | ||
](https://ci.testling.com/ampersandjs/ampersand-state) | ||
## Install | ||
@@ -57,3 +52,3 @@ | ||
`AmpersandState.extend` does more than just copy attributes from one prototype to another. As such it is incompatible with Coffeescript's class-based extend. TypeScript users may have similar issues. | ||
`AmpersandState.extend` does more than just copy attributes from one prototype to another. As such it is incompatible with Coffeescript's class-based extend. TypeScript users may have similar issues. | ||
@@ -223,15 +218,15 @@ For instance, this will not work since it never actually calls `AmpersandState.extend`: | ||
ampersand-state defines several built-in datatypes: `string`, `number`, `boolean`, `array`, `object`, `date`, or `any`. Of these, `object`, `array` and `any` allow for a lot of extra flexibility. However sometimes it may be useful to define your own custom datatypes. Then you can use these types in the `props` below with all their features (like `required`, `default`, etc). | ||
ampersand-state defines several built-in datatypes: `string`, `number`, `boolean`, `array`, `object`, `date`, `state`, or `any`. Of these, `object`, `array` and `any` allow for a lot of extra flexibility. However sometimes it may be useful to define your own custom datatypes. Then you can use these types in the `props` below with all their features (like `required`, `default`, etc). | ||
To define a type, you generally will provide an object with 4 member functions (though only 2 are usually necessary) `get`, `set`, `default`, and `compare`. | ||
To define a type, you generally will provide an object with 4 member functions (though only 2 are usually necessary) `get`, `set`, `default`, and `compare`. | ||
* `set : function(newVal){}; returns {type : type, val : newVal};`: Called on every set. Should return an object with two members: `val` and `type`. If the `type` value does not equal the name of the dataType you defined, a `TypeError` should be thrown. | ||
* `compare : function(currentVal, newVal, attributeName){}; returns boolean`: Called on every `set`. Should return `true` if `oldVal` and `newVal` are equal. Non-equal values will eventually trigger `change` events, unless the state's `set` (not the dataTypes's!) is called with the option `{silent : true}`. | ||
* `get : function(val){} returns val;`: Overrides the default getter of this type. Useful if you want to make defensive copies. For example, the `date` dataType returns a clone of the internally saved `date` to keep the internal state consistent. | ||
* `default : function(){} returns val;`: Returns the default value for this type. | ||
* `get : function(val){} returns val;`: Overrides the default getter of this type. Useful if you want to make defensive copies. For example, the `date` dataType returns a clone of the internally saved `date` to keep the internal state consistent. | ||
* `default : function(){} returns val;`: Returns the default value for this type. | ||
For example, let's say your application uses a special type of date, `JulianDate`. You'd like to setup this as a type in state, but don't want to just use `any` or `object` as the type. To define it: | ||
```javascript | ||
// Julian Date is a 'class' defined elsewhere: | ||
// Julian Date is a 'class' defined elsewhere: | ||
// it has an 'equals' method and takes `{julianDays : number}` as a constructor | ||
@@ -243,3 +238,3 @@ | ||
// set called every time someone tried to set a property of this datatype | ||
set : function(newVal){ | ||
set : function(newVal){ | ||
if(newVal instanceof JulianDate){ | ||
@@ -254,3 +249,3 @@ return { | ||
var newDate = new JulianDate(newVal); | ||
return { | ||
@@ -272,3 +267,3 @@ val : newDate, | ||
} | ||
} | ||
@@ -282,3 +277,3 @@ props : { | ||
// assuming an 'add' function on julian date which returns a new JulianDate | ||
return this.bornOn.add('60','years'); | ||
return this.bornOn.add('60','years'); | ||
} | ||
@@ -295,7 +290,7 @@ } | ||
// and will also trigger a change event | ||
person.bornOn = {julianDays : 1001}; | ||
person.bornOn = {julianDays : 1001}; | ||
// but this will not trigger a change event since the equals method would return true | ||
person.bornOn = {julianDays : 1001}; | ||
``` | ||
@@ -315,7 +310,7 @@ | ||
* If `required` is `true`, one of two things will happen | ||
* If the property has a `default`, it will start with that value, and revert to it after a call to `unset(propertyName)`. | ||
* If the property has a `default`, it will start with that value, and revert to it after a call to `unset(propertyName)`. | ||
* If the property does not have a `default`, calls to `unset(propertyName)` will throw an error. | ||
* If `values` array is passed, then you'll be able to change a property to one of those values only. | ||
* If `setOnce` is `true`, then you'll be able to set property only once. | ||
* If the property has a `default`, and you don't set the value initially, the property will be permanently set to the default value. | ||
* If the property has a `default`, and you don't set the value initially, the property will be permanently set to the default value. | ||
* If the property doesn't have a `default`, and you don't set the value initially, it can be set later, but only once. | ||
@@ -341,2 +336,10 @@ | ||
#### reserved prop, session names | ||
The following should not be used as `prop` names for any state object. This of course includes things based on state such as ampersand-model and ampersand-view. | ||
If you're consuming an API you don't control, you can re-name keys by overwriting `parse` and `serialize` methods. | ||
`bind`, `changedAttributes`, `cid`, `clear`, `collection`, `constructor`, `createEmitter`, `escape`, `extraProperties`, `get`, `getAttributes`, `getId`, `getNamespace`, `getType`, `hasChanged`, `idAttribute`, `initialize`, `isNew`, `isValid`, `listenTo`, `listenToAndRun`, `listenToOnce`, `namespaceAttribute`, `off`, `on`, `once`, `parent`, `parse`, `previous`, `previousAttributes`, `serialize`, `set`, `stopListening`, `toJSON`, `toggle`, `trigger`, `typeAttribute`, `unbind`, `unset`, `url` | ||
#### defaulting to objects/arrays | ||
@@ -447,5 +450,34 @@ | ||
**note:** If you want to be able to swap out and get a `change` event from a child model, don't use `children` instead, define a prop in `props` of type `state`. | ||
`children` and `collections` are not just a property of the parent, they're *part* of the parent. When you create the parent, an instance of any children or collections will be instantiated as part of instantiating the parent, whether they have any data or not. | ||
Calling `.set()` on the parent with a nested object will automatically `set()` them on children and collections too. This is super handy for APIs [like this one](https://developer.github.com/v3/repos/#response) that return nested JSON structures. | ||
Also, there will be no `change` events triggered if you replace a child with something else after you've instantiated the parent because it's not a true property in the `props` sense. If you need a prop that stores a state instance, define it as such, don't use `children`. | ||
The distinction is important because without it, the following would be problemmatic: | ||
``` | ||
var Person = State.extend({ | ||
props: { | ||
child: { | ||
type: 'state' | ||
} | ||
} | ||
}); | ||
var person = new Person() | ||
// throws type error because `{}` isn't a state object | ||
person.child = {}; | ||
// should this work? What should happen if the `child` prop isn't defined yet? | ||
person.set({child: {name: 'mary'}}); | ||
``` | ||
So, while having `children` in addition to props of type `state` may feel redundant they both exist to help disambiguate how they're meant to be used. | ||
### collections `AmpersandState.extend({ collections: { widgets: Widgets } })` | ||
Define child collection objects to attach to the object. Attributes passed to the constructor or to `set()` will be proxied to the collections. | ||
Define child collection objects to attach to the object. Attributes passed to the constructor or to `set()` will be proxied to the collections. | ||
@@ -479,3 +511,3 @@ **Note:** Currently, events *don't* automatically proxy from collections to parent. This is for efficiency reasons. But there are ongoing discussions about how to best handle this. | ||
var me = new Person({ | ||
name: 'Henrik', | ||
name: 'Henrik', | ||
widgets: [ | ||
@@ -571,3 +603,3 @@ { name: 'rc car', funLevel: 8 }, | ||
Clear all the attributes from the state object, by calling the `unset` function for each attribute, with the options provided. | ||
Clear all the attributes from the state object, by calling the `unset` function for each attribute, with the options provided. | ||
@@ -676,4 +708,2 @@ ```javascript | ||
## Changelog | ||
<!-- starthide --> | ||
@@ -680,0 +710,0 @@ ## Credits |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
59341
704