can-observe
Version:
Like can.Map, but without the .attr method.
196 lines (145 loc) • 4.18 kB
Markdown
{function} can-observe.Object Object
can-observe/properties
true
Create observable key-value instances or types.
`new observe.Object(properties)`
Create an instance of an observable object.
```js
import observe from "can-observe";
const person = new observe.Object( { name: "Frank Castle" } );
```
Unlike `observe({name: "Frank Castle"})`, `person` will
have [mixed-in methods and properties](#Mixedinmethodsandproperties) like `.on` and
`.off` available.
`class extends observe.Object {...}`
Extend and create your own `Object` type:
```js
import observe from "can-observe";
class Person extends observe.Object {
get fullName() {
return this.first + " " + this.last;
}
}
```
Getter properties like `fullName` above are computed. Meaning that if they are bound
subsequent reads are not re-evaluated.
Instances of `Person` will
have [mixed-in methods and properties](#Mixedinmethodsandproperties) like `.on` and
`.off` available.
## Mixed in methods and properties
Instances of `observe.Object` have all methods and properties from
[can-event-queue/map/map]:
{{#each (getChildren [can-event-queue/map/map])}}
- [{{name}}] - {{description}}{{/each}}
Example:
```js
class MyObject extends observe.Object {
}
const instance = new MyObject( {} );
canReflect.onPatches( instance, function( patches ) { /* ... */ } );
```
## Mixed-in type methods and properties
Extended `observe.Object` constructor functions have all methods and properties from
[can-event-queue/type/type]:
{{#each (getChildren [can-event-queue/type/type])}}
- [{{name}}] - {{description}}{{/each}}
Example:
```js
class MyObject extends observe.Object {
}
canReflect.onInstancePatches( MyObject, function( instance, patches ) { /* ... */ } );
```
## Use Cases
`observe.Object` is used to make observable __models__ and __view-models__.
## ViewModels
Use `observe.Object` to create __view-models__ for use with [can-component]. The following
creates a `TodoListVM` and and uses it with the `todo-list` component:
```js
class TodoListVM extends observe.Object {
isEditing( todo ) {
return todo === this.editing;
}
edit( todo ) {
this.backupName = todo.name;
this.editing = todo;
}
cancelEdit() {
if ( this.editing ) {
this.editing.name = this.backupName;
}
this.editing = null;
}
updateName() {
this.editing.save();
this.editing = null;
}
}
Component.extend( {
tag: "todo-list",
view,
ViewModel: TodoListVM
} );
```
### Special behaviors
`observe.Object` lacks many of the extended features of [can-define]. This means you often need to
add this behavior manually.
When simple `getters` can be used, use [can-component/connectedCallback] to update properties based on other
values. The following keeps `todosList` updated with changes in `todosPromise`:
```js
class AppVM extends observe.Object {
get todosPromise() {
if ( !this.filter ) {
return Todo.getList( {} );
} else {
return Todo.getList( {
complete: this.filter === "complete"
} );
}
}
connectedCallback() {
this.listenTo( "todosPromise", ( promise ) => {
promise.then( ( todos ) => {
this.todosList = todos;
} );
} );
this.todosPromise.then( ( todos ) => {
this.todosList = todos;
} );
return this.stopListening.bind( this );
}
}
```
If you'd like a property to be non-enumerable, you need to define this during
initialization of your instance within `constructor`. The following makes
`todosList` non-enumerable:
```js
class AppVM extends observe.Object {
constructor( props ) {
super( props );
Object.defineProperty( this, "todosList", {
enumerable: false,
value: null,
configurable: true,
writable: true
} );
}
}
```
## Models
Use `observe.Object` to create observable view-models for use
with [can-connect]. The following creates a simple `Todo` type:
```js
import observe from "can-observe";
import baseMap from "can-connect/can/base-map/base-map";
class Todo extends observe.Object {
updateName( newName ) {
this.name = newName;
this.updatedAt = new Date().getTime();
}
}
baseMap( {
url: "/api/todos",
Map: Todo
} );
```