Reading and Editing
The TreeView
object and its children expose properties and methods that allow applications read and edit the tree.
The APIs have been designed to match as much as possible the syntax of TypeScript primitives, objects, maps, and arrays (although some editing APIs are different for the sake of making the merge semantics clearer).
Leaf Node APIs
Leaf nodes are read and written exactly the way JavaScript primitive types are by using dot notation and the assignment operator (=
). The following example shows how to write to a leaf node:
myNewsPaperTree.articles[1].headline = "Man bites dog";
The following examples show how to read from a leaf node. Note that the datatype of pointsForDetroitTigers
is number
, not sf.number
. This is a general principle: the value returned from a leaf node, other than a FluidHandle
node, is the underlying JavaScript primitive type.
const pointsForDetroitTigers: number = seasonTree.tigersTeam.game1.points;
Object Node APIs
Reading Object Properties
Your code reads object nodes and their properties exactly as it would from a JavaScript object. The following are some examples.
const pointsForDetroitTigers: number = seasonTree.tigersTeam.game1.points;
const counterHandle: FluidHandle = myTree.myObjectNode.myHandle;
const myItems: Items = stickyNotesTree.items;
Creating Objects
You must create the object using the constructor of the class that you derived from the object returned by SchemaFactory.object()
method. The following shows how to create a note object from the sticky notes example.
const babyShowerNote = new Note({
id: Guid.create().toString(),
text: "Baby shower is at 3 PM today.",
author: "Bob",
lastChanged: 19697 // Days since January 1, 1970, the Unix epoch.
votes: ["0"]
});
We show how to add this note to an array of notes in the tree in Array node APIs.
Editing Object Properties
To update the property on an object node, you assign a new node or value to it with the assignment operator (=
).
See here for details on the merge semantics of these edits.
rectangle.topLeft = new Point({ x: 0, y: 0 });
babyShowerNote.author = "The Joneses";
Optional properties can be cleared by assigning undefined
to them.
proposal.text = undefined;
Note that if the new value is a node (as opposed to a primitive), then its status must be TreeStatus.New
,
In other words, it is not possible to set a node that has already been inserted in the tree in the past, even if that node has since been removed.
Map Node APIs
Map Node Read APIs
The read APIs for map nodes have the same names and syntax as the corresponding APIs for JavaScript Map objects.
has(key): boolean
Returns true
if the key is present in the map.
get(key): T | undefined
Returns the value associated with the specified key if any, and returns undefined
if no value is associated with that key.
keys(): IterableIterator<string>
Returns an Iterator that contains the keys in the map node.
values(): IterableIterator<T>
Returns an Iterator that contains the values in the map node.
entries(): IterableIterator<[string, T]>
Returns an Iterator that contains the key/value pairs in the map node.
map(callback: ()=>[]): IterableIterator<[string, T]>
Returns an array, not a map node or array node, that is the result of applying the callback parameter to each member of the original map node. It is just like Array.map.
Map Node Write APIs
The write methods for map nodes are similar to the corresponding methods for JavaScript Map
objects.
See here for details on the merge semantics of these edits.
set(key: string, value: T)
The set()
method sets/changes the value of the item with the specified key. If the key is not present, the item is added to the map. Note the following:
- The
T
can be any type that conforms to the map node's schema. For example, if the schema was defined withclass MyMap extends sf.map([sf.number, sf.string]);
, thenT
could benumber
orstring
. - If the
value
argument is a node (as opposed to a primitive), then its status must beTreeStatus.New
, In other words, it is not possible to set a node that has already been inserted in the tree in the past, even if that node has since been removed. - If multiple clients set the same key simultaneously, the key gets the value set by the last edit to apply. For the meaning of "simultaneously", see Types of distributed data structures.
delete(key: string): void
The delete()
method removes the item with the specified key. If one client sets a key and another deletes it simultaneously, the key is deleted only if the deletion op is the last one applied. For the meaning of "simultaneously", see Types of distributed data structures.
Map Node Properties
size: number;
The total number of entries in the map node.
Array Node APIs
Array Node Read APIs
Array nodes have all the same non-mutating read methods as the JavaScript Array type. (For information about the differences between mutating and non-mutating methods, see Copying methods and mutating methods). Note that methods which return an array, like Array.map()
, when called on an array node, return a JavaScript array, not an object of the type of the array node. For example, if the type is Notes
from the sticky notes example, an array is returned, not a Notes
object.
Array Node Write APIs
The write APIs for array nodes are quite different from JavaScript arrays. They are more suitable for data items that are being worked on collaboratively by multiple people. There are three categories of write APIs: Insert, Remove, and Move. See here for details on the merge semantics of these edits.
Insert Methods
Array nodes have three methods that insert items into the array. Note the following:
- In all of the following, the
T
can be any type that conforms to the array node's schema. For example, if the schema was defined withclass MyArray extends sf.array([sf.number, sf.string]);
, thenT
could benumber
orstring
. - Inserted values that are nodes (as opposed to a primitive), must have a status equal
TreeStatus.New
. In other words, it is not possible to set a node that has already been inserted in the tree in the past, even if that node has since been removed.
insertAt(index: number, value: Iterable<T>)
Inserts the provided value(s) at the specified index
. If the index
is greater than the length of the array, the items are inserted at the end of the array.
insertAtStart(value: Iterable<T>)
Inserts the provided value(s) at the start of the array. This is sugar for insertAt(0, …)
.
insertAtEnd(value: Iterable<T>)
Inserts the provided value(s) at the end of the array. This is syntactic sugar for insertAt(Infinity, …)
.
Remove Methods
Array nodes have two methods that remove items from the node. Note the following about these methods:
- Removed items are saved internally for a time in case they need to be restored as a result of an undo operation.
- A removed item may be restored as a result of a simultaneous move operation from another client. For example, if one client removes items 3-5, and another client simultaneously moves items 4 and 5, then, if the move operation is ordered last, only item 3 is removed (items 4 and 5 are restored and moved to their destination by the move operation). If the remove operation is ordered last, then all three items will be removed, no matter where they reside.
- Removal of items never overrides inserting (or moving in) items. For example, if one client removes items 10-15, and another client simultaneously inserts an item at index 12, the original items 10-15 are removed, but new item is inserted between item 9 and the item that used to be at index 16. This is true regardless of the order of the remove and insert operations.
For the meaning of "simultaneously", see Types of distributed data structures.
removeAt(index: number)
Removes the item at the given index
.
removeRange(start?: number, end?: number)
Removes the items indicated by the start
index (inclusive) and end
index (exclusive). If the end index is omitted, every item from the start index to the end of the array is removed. If the start index is omitted, it defaults to 0. So, calling removeRange()
removes all the items in the array.
Move Methods
Array nodes have three methods that move items within an array or from one array node to another. When moving from one array node to another, these methods must be called from the destination array node. Note that in all of the following, the T
can be any type that is derived from an object that is returned by a call of SchemaFactory.array()
, such as the Notes
and Items
classes in the sticky notes example.
Note the following about these methods:
- If multiple clients simultaneously move an item, then that item will be moved to the destination indicated by the move of the client whose edit is ordered last.
- A moved item may be removed as a result of a simultaneous remove operation from another client. For example, if one client moves items 3-5, and another client simultaneously removes items 4 and 5, then, if the remove operation is ordered last, items 4 and 5 are removed from their destination by the remove operation. If the move operation is ordered last, then all three items will be moved to the destination.
- Moved items that are nodes (as opposed to a primitives), must have a status equal
TreeStatus.InDocument
. - We also expose variations of these methods for moving a single item.
For the meaning of "simultaneously", see Types of distributed data structures.
moveRangeToStart(sourceStartIndex: number, sourceEndIndex: number, source?: T)
Moves the specified items to the start of the array. Specify a source
array if it is different from the destination array.
moveRangeToEnd(sourceStartIndex: number, sourceEndIndex: number, source?: T)
Moves the specified items to the end of the array. Specify a source
array if it is different from the destination array.
moveRangeToIndex(destinationGap: number, sourceStartIndex: number, sourceEndIndex: number, source?: T)
Moves the items to the specified destinationGap
in the destination array.
Specify a source
array if it is different from the destination array.
If the items are being moved within the same array, the destinationGap
position is interpreted including the items being moved (as if a new copy of the moved items were being inserted, without removing the originals).
See the doc comments for details.