Skip to content

Commit 3c89d74

Browse files
author
Vlad Balin
committed
Refactored record's updates and change events docs
1 parent 248a059 commit 3c89d74

File tree

3 files changed

+173
-109
lines changed

3 files changed

+173
-109
lines changed

docsource/03_General_concepts/02_Updates_and_change_events.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1-
## Transactional updates
1+
#### node.set( values, options? )
2+
3+
24

35
#### node.transaction( fun : ( self : this ) => void, options : TransactionOptions = {} ) : void{
4-
#### node.set( values : any, options? : TransactionOptions ) : this {
6+
57

68
## Change events
79

docsource/04_Record/03_Events_and_Transactions.md

Lines changed: 0 additions & 107 deletions
This file was deleted.
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
## Update record attributes
2+
3+
#### record.attrName = val
4+
5+
Assign record attribute.
6+
7+
1. Assign new attribute value.
8+
2. If value has changed,
9+
- trigger `change:attrName` *( record, value )* event.
10+
- trigger `change` *( record )* event.
11+
12+
#### record.set( { attrName : val, ... }, options? : `options` )
13+
14+
Bulk assign record's attributes, possibly taking options.
15+
16+
1. Assign new attribut values.
17+
2. For any changed attribute, trigger `change:attrName` *( record, val, options )* event.
18+
3. If any attribute has changed:
19+
- trigger `change` *(record, options)* event.
20+
21+
#### `options` { parse : true }
22+
23+
Transform `record.set` argument with user-defined parse logic. Typically used to process the responce from the server to make user-defined JSON format conversion.
24+
25+
#### `options` { merge : true }
26+
27+
Merge attributes of record and collection types instead of replacement. If the new instance of record or collection is to be assigned,
28+
update the current instances instead.
29+
30+
#### record.assignFrom( otherRecord )
31+
32+
Makes the `record` to be the copy of `otherRecord`, recursively assigning all attributes.
33+
34+
Works similar to `record.set( otherRecord.attributes, { merge : true });
35+
36+
## Listening to events
37+
38+
### Deep changes detection
39+
40+
Records automatically listens to change events of nested records and collections, and triggers the corresponding change events on its attributes. It means that the single attribute change deeply inside of aggregation tree will trigger change events on all the parents in a sequence.
41+
42+
#### `attrDef` attr : Type.has.changeEvents( false )
43+
44+
Do _not_ listen for the inner changes of the `attr`.
45+
46+
### Custom attribute change watchers
47+
48+
Declaratively attach the watcher in attribute definition. Subscription will be managed automatically.
49+
50+
#### `attrDef` attr : Type.has.watcher( 'methodName' )
51+
#### `attrDef` attr : Type.has.watcher( function( value, name ){ ... } )
52+
53+
Attach `change:attr` event listener to the particular record's attribute.
54+
55+
_Watcher function_ has the signature `( attrValue, attrName ) => void` and is executed in the context of the record.
56+
57+
```javascript
58+
@define class User extends Record {
59+
static attributes = {
60+
name : String.has.watcher( 'onNameChange' ),
61+
isAdmin : Boolean,
62+
}
63+
64+
onNameChange(){
65+
// Cruel. But we need it for the purpose of the example.
66+
this.isAdmin = this.name.indexOf( 'Admin' ) >= 0;
67+
}
68+
}
69+
```
70+
71+
### Generic event API
72+
73+
Generic events API can be used to listen to any record's events.
74+
75+
#### listener.listenTo( record, eventName, handler )
76+
#### listener.listenTo( record, { eventName : handler, ... } )
77+
78+
Subscribe for `eventName` from the record. Subscription will be automatically cancelled when messenger is disposed.
79+
The handler is executed in the context of the listener.
80+
81+
#### listener.stopListening( record?, eventName?, hander? )
82+
#### listener.stopListening( record?, { eventName : handler, ... } )
83+
84+
`listener.stopListening( record )` stops subscriptions from the record.
85+
86+
`listener.stopListening()` stops _all_ event subscriptions and _is called automatically_ from the `listener.dispose()`.
87+
88+
### Low-level event API
89+
90+
Low level event API is more efficient but requires precise `off()` call to stop the subscription. It must be done
91+
in overidden `dispose()` method to prevent memory leaks.
92+
93+
#### record.onChanges( handler, context? )
94+
95+
Subscribe for `change` event from the record. If `context` is passed, handler will be called in this context.
96+
97+
#### record.on( eventName, handler, context? )
98+
#### record.on( { eventName : handler, ... }, context? )
99+
100+
Subscribe for the `eventName` from the record. If `context` is passed, handler will be called in this context.
101+
102+
#### record.off( eventName, handler, context? )
103+
#### record.off( { eventName : handler, ... }, context? )
104+
105+
Cancel event subscription.
106+
107+
## Transactions
108+
109+
All record updates occures in the scope of transactions. Transaction is the sequence of changes which results in a single `change` event.
110+
111+
Transaction can be opened either manually or implicitly with calling `set()` or assigning an attribute.
112+
Any additional changes made to the record in `change:attr` event handler will be executed in the scope of the original transaction, and won't trigger additional `change` events.
113+
114+
#### record.transaction( fun )
115+
116+
Execute the all changes made to the record in `fun` as single transaction.
117+
118+
```javascript
119+
some.record.transaction( record => {
120+
record.a = 1; // `change:a` is triggered.
121+
record.b = 2; // `change:b` is triggered.
122+
}); // `change` is triggered.
123+
```
124+
125+
Manual transactions with attribute assignments are superior to `record.set()` in terms of both performance and flexibility.
126+
127+
## Change inspection methods
128+
129+
Following API might be useful in change event listeners.
130+
131+
#### record.changed
132+
133+
The `changed` property is the internal hash containing all the attributes that have changed during its last transaction.
134+
Please do not update `changed` directly since its state is internally maintained by `set()`.
135+
A copy of `changed` can be acquired from `changedAttributes()`.
136+
137+
#### record.changedAttributes( attrs? )
138+
139+
Retrieve a hash of only the record's attributes that have changed during the last transaction,
140+
or false if there are none. Optionally, an external attributes hash can be passed in,
141+
returning the attributes in that hash which differ from the record.
142+
This can be used to figure out which portions of a view should be updated,
143+
or what calls need to be made to sync the changes to the server.
144+
145+
#### record.previous( attr )
146+
147+
During a "change" event, this method can be used to get the previous value of a changed attribute.
148+
149+
```javascript
150+
@define class Person extends Record{
151+
static attributes = {
152+
name: ''
153+
}
154+
}
155+
156+
const bill = new Person({
157+
name: "Bill Smith"
158+
});
159+
160+
bill.on("change:name", ( record, name ) => {
161+
alert( `Changed name from ${ bill.previous('name') } to ${ name }`);
162+
});
163+
164+
bill.name = "Bill Jones";
165+
```
166+
167+
#### record.previousAttributes()
168+
169+
Return a copy of the record's previous attributes. Useful for getting a diff between versions of a record, or getting back to a valid state after an error occurs.

0 commit comments

Comments
 (0)