Getting Started with Kuzzle and VueJS

This section deals with Kuzzle (+ Javascript SDK) and VueJS. We will create documents in Kuzzle and subscribe to document notifications to develop a realtime chat.

Requirements

Prepare your environment

Create your VueJS app with Vue CLI. You'll need to select manually the features, just add Babel, Linter and select the default options for the other features.

Copied to clipboard!
vue create kuzzle-playground

Install Kuzzle's Javascript SDK:

Copied to clipboard!
cd kuzzle-playground
npm install kuzzle-sdk

In the App.vue file, you should remove the tag, the import and the component registration of the HelloWorld component, we won't use it.

Instantiating Kuzzle SDK

We have to connect the server so that our client can interact with it.

To do this, we have to create a src/services/kuzzle.js file to put our kuzzle instance declaration:

Copied to clipboard!
import { Kuzzle, WebSocket } from 'kuzzle-sdk';

export default new Kuzzle(new WebSocket('localhost'));

We need to import our Kuzzle SDK instance, so just add the following line in your <script> tag in the App.vue file:

Copied to clipboard!
import kuzzle from "./services/kuzzle";

Then we will establish the connection to kuzzle and create, if they don't exist, the index and collection of our chat. Add the following valid() method in the export of the <script> tag of your App.vue file:

Copied to clipboard!
async valid() {
  // Etablish the connection
  await kuzzle.connect();
  // Check if 'chat' index exists
  if (! await kuzzle.index.exists("chat")) {
    // If not, create 'chat' index and 'messages' collection
    await kuzzle.index.create("chat");
    await kuzzle.collection.create("chat", "messages");
  }
  await this.fetchMessages();
  await this.subscribeMessages();
  this.validate = true;
  }

Get the username

First of all, we need to know the user's name. Let's start by adding the following HTML code in the <template> tag, allowing one to enter their name:

Copied to clipboard!
<div v-if="!validate">
  <input
    autofocus
    v-on:keyup.enter="valid"
    type="text"
    v-model="username"
    placeholder="Enter your nickname"
  />
  <button @click="valid">Valid</button>
  </div>

As you can see we'll need two properties: username and validate.

Display the messages

We'll need some properties to manage our messages. Add the following data to your App.vue

Copied to clipboard!
data() {
  return {
    message: "", // String containing the user input
    messages: [], // Array containing our messages
    roomID: "", // Id of the realtime subscription
    username: "", // Nickname of the current user
    validate: false // Value that will change the display (false => Pseudo input; true => Message input)
  };
  },

Then, create the following functions to fetch and display the messages:

Copied to clipboard!
// This function return the right formated date depending on the timestamp
getDate(timestamp) {
  const date = new Date(timestamp);
  return date.toLocaleString().split("GMT")[0];
  },
Copied to clipboard!
// This function will create a message object containing the informations we need to display it
getMessage(document) {
  const message = {
    // The unique id of the document containing the message
    _id: document._id,
    // The text of the message
    value: document._source.value,
    // The creation date
    createdAt: document._source._kuzzle_info.createdAt,
    // The author name
    username: document._source.username
  };
  return message;
  },

The function fetchMessage() will search for the first hundred newest messages and store them in our array, before subscribing to changes in the messages collection. We called it in the valid() function we created above.

Copied to clipboard!
async fetchMessages() {
  // Call the search method of the document controller
  const results = await kuzzle.document.search(
    "chat", // Name of the index
    "messages", // Name of the collection
    { sort: ["_kuzzle_info.createdAt"] }, // Query => Sort the messages by creation date
    { size: 100 } // Options => get a maximum of 100 messages
  );
  // Add each message to our array
  results.hits.map(hit => {
    this.messages = [this.getMessage(hit), ...this.messages];
  });
  },

Now, add the following HTML code to display the messages:

Copied to clipboard!
<div
  v-for="message in messages"
  :key="message._id"
  :class="`messages ${message.username === username ? 'fromMe' : 'fromOthers'}`"
>
  <span class="username">{{ message.username }}</span>
  <span>({{ getDate(message.createdAt) }})</span>
  <p>{{ message.value }}</p>
  </div>

To finish this part, add the following CSS classes:

Copied to clipboard!
#app {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}

.username {
  font-weight: bold;
}

.messages {
  padding: 10px;
  margin: 1px;
  width: 45vw;
  border-radius: 10px;
}

.fromMe {
  text-align: right;
  float: right;
  margin-left: 49vw;
  background-color: #9ca4f0;
}

.fromOthers {
  text-align: left;
  margin-right: 49vw;
  float: left;
  background-color: rgb(206, 246, 147);
}

We can now display the messages stored in Kuzzle. All there is to do is to create some.

Send messages

We need to write a simple method that will create a new message document in Kuzzle.

Copied to clipboard!
async sendMessage() {
  if (this.message === "") return;
  // Call the create method of the document controller
  await kuzzle.document.create(
    "chat",
    "messages",
    // Pass the document to be stored in Kuzzle as a parameter
    {
      value: this.message,
      username: this.username
    }
  );
  // Clear the user input
  this.message = "";
  },

As you can see we don't push the new message in our array on message creation.

Indeed, we will receive notifications from Kuzzle each time we modify our message collection (even if it is a message creation on our part) that we will use to add the messages in our array.

Now, we need to subscribe to the collection that contains our messages. So let's create our subscribeMessages() action. It will call the Kuzzle's realtime controller to allow us to receive notifications on message creations:

Copied to clipboard!
async subscribeMessages() {
  // Call the subscribe method of the realtime controller and receive the roomId
  // Save the id of our subscription (we could need it to unsubscribe)
  this.roomID = await kuzzle.realtime.subscribe(
    "chat", // Id of the index
    "messages", // Id of the collection
    {}, // Filter
    // Callback to receive notifications
    notification => {
      // Check if the notification interest us (only document creation)
      if (notification.type !== "document") return;
      if (notification.action !== "create") return;
      // Add the new message to our array
      this.messages = [
        this.getMessage(notification.result),
        ...this.messages
      ];
    }
  );
  },

To finish, just add an input field bound to the message property, and a button which calls our sendMessage() function:

Copied to clipboard!
<div class="wrapper" v-else>
  <input
    autofocus
    type="text"
    v-model="message"
    v-on:keyup.enter="sendMessage"
    placeholder="Enter your message"
  />
  <button @click="sendMessage">Send</button>
  </div>

And the following CSS class:

Copied to clipboard!
.wrapper {
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 10px;
}

You can now add new messages to Kuzzle and receive the creation notification to update your state and display the new messages.

Where do we go from here?

Now that you're more familiar with Kuzzle, dive even deeper to learn how to leverage its full capabilities: