Skip to main content

Overview

Transaction encapsulates a set of operations to modify the document. All document changes should go through transactions to support:
  • Undo/Redo: Transactions are recorded in the history stack
  • Collaborative Editing: Operations can be sent to other users
  • Consistency: Multiple operations are applied atomically

Constructor

Transaction({required Document document})

Parameters

document
Document
required
The document this transaction operates on.

Properties

document
Document
The target document.
operations
List<Operation>
The list of operations in this transaction.
afterSelection
Selection?
Selection to apply after the transaction completes.
beforeSelection
Selection?
Selection before the transaction (for undo).
customSelectionType
SelectionType?
Custom selection type (inline or block).
reason
SelectionUpdateReason?
Reason for the selection update.
selectionExtraInfo
Map?
Additional selection metadata.

Node Operations

insertNode

void insertNode(
  Path path,
  Node node, {
  bool deepCopy = true,
})
Inserts a single node at the specified path.
path
Path
required
Where to insert the node.
node
Node
required
The node to insert.
deepCopy
bool
default:"true"
Whether to deep copy the node before insertion.
Example:
final transaction = editorState.transaction;
transaction.insertNode(
  [1],
  paragraphNode(text: 'New paragraph'),
);
await editorState.apply(transaction);

insertNodes

void insertNodes(
  Path path,
  Iterable<Node> nodes, {
  bool deepCopy = true,
})
Inserts multiple nodes at the specified path.

updateNode

void updateNode(Node node, Attributes attributes)
Updates a node’s attributes.
node
Node
required
The node to update.
attributes
Attributes
required
Attributes to merge into the node.
Example:
final transaction = editorState.transaction;
transaction.updateNode(node, {'level': 2, 'bold': true});
await editorState.apply(transaction);

deleteNode

void deleteNode(Node node)
Deletes a single node from the document.
node
Node
required
The node to delete.

deleteNodes

void deleteNodes(Iterable<Node> nodes)
Deletes multiple nodes.

deleteNodesAtPath

void deleteNodesAtPath(Path path, [int length = 1])
Deletes consecutive nodes starting at the path.
path
Path
required
Starting path for deletion.
length
int
default:"1"
Number of nodes to delete.

moveNode

void moveNode(Path path, Node node)
Moves a node to a new path.

Text Operations

insertText

void insertText(
  Node node,
  int index,
  String text, {
  Attributes? attributes,
  Attributes? toggledAttributes,
  bool sliceAttributes = true,
})
Inserts text at the specified position.
node
Node
required
The text node to insert into.
index
int
required
Character position to insert at.
text
String
required
The text to insert.
attributes
Attributes
Text formatting attributes. If null, inherits from previous character.
toggledAttributes
Attributes
Additional toggled attributes to apply.
sliceAttributes
bool
default:"true"
Whether to slice attributes from the previous character.
Example:
final transaction = editorState.transaction;
transaction.insertText(
  node,
  5,
  'Hello',
  attributes: {'bold': true},
);
await editorState.apply(transaction);

deleteText

void deleteText(
  Node node,
  int index,
  int length,
)
Deletes text from a node.
node
Node
required
The text node.
index
int
required
Starting position.
length
int
required
Number of characters to delete.
Example:
final transaction = editorState.transaction;
transaction.deleteText(node, 0, 5); // Delete first 5 characters
await editorState.apply(transaction);

replaceText

void replaceText(
  Node node,
  int index,
  int length,
  String text, {
  Attributes? attributes,
})
Replaces text in a node.
node
Node
required
The text node.
index
int
required
Starting position.
length
int
required
Number of characters to replace.
text
String
required
The replacement text.
attributes
Attributes
Formatting for the new text.

formatText

void formatText(
  Node node,
  int index,
  int length,
  Attributes attributes,
)
Applies formatting to a text range.
node
Node
required
The text node.
index
int
required
Starting position.
length
int
required
Number of characters to format.
attributes
Attributes
required
Formatting attributes (e.g., {'bold': true}).
Example:
final transaction = editorState.transaction;
transaction.formatText(node, 0, 5, {'bold': true, 'italic': true});
await editorState.apply(transaction);

mergeText

void mergeText(
  Node left,
  Node right, {
  int? leftOffset,
  int rightOffset = 0,
})
Merges text from two nodes.
left
Node
required
The left (target) node.
right
Node
required
The right (source) node.
leftOffset
int
Position in left node to merge at. Defaults to end of left node.
rightOffset
int
default:"0"
Starting position in right node.

insertTextDelta

void insertTextDelta(
  Node node,
  int index,
  Delta insertedDelta,
)
Inserts a Delta (rich text with formatting) at the specified position.

replaceTexts

void replaceTexts(
  List<Node> nodes,
  Selection selection,
  List<String> texts,
)
Replaces text across multiple nodes.

Utility Methods

add

void add(Operation operation, {bool transform = true})
Adds a low-level operation to the transaction.

toJson

Map<String, dynamic> toJson()
Serializes the transaction to JSON.

compose

void compose()
Composes pending delta operations (called automatically).

Example Usage

import 'package:appflowy_editor/appflowy_editor.dart';

final editorState = EditorState.blank();

// Get a transaction from the editor state
final transaction = editorState.transaction;

// Insert a new paragraph
transaction.insertNode(
  [1],
  paragraphNode(text: 'Hello, World!'),
);

// Insert text into an existing node
final node = editorState.document.nodeAtPath([0]);
if (node != null) {
  transaction.insertText(
    node,
    0,
    'New text ',
    attributes: {'bold': true},
  );
}

// Format existing text
transaction.formatText(node, 0, 8, {'italic': true});

// Update node attributes
transaction.updateNode(node, {'level': 2});

// Set the selection after transaction
transaction.afterSelection = Selection.collapsed(
  Position(path: [0], offset: 9),
);

// Apply the transaction
await editorState.apply(transaction);

// Apply without recording in undo stack
await editorState.apply(
  transaction,
  options: ApplyOptions(recordUndo: false),
);

Chaining Operations

You can chain multiple operations in a single transaction:
final transaction = editorState.transaction
  ..insertText(node1, 0, 'Hello')
  ..deleteText(node2, 0, 5)
  ..formatText(node3, 0, 10, {'bold': true})
  ..afterSelection = Selection.collapsed(Position(path: [0], offset: 5));

await editorState.apply(transaction);

See Also

Build docs developers (and LLMs) love