[Tutorial]How to build a real-time collaborative app using CRDT in angular?
Many of us have come across several real-time collaboration applications that help teams work together on the same document or project. Apps like Google Docs or Spreadsheets allow users to edit documents simultaneously.
Have you ever thought about what happens when we grant our users the opportunity to edit the same document at the same time? Or what happens if any user suddenly goes offline due to some network issues while editing a document?
The other teammates would be editing the document, and once the user comes back online, what if the user has already made some changes while he was offline. If correct measures are not taken then the application will merge the changes and provide inconsistent data. Almost most of the users end up overwriting the data of each other.
So if we take a closer look at how these collaborative real-time apps work, we’ll come across terms such as OT (Operational Transformation) and CRDT (Conflict-free Replicated Data Type).
Now some of you might wonder what these words really mean. Followed by which one of these should be used to create real-time interactive applications.
So, let’s start with the basics of OT and CRDT.
- OT relies on an active server connection to coordinate and guarantee all clients operate correctly.
- CRDT is capable of working peer-to-peer with end-to-end encryption. It only needs to coordinate connections between clients, even if a server is used. CRDT is resilient to transient network connections. It even works if the clients go offline for a while, make changes, and synchronize when the network returns.
For knowing more about OT (Operational Transformation) and CRDT (Conflict-free Replicated Data Type) refer to this link.
Collaborative apps can cause divergence if there is no synchronization between the clients while editing text. This can lead to a whole lot of conflicts in the final data. We are going with CRDT to avoid these kinds of issues.
There are many types of CRDTs. Refer to this link for a good overview of the types of CRDT. Currently, there are many CRDT frameworks implemented.
In this tutorial, let’s learn how to build a real-time collaborative app using CRDT in angular.
Note: In this tutorial, we will be using the Yjs NPM module as the CRDT framework. Users can implement their own design for the text editor. We are using Angular in this tutorial to implement the same.
So, let’s get started!!
Steps for creating a real-time collaborative app using CRDT
The complete code and repository for the above project have been given below. Small code snippets have been given in the steps below to illustrate this.
- To start with, create an Angular project and install the npm module for Yjs and y-WebSocket.
npm install yjs y-websocket
- Now Yjs gives us some predefined bindings for real-time collaborative text editing. We will first show how to implement that binding and create a real-time text editor. In the later part, we will create a real-time TODO app with CRDT using Yjs from scratch.
- Firstly we will use code-mirror binding from Yjs for real-time collaboration text editor without creating any conflicts.
npm install codemirror
- To add a text editor to the interface for allowing the user to edit text, we need to add these commands in the typescript file. This will create a text editor for the users to collaborate their thoughts in a real-time way.
import { Component } from "@angular/core";
import * as Y from "yjs";
import CodeMirror from "codemirror";
import { WebsocketProvider } from "y-websocket";
import { CodemirrorBinding } from "y-codemirror";export class YjsComponent {// New Doc initialised
ydoc = new Y.Doc();// Websocket Provider
provider = new WebsocketProvider(
"wss://demos.yjs.dev",
"codemirror-large",
this.ydoc
);textContent = "Disconnect"constructor() {// Using Codemirror package from YJS for building connection between users
// Codemirror Code for setting up Textarea field for entering dataconst yText = this.ydoc.getText("codemirror");
const editorContainer = document.createElement("div");
editorContainer.setAttribute("id", "editor");
document.body.insertBefore(editorContainer, null);// Code for adding line numbers to the text editor.const editor = CodeMirror(editorContainer, {
mode: "javascript",
lineNumbers: true,
});const binding = new CodemirrorBinding(yText, editor, this.provider.awareness);
const provider = this.provider;
const ydoc = this.ydoc;// @ts-ignore
window.example = { provider, ydoc, yText, binding, Y };
}
}
- Now to connect/disconnect the editor from the real-time WebSocket connection, we need to write a function.
// Function for connecting/disconnecting websocket connection between users.connect() {
if (this.provider.shouldConnect) {
this.provider.disconnect();
this.textContent = "Connect";
} else {
this.provider.connect();
this.textContent = "Disconnect";
}
}
- The HTML part for adding the button for connecting the editor to real-time WebSocket connection will look like this.
<!-- Button for disconnecting/connecting connection between users--><button type="button" id="y-connect-btn" (click)="connect()">{{textContent}}</button>
- The CSS part for adding the cursor to identify which user is currently editing the document is given below. This will show the User ID along with the cursor.
.remote-caret.hide-name > div {
transition-delay: 0.7s;
opacity: 0;
}.remote-caret:hover > div {
opacity: 1;
transition-delay: 0s;
}.remote-caret {
position: absolute;
border-left: black;
border-left-style: solid;
border-left-width: 2px;
height: 1em;
}.remote-caret > div {
position: relative;
top: -1.05em;
font-size: 13px;
background-color: rgb(250, 129, 0);
font-family: serif;
font-style: normal;
font-weight: normal;
line-height: normal;
user-select: none;
color: white;
padding-left: 2px;
padding-right: 2px;
z-index: 3;
transition: opacity 0.3s ease-in-out;
}
Below is a demonstration of real-time collaboration. This will display the user ID of the user that is currently editing the text.
Now, let’s see how the CRDT is playing the role of providing conflict-free data. To do this, we will disable the web socket link, update the document, and see how CRDT will fix disputes and provide reliable data when the web socket link is switched back on.
In the above image, you will see that once the WebSocket connection was turned on, CRDT came into action and removed all conflicts and provided consistent data.
Now, let’s see how to create a Real-time TODO app using Yjs from scratch.
- The code is given below for creating a real-time Todo List and removing conflicts using CRDT.
import { Component, OnInit } from "@angular/core";
import * as Y from "yjs";
import { WebsocketProvider } from "y-websocket";
import { IndexeddbPersistence } from 'y-indexeddb';...ydoc = new Y.Doc();constructor() {
// String data in indexdb of browser
const indexeddbProvider = new IndexeddbPersistence('todoList', this.ydoc)// Getting contents of array from document created.
this.yarray = this.ydoc.getArray("todoList");// Creating a websocket connection between users.
this.websocketProvider = new WebsocketProvider(
"wss://demos.yjs.dev",
"todoList",
this.ydoc
);
}// Function for inserting Data into arrayinsert() {
this.array = [];
this.array.push(this.value);
this.ydoc.getArray("todoList").insert(0, this.array);
}// Function for making connection between users.connect() {
if (this.websocketProvider.shouldConnect) {
this.websocketProvider.disconnect();
this.textContent = "Connect";
} else {
this.websocketProvider.connect();
this.textContent = "Disconnect";
}}
}
- Now the code for the HTML part is given below to create a textbox for getting tasks from users.
<!-- Input Field for adding Todo -->
<div class="col-lg-12">
<input type="text" class="form-control textbox" [(ngModel)]="value" />
</div><!-- Showing Task that has been entered by multiple users --><h4>List of Tasks :</h4>
<div *ngFor="let item of yarray" class="row mt-1">
<div class="col-12 col-md-11 list-todo">
<p><span class="font-weight-bold">Task</span> : {{ item }}</p>
</div>
</div><!-- Button for disconnecting/connecting connection between users -->
<button style="margin-left: 40%;" class="btn button" (click)="connect()">{{ textContent }}</button>
- A glance at the application below shows how users can incorporate tasks in real-time.
We have successfully created a real-time TODO app using CRDT to remove conflicts. This will helps us to easily collaborate with our teammates and document data. Refer to the Github repository link to view the full source code.
Summary
Using the CRDT algorithm, various users can easily interact with the text editor or the todo app in real-time to write down their notes. This, in turn, lets users make notes quickly and also prevents users from creating inaccurate data when they come back online.
Thanks for reading the tutorial. Requesting you to share your thoughts in the comments below!
References
About Blocksurvey
BlockSurvey is a privacy-focused platform to create surveys, polls, & forms with complete confidentiality. Through BlockSurvey, all your data is encrypted end to end and only you can see it. You own your data. It’s your digital right. There are zero trackers and we keep you as anonymous to the data collectors. Our platform utilizes Blockstack and helps in maintaining privacy and anonymity, resulting in effective surveys and polls. Try out by creating your surveys and polls with us.