diff --git a/docs/default.md b/docs/default.md index 5069cde..1bdc0f9 100644 --- a/docs/default.md +++ b/docs/default.md @@ -27,7 +27,7 @@ If the default value should be an object of some type, it should be specified as Any value can be provided as the default value used for this property, like: -``` +```js { prop: { default: 'foo' @@ -44,6 +44,7 @@ Any value can be provided as the default value used for this property, like: The following defaults `age` to `0` and `address` to an object: ```js +import { DefineMap } from "can" // A default age of `0`: const Person = DefineMap.extend( { age: { @@ -55,7 +56,11 @@ const Person = DefineMap.extend( { } } } ); + +const person = new Person(); +console.log(person.age); //-> 0 ``` +@codepen ## Alternates diff --git a/docs/defaultConstructor.md b/docs/defaultConstructor.md index 56d747b..9b30720 100644 --- a/docs/defaultConstructor.md +++ b/docs/defaultConstructor.md @@ -27,6 +27,8 @@ Specify `Default` like: ## Use ```js +import { DefineMap } from "can"; + const Address = DefineMap.extend( { street: { type: "string", value: "321 Longbow" }, city: { type: "string", value: "Dallas" } @@ -41,6 +43,7 @@ const direction = new Direction( { to: { street: "2070 N. Stave" } } ); -direction.from.street; //-> "321 Longbow" -direction.to.street; //-> "2070 N. Stave" +console.log(direction.from.street); //-> "321 Longbow" +console.log(direction.to.street); //-> "2070 N. Stave" ``` +@codepen diff --git a/docs/type.md b/docs/type.md index 424545d..bd28d2f 100644 --- a/docs/type.md +++ b/docs/type.md @@ -82,8 +82,8 @@ as either: - A type function that returns the type coerced value. - A named type in [can-define.types]. -- An object that gets converted into an inline `DefineMap`. -- An array that gets converted to an inline `DefineList`. +- An object that gets converted into an inline `[can-define/map/map DefineMap]`. +- An array that gets converted to an inline `[can-define/list/list DefineList]`. ### Basic Example diff --git a/docs/types.get.md b/docs/types.get.md index 00415a3..ca846d6 100644 --- a/docs/types.get.md +++ b/docs/types.get.md @@ -25,7 +25,7 @@ Specify `get` like: ``` @param {*} [lastSetValue] The value last set by `instance.propertyName = value`. Typically, _lastSetValue_ - should be an observable value, like a [can-compute] or promise. If it's not, it's likely + should be an observable value, like a [can-simple-observable] or promise. If it's not, it's likely that a [can-define.types.set] should be used instead. @return {*} The value of the property. @@ -74,6 +74,8 @@ Whenever a getter is provided, it is wrapped in a [can-compute], which ensures that whenever its dependent properties change, a change event will fire for this property also. ```js +import { DefineMap } from "can"; + const Person = DefineMap.extend( { first: "string", last: "string", @@ -86,14 +88,15 @@ const Person = DefineMap.extend( { const p = new Person( { first: "Justin", last: "Meyer" } ); -p.fullName; // "Justin Meyer" +console.log(p.fullName); //-> "Justin Meyer" p.on( "fullName", function( ev, newVal ) { - newVal; //-> "Lincoln Meyer"; + console.log(newVal); //-> "Lincoln Meyer"; } ); p.first = "Lincoln"; ``` +@codepen ## Asynchronous virtual properties @@ -101,6 +104,8 @@ Often, a virtual property's value only becomes available after some period of ti given a `personId`, one might want to retrieve a related person: ```js +import { DefineMap } from "can"; + const AppState = DefineMap.extend( { personId: "number", person: { @@ -167,22 +172,25 @@ For example, a property might be set to a compute, but when read, provides the v of the compute. ```js +import { DefineMap, SimpleObservable, Reflect } from "can"; + const MyMap = DefineMap.extend( { - value: { - get: function( lastSetValue ) { - return lastSetValue(); - } - } + value: { + get: function( lastSetValue ) { + return lastSetValue.value; + } + } } ); const map = new MyMap(); -const compute = compute( 1 ); -map.value = compute; +const observable = new SimpleObservable( 1 ); +map.value = observable; -map.value; //-> 1 -compute( 2 ); -map.value; //-> 2 +console.log(map.value); //-> 1 +Reflect.setValue(observable, 2); +console.log(map.value); //-> 2 ``` +@codepen This technique should only be used when the `lastSetValue` is some form of observable, that when it changes, can update the `getter` value. @@ -200,16 +208,24 @@ the [can-define/list/list] will be updated with the `id`s of the `locations`. ```js +import { DefineMap, DefineList } from "can"; + const Store = DefineMap.extend( { - locations: DefineList, + locations: { Default: DefineList }, locationIds: { Default: DefineList, get: function( initialValue ) { const ids = this.locations.map( function( location ) { - ids.push( location.id ); + return location.id; } ); return initialValue.replace( ids ); } } } ); + +const s = new Store(); +console.log(s.locationIds[0]); //-> undefined +s.locations.push({ id: 1 }); +console.log(s.locationIds[0]); //-> 1 ``` +@codepen diff --git a/docs/types.propDefinition.md b/docs/types.propDefinition.md index 1db1dc7..032839a 100644 --- a/docs/types.propDefinition.md +++ b/docs/types.propDefinition.md @@ -23,40 +23,46 @@ observable property. These behaviors can be specified with as an `Object`, `Str } ``` - @option {can-define.types.default} default Specifies the initial value of the property or - a function that returns the initial value. + @option {can-define.types.default} default Specifies the initial value of the property or a function that returns the initial value. ```js +import { DefineMap } from "can"; + // A default age of `0`: const Person = DefineMap.extend( { - age: { - value: 0 - }, - address: { - value: function() { - return { city: "Chicago", state: "IL" }; - } - } + age: { + default: 0 + }, + address: { + default: function() { + return { city: "Chicago", state: "IL" }; + } + } } ); + +const person = new Person(); +console.log(person.age); //-> 0 ``` - @option {can-define.types.defaultConstructor} Default Specifies a function that will be called with `new` whose result is - set as the initial value of the attribute. + @option {can-define.types.defaultConstructor} Default Specifies a function that will be called with `new` whose result is set as the initial value of the attribute. ```js +import { DefineMap, DefineList } from "can"; + // A default empty DefineList of hobbies: const Person = DefineMap.extend( { hobbies: { Default: DefineList } } ); -new Person().hobbies; //-> [] +const person = new Person(); +console.log(person.hobbies); //-> [] ``` - @option {can-define.types.type} type Specifies the type of the - property. The type can be specified as either a function - that returns the type coerced value or one of the [can-define.types] names. + @option {can-define.types.type} type Specifies the type of the property. The type can be specified as either a function that returns the type coerced value or one of the [can-define.types] names. ```js +import { DefineMap } from "can"; + const Person = DefineMap.extend( { age: { type: "number" }, hobbies: { @@ -69,13 +75,16 @@ const Person = DefineMap.extend( { } } } ); + +const person = new Person({ age: 20, hobbies: "1,2,3" }); +console.log(person.age, person.hobbies); //-> 20, [1,2,3] ``` - @option {can-define.types.typeConstructor} Type A constructor function that takes - the assigned property value as the first argument and called with new. For example, the following will call - `new Address(newValue)` with whatever non null, undefined, or address type is set as a `Person`'s address property. + @option {can-define.types.typeConstructor} Type A constructor function that takes the assigned property value as the first argument and called with new. For example, the following will call `new Address(newValue)` with whatever non null, undefined, or address type is set as a `Person`'s address property. ```js +import { DefineMap } from "can"; + const Address = DefineMap.extend( { street: "string", state: "string" @@ -84,22 +93,32 @@ const Address = DefineMap.extend( { const Person = DefineMap.extend( { address: { Type: Address } } ); -``` - +const person = new Person({ + address: { + street: "Example Ave.", + state: "IL" + } +}); +console.log(person.address.street); //-> "Example Ave." +``` - @option {can-define.types.get} get A function that specifies how the value is retrieved. The get function is - converted to an [can-compute.async async compute]. It should derive its value from other values on the object. The following - defines a `page` getter that reads from a map's offset and limit: + @option {can-define.types.get} get A function that specifies how the value is retrieved. The get function is converted to an [can-compute.async async compute]. It should derive its value from other values on the object. The following defines a `page` getter that reads from a map's offset and limit: ```js -DefineMap.extend( { +import { DefineMap } from "can"; + +const pages = DefineMap.extend( { + offset: 10, + limit: 5, page: { get: function( newVal ) { return Math.floor( this.offset / this.limit ) + 1; } } } ); + +console.log(pages.page) //-> 3 ``` A `get` definition makes the property __computed__ which means it will not be enumerable by default. @@ -109,7 +128,9 @@ DefineMap.extend( { counts the number of times the `page` property changes: ```js -DefineMap.extend( { +import { DefineMap } from "can"; + +const book = DefineMap.extend( { pageChangeCount: function( prop ) { let count = 0; @@ -122,12 +143,14 @@ DefineMap.extend( { prop.resolve( count ); } } ); +book.page = 1; +book.page += 1; +console.log(book.count); //-> 2 ``` A `value` definition makes the property __computed__ which means it will not be enumerable by default. - @option {can-define.types.set} set A set function that specifies what should happen when a property is set. `set` is called with the result of `type` or `Type`. The following - defines a `page` setter that updates the map's offset: + @option {can-define.types.set} set A set function that specifies what should happen when a property is set. `set` is called with the result of `type` or `Type`. The following defines a `page` setter that updates the map's offset: ```js DefineMap.extend( { @@ -206,7 +229,7 @@ OR @type {Array} Defines an inline [can-define/list/list] Type setting. This is used as a shorthand for creating a property that is an [can-define/list/list] of another type. -``` +```js { propertyName: [Constructor | propDefinitions] } @@ -252,11 +275,9 @@ This is a shorthand for providing an object with a `get` property like: } ``` -You must use an object with a [can-define.types.get] property if you want your get to take the `lastSetValue` -or `resolve` arguments. +You must use an object with a [can-define.types.get] property if you want your get to take the `lastSetValue` or `resolve` arguments. -@type {SETTER} Defines a property's [can-define.types.set] behavior with the -[set syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set). +@type {SETTER} Defines a property's [can-define.types.set] behavior with the [set syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set). ```js { @@ -278,7 +299,7 @@ For example: This is a shorthand for providing an object with a `set` property like: -``` +```js { fullName: { set: function(newValue){ @@ -305,19 +326,19 @@ get converted to a `PropDefinition` as follows: ```js DefineMap.extend( { - propertyA: Object, // -> PropertyDefinition - propertyB: String, // -> {type: String} - propertyC: Constructor, // -> {Type: Constructor} - propertyD: [ PropDefs ], // -> {Type: DefineList.extend({"#": PropDefs})>} + propertyA: Object, // -> PropertyDefinition + propertyB: String, // -> {type: String} + propertyC: Constructor, // -> {Type: Constructor} + propertyD: [ PropDefs ], // -> {Type: DefineList.extend({"#": PropDefs})>} get propertyE() { /* ... */ }, // -> {get: propertyE(){ /* ... */ }} - set propertyF( value ) { /* ... */ }, // -> {set: propertyF(value){ /* ... */ }} + set propertyF( value ) { /* ... */ }, // -> {set: propertyF(value){ /* ... */ }}, method: Function } ); ``` Within a property definition, the available properties and their signatures look like: -``` +```js DefineMap.extend({ property: { get: function(lastSetValue, resolve){...}, @@ -338,6 +359,12 @@ For example: ```js +import { DefineMap } from "can"; +const Address = DefineMap.extend( "Address", { + street: "string", + state: "string" +} ); + const Person = DefineMap.extend( "Person", { // a `DefineList` of `Address` @@ -355,4 +382,9 @@ const person = new Person( { name: { first: "Kath", last: "Iann" }, cars: [ { make: "Nissan", year: 2010 } ] } ); + +console.log(person.addresses[0].street); //-> "1134 Pinetree" +console.log(person.name.first); //-> "Kath" +console.log(person.cars[0].make); //-> "Nissan" ``` +@codepen \ No newline at end of file diff --git a/docs/types.set.md b/docs/types.set.md index 12054b9..2b19056 100644 --- a/docs/types.set.md +++ b/docs/types.set.md @@ -65,19 +65,30 @@ The following makes setting a `page` property update the `offset`: ```js -{ - page: { - set: function( newVal ) { - this.offset = ( parseInt( newVal ) - 1 ) * this.limit; - } - } -} +import { DefineMap } from "can"; + +const Pages = DefineMap.extend( { + limit: { default: 5 }, + offset: { default: 0 }, + page: { + set: function( newVal ) { + this.offset = ( parseInt( newVal ) - 1 ) * this.limit; + } + } +} ); +const book = new Pages(); +book.page = 10; +console.log(book.offset); //-> 45 ``` +@codepen The following makes changing `makeId` un-define the `modelId` property: ```js -{ +import { DefineMap } from "can"; + +const Car = DefineMap.extend( { + modelId: { default: undefined }, makeId: { set: function(newValue){ // Check if we are changing. @@ -88,8 +99,14 @@ The following makes changing `makeId` un-define the `modelId` property: return newValue; } } -} +} ); + +const myCar = new Car({ makeId: "GMC", modelId: "Jimmy" }); +console.log(myCar.modelId) ;//-> "Jimmy" +myCar.makeId = "Chevrolet"; +console.log(myCar.modelId); //-> undefined ``` +@codepen #### Asynchronous Setter diff --git a/docs/value.md b/docs/value.md index 5273325..5302e45 100644 --- a/docs/value.md +++ b/docs/value.md @@ -220,8 +220,9 @@ const Person = DefineMap.extend( "Person", { } ); const p = new Person({ first: "John", last: "Smith" }); +p.on("fullNameChangeCount", () => {}); p.first = "Justin"; p.last = "Meyer"; console.log(p.fullNameChangeCount); //-> 2 ``` - \ No newline at end of file +@codepen \ No newline at end of file