Lock states
Component locking is handled entirely client-side. Members may begin to optimistically edit a component as soon as they callacquire() on the lock identifier related to it. Alternatively, you could wait until they receive a locked event and display a spinning symbol in the UI until this is received. In either case, a subsequent unlocked event may invalidate that member’s lock request if another member acquired it earlier. The time for confirmation of whether a lock request was successful or rejected is, on average, in the hundreds of milliseconds. However, your code should handle all possible lock state transitions.
A lock will be in one of the following states:
The following lock state transitions may occur:
- None →
pending: a member callsacquire()to request a lock. pending→locked: the requesting member holds the lock.pending→unlocked: the requesting member does not hold the lock, since another member already holds it.locked→unlocked: the lock was either explicitly released by the member, or their request was invalidated by a concurrent request which took precedence.unlocked→locked: the requesting member reacquired a lock they previously held.
locked or unlocked status will emit a lock event that members can subscribe() to.
Acquire a lock
Use theacquire() method to attempt to acquire a lock with a given unique ID. Additional attributes may be passed when trying to acquire a lock that can contain a set of arbitrary key-value pairs. An example of using attributes is to store the component ID the lock relates to so that it can be easily updated in the UI with a visual indication of its lock status.
A member must have been entered into the space to acquire a lock.
The following is an example of attempting to acquire a lock:
The following is an example of passing a set of attributes when trying to acquire a lock:
The following is an example payload returned by space.locks.acquire(). The promise will resolve to a lock request with the pending status:
Once a member requests a lock by calling acquire(), the lock is temporarily in the pending state. An event will be emitted based on whether the lock request was successful (a status of locked) or invalidated (a status of unlocked). This can be subscribed to in order for the client to know whether their lock request was successful or not.
Release a lock
Use therelease() method to explicitly release a lock once a member has finished editing the related component. For example, the release() method can be called once a user clicks outside of the component, such as clicking on another cell within a spreadsheet. Any UI indications that the previous cell was locked can then be cleared.
The following is an example of releasing a lock:
Releasing a lock will emit a lock event with a lock status of unlocked.
Subscribe to lock events
Subscribe to lock events by registering a listener. Lock events are emitted whenever the lock state transitions intolocked or unlocked. Use the subscribe() method on the locks namespace of the space to receive updates.
All lock events are update events. When a lock event is received, UI components can be updated to add and remove visual indications of which member is locking them, as well as enabling and disabling the ability for other members to edit them.
The following is an example of subscribing to lock events:
The following is an example payload of a lock event:
The following are the properties of a lock event payload:
| Property | Description | Type |
|---|---|---|
| id | The unique ID of the lock request. | String |
| status | The lock status of the event. Will be one of locked, unlocked, or pending. | String |
| timestamp | The timestamp of the lock event. | Number |
| attributes | The optional attributes of the lock, such as the ID of the component it relates to. | Object |
| reason | If set, gives the reason for status. Successful lock requests do not set a reason. | ErrorInfo |
| member.clientId | The client identifier for the member. | String |
| member.connectionId | The unique identifier of the member’s connection. | String |
| member.isConnected | Whether the member is connected to Ably or not. | Boolean |
| member.lastEvent.name | The most recent event emitted by the member. Will be one of enter, update, present, or leave. | String |
| member.lastEvent.timestamp | The timestamp of the most recently emitted event. | Number |
| member.profileData | The optional profile data associated with the member. | Object |
reason property:
| Error code | Description |
|---|---|
| 101002 | There is an existing lock request in the pending or locked state. Nested locks are not supported, so the previous request must be handled before a new lock is requested. |
| 101003 | The lock is currently in the locked state, and the pending request did not invalidate the status. |
| 101004 | The lock request invalidated an existing lock in the locked state. |
Unsubscribe from lock events
Unsubscribe from lock events to remove previously registered listeners. The following is an example of removing a listener for lock update events: Or remove all listeners:Query lock status
Use theget() method to query whether a lock is currently locked, and by which member if it is. The lock is identifiable by its unique string ID.
The following is an example of checking whether a lock identifier is currently locked:
The following is an example of checking which member holds the lock:
The following is an example of viewing the attributes assigned to the lock by the member holding it:
If the lock is not currently held by a member, get() will return undefined. Otherwise, it will return the most recent lock event for the lock.
Retrieve locks
Locks can also be retrieved in one-off calls. These are local calls and retrieve the locks retained in memory by the SDK. The following is an example of retrieving a member’s own currently held locks: The following is an example payload returned byspace.locks.getSelf()
The following is an example of retrieving the locks held by all members other than the member themselves:
The following is an example payload returned by space.locks.getOthers()
The following is an example of retrieving an array of all currently held locks in a space:
The following is an example payload returned by space.locks.getAll()
