Skip to content

Commit 5d95e7f

Browse files
committed
Add LiveObjects LiveMap docs
1 parent 8929a87 commit 5d95e7f

File tree

1 file changed

+214
-0
lines changed

1 file changed

+214
-0
lines changed

content/liveobjects/map.textile

+214
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
---
2+
title: LiveMap
3+
meta_description: "Create, update and receive updates for a key/value data structure that synchronizes state across clients in realtime."
4+
product: liveobjects
5+
languages:
6+
- javascript
7+
---
8+
9+
@LiveMap@ is a key/value data structure that synchronizes its state across users in realtime. It allows you to store primitive values, such as numbers, strings, booleans and buffers, as well as other Live Objects, "enabling you to build complex, hierarchical state structures":#composability.
10+
11+
Conflicts in a LiveMap are automatically resolved following the Last Write Wins (LWW) semantics. The latest received operation on a key in a map will be applied, persisted in the LiveObjects state on a channel, and broadcast to all clients.
12+
13+
h2(#create). Create LiveMap
14+
15+
A @LiveMap@ instance can be created using the @channel.objects.createMap()@ method. It must be stored inside another @LiveMap@, such as the "root object":/docs/liveobjects/setup#root, to persist it within the LiveObjects state and share it with other clients.
16+
17+
blang[javascript].
18+
@channel.objects.createMap()@ is asynchronous, as the client sends the create operation to the Ably system and waits for an acknowledgment of the successful map creation.
19+
20+
blang[javascript].
21+
22+
```[javascript]
23+
const map = await channel.objects.createMap();
24+
await root.set('myMap', map);
25+
```
26+
27+
Optionally, you can specify an initial key/value structure when creating the map:
28+
29+
blang[javascript].
30+
31+
```[javascript]
32+
// Pass a regular JavaScript object reflecting the initial state
33+
const map = await channel.objects.createMap({ foo: 'bar', baz: 42 });
34+
// You can also pass other Live Objects as values for keys
35+
await channel.objects.createMap({ nestedMap: map });
36+
```
37+
38+
h2(#value). Get value for a key
39+
40+
Get the current value for a key in a map using the @LiveMap.get()@ method:
41+
42+
blang[javascript].
43+
44+
```[javascript]
45+
console.log('Value for my-key:', map.get('my-key'));
46+
```
47+
48+
h2(#subscribe-data). Subscribe to data updates
49+
50+
You can subscribe to data updates on a map to receive realtime changes made by you or other clients.
51+
52+
<aside data-type='note'>
53+
<p>
54+
@LiveMap@ mutation methods do not directly modify the local map state. Instead, they send the intended operation to the Ably system, and the change is applied only when the corresponding realtime operation is echoed back to the client. This means that the state retrieved immediately after a mutation may not reflect the latest updates yet. You will be notified via subscription when the map is updated.
55+
</p>
56+
</aside>
57+
58+
Subscribe to data updates on a map using the @LiveMap.subscribe()@ method:
59+
60+
blang[javascript].
61+
62+
```[javascript]
63+
map.subscribe((update) => {
64+
console.log('Map updated:', [...map.entries()]);
65+
console.log('Update details:', update);
66+
});
67+
```
68+
69+
The update object provides details about the change, listing the keys that were changed and indicating whether they were updated (value changed) or removed from the map.
70+
71+
Example structure of an update object when the key **foo** is updated and the key **bar** is removed:
72+
73+
```[json]
74+
{
75+
{
76+
"foo": "updated",
77+
"bar": "removed"
78+
}
79+
}
80+
```
81+
82+
h2(#unsubscribe-data). Unsubscribe from data updates
83+
84+
Use the @unsubscribe()@ function returned in the @subscribe()@ response to remove a map update listener:
85+
86+
blang[javascript].
87+
88+
```[javascript]
89+
// Initial subscription
90+
const { unsubscribe } = map.subscribe(() => console.log('Map updated'));
91+
// To remove the listener
92+
unsubscribe();
93+
```
94+
95+
Use the @LiveMap.unsubscribe()@ method to deregister a provided listener:
96+
97+
blang[javascript].
98+
99+
```[javascript]
100+
// Initial subscription
101+
const listener = () => console.log('Map updated');
102+
map.subscribe(listener);
103+
// To remove the listener
104+
map.unsubscribe(listener);
105+
```
106+
107+
Use the @LiveMap.unsubscribeAll()@ method to deregister all map update listeners:
108+
109+
blang[javascript].
110+
111+
```[javascript]
112+
map.unsubscribeAll();
113+
```
114+
115+
h2(#set). Set keys in a LiveMap
116+
117+
Set a value for a key in a map by calling @LiveMap.set()@. This operation is synchronized across all clients and triggers data subscription callbacks for the map, including on the client making the request.
118+
119+
Keys in a map can contain numbers, strings, booleans and buffers, as well as other LiveMaps and LiveCounters.
120+
121+
blang[javascript].
122+
This operation is asynchronous, as the client sends the corresponding update operation to the Ably system and waits for acknowledgment of the successful map key update.
123+
124+
blang[javascript].
125+
126+
```[javascript]
127+
await map.set('foo', 'bar');
128+
await map.set('baz', 42);
129+
130+
// Can also set a reference to another Live Object
131+
const counter = await channel.objects.createCounter();
132+
await map.set('counter', counter);
133+
```
134+
135+
h2(#remove). Remove a key from a LiveMap
136+
137+
Remove a key from a map by calling @LiveMap.remove()@. This operation is synchronized across all clients and triggers data subscription callbacks for the map, including on the client making the request.
138+
139+
blang[javascript].
140+
This operation is asynchronous, as the client sends the corresponding remove operation to the Ably system and waits for acknowledgment of the successful map key removal.
141+
142+
blang[javascript].
143+
144+
```[javascript]
145+
await map.remove('foo');
146+
```
147+
148+
h2(#subscribe-lifecycle). Subscribe to Lifecycle Events
149+
150+
Subscribe to lifecycle events on a map using the @LiveMap.on()@ method:
151+
152+
blang[javascript].
153+
154+
```[javascript]
155+
map.on('deleted', () => {
156+
console.log('Map has been deleted');
157+
});
158+
```
159+
160+
Read more about "Live Objects lifecycle events":/docs/liveobjects/lifecycle#objects.
161+
162+
h2(#unsubscribe-lifecycle). Unsubscribe from Lifecycle Events
163+
164+
Use the @off()@ function returned in the @on()@ response to remove a lifecycle event listener:
165+
166+
blang[javascript].
167+
168+
```[javascript]
169+
// Initial subscription
170+
const { off } = map.on(('deleted') => console.log('Map deleted'));
171+
// To remove the listener
172+
off();
173+
```
174+
175+
Use the @LiveMap.off()@ method to deregister a provided lifecycle event listener:
176+
177+
blang[javascript].
178+
179+
```[javascript]
180+
// Initial subscription
181+
const listener = () => console.log('Map deleted');
182+
map.on('deleted', listener);
183+
// To remove the listener
184+
map.off('deleted', listener);
185+
```
186+
187+
Use the @LiveMap.offAll()@ method to deregister all lifecycle event listeners:
188+
189+
blang[javascript].
190+
191+
```[javascript]
192+
map.offAll();
193+
```
194+
195+
h2(#composability). Composability
196+
197+
@LiveMap@ can store references to other LiveMaps or LiveCounters as values for its keys, allowing you to build complex, hierarchical state structures. This enables you to represent complex data models in your applications while ensuring realtime synchronization across clients.
198+
199+
blang[javascript].
200+
201+
```[javascript]
202+
// Create a hierarchy of objects using LiveMaps
203+
const counter = await channel.objects.createCounter();
204+
const map = await channel.objects.createMap({ nestedCounter: counter });
205+
const outerMap = await channel.objects.createMap({ nestedMap: map });
206+
await root.set('outerMap', outerMap);
207+
208+
// resulting structure:
209+
// root (LiveMap)
210+
// └── outerMap (LiveMap)
211+
// └── nestedMap (LiveMap)
212+
// └── nestedCounter (LiveCounter)
213+
```
214+

0 commit comments

Comments
 (0)