How to Build a Real-Time Editable Data Table in Vuejs

How to Build a Real-Time Editable Data Table in Vuejs

While there are tons of libraries that make it easy to add a data table to a Vue app, Kendo UI for Vue makes it a lot easier to render data and style. Read along as we build a real-time editable data table with Kendo UI for Vue and Hamoni Sync.

Building responsive Vue apps just got better and faster with Kendo UI for Vue. Kendo UI for Vue is a library with a set of UI components that you can use in your Vue applications to make them beautiful, responsive and accessible. One of the components that comes with Kendo UI for Vue is the Grid component. The Grid is used to display data in a tabular format. It not only allows you to display data in a tabular form, but it also provides the features highlighted below:

  • Paging
  • Sorting
  • Filtering
  • Grouping
  • Editing
  • Column Resizing and Reordering
  • Multi-column headers
  • Virtual Scrolling
  • Globalization / Localization
  • Export to PDF and Excel
Show Me Some Code!

After all is said and done, I’ll show how to use the Grid component by building a small app that allows you to add and edit data in a Grid in real time. We will be using Hamoni Sync for real-time synchronization, and Vue CLI to bootstrap the project. Here’s a peek at what you will build:

Let’s get started with creating a Vue project. Open the command line and run vue create kendo-realtime-vue-grid && cd kendo-realtime-vue-grid command, select the default option and press Enter. In a short while, a Vue project will be bootstrapped by the Vue CLI. With the project ready, we’ll go ahead and install dependencies needed for the project. Run the following npm command to install dependencies for Kendo Vue and Hamoni Sync.

npm install --save @progress/kendo-theme-material @progress/kendo-vue-grid @progress/kendo-vue-intl vue-class-component hamoni-sync

We installed the Material design theme for Kendo UI, the Kendo Vue Grid package, and Hamoni Sync.

Let’s get started with some code. Open App.vue and delete the style section. Update the template section with the following snippet:

<template>
  <div>
    <Grid
      ref="grid"
      :data-items="gridData"
      :edit-field="'inEdit'"
      @edit="edit"
      @remove="remove"
      @save="save"
      @cancel="cancel"
      @itemchange="itemChange"
      :columns="columns"
    >
      <GridToolbar>
        <button title="Add new" class="k-button k-primary" @click="insert">
          Add new
        </button>
        <button
          v-if="hasItemsInEdit"
          title="Cancel current changes"
          class="k-button"
          @click="cancelChanges"
        >
          Cancel current changes
        </button>
      </GridToolbar>
    </Grid>
  </div>
</template>

We used a Grid component, which represents the data table, and passed it some props. The data-items props holds the data for the grid, columns set the properties of the columns that will be used, and edit-field is used to determine if the current record is in edit mode. We chose to use inEdit as the field name to be used to determine which record is being edited. We will create a computed method called hasItemsInEdit that returns Boolean and is used in Kendo’s GridToolbar component. If it returns true, we show a button that allows canceling the edit operation; otherwise, it shows a button to trigger adding new data. The edit event is fired when the user triggers an edit operation, the remove event for removing records, and the itemchange event for when data changes in edit mode.

In the script section, add the following import statements.

import Vue from "vue";
import "@progress/kendo-theme-material/dist/all.css";
import { Grid, GridToolbar } from "@progress/kendo-vue-grid";
import Hamoni from "hamoni-sync";
import DropDownCell from "./components/DropDownCell.vue";
import CommandCell from "./components/CommandCell.vue";

Vue.component("kendo-dropdown-cell", DropDownCell);
Vue.component("kendo-command-cell", CommandCell);

const primitiveName = "kendo-grid";

In the code above we have the Grid and GridToolbar from Kendo Vue Grid, and also Hamoni (we’ll get to that later). The DropDownCell and CommandCell components will be added later. One of the columns will need a dropdown when it’s in edit mode, so the DropDownCell will be used to render that cell. CommandCell will be used to display buttons to trigger edit or cancel changes while in edit mode.

Next, update the exported object to look like the following:

export default {
  name: "app",
  components: {
    Grid,
    GridToolbar
  },
  data: function() {
    return {
      columns: [
        { field: "ProductID", editable: false, title: "ID", width: "50px" },
        { field: "ProductName", title: "Name" },
        {
          field: "FirstOrderedOn",
          editor: "date",
          title: "First Ordered",
          format: "{0:d}"
        },
        {
          field: "UnitsInStock",
          title: "Units",
          width: "150px",
          editor: "numeric"
        },
        {
          field: "Discontinued",
          title: "Discontinued",
          cell: "kendo-dropdown-cell"
        },
        { cell: "kendo-command-cell", width: "180px" }
      ],
      gridData: []
    };
  },
  mounted: async function() {
    const accountId = "YOUR_ACCOUNT_ID";
    const appId = "YOUR_APP_ID";
    let hamoni;

    const response = await fetch("https://api.sync.hamoni.tech/v1/token", {
      method: "POST",
      headers: {
        "Content-Type": "application/json; charset=utf-8"
      },
      body: JSON.stringify({ accountId, appId })
    });
    const token = await response.json();
    hamoni = new Hamoni(token);

    await hamoni.connect();
    try {
      const primitive = await hamoni.get(primitiveName);
      this.listPrimitive = primitive;
      this.gridData = [...primitive.getAll()];
      this.subscribeToUpdate();
    } catch (error) {
      if (error === "Error getting state from server") this.initialise(hamoni);
      else alert(error);
    }
  },
  computed: {
    hasItemsInEdit() {
      return this.gridData.filter(p => p.inEdit).length > 0;
    }
  }
};

In the code above, we have declared data for the columns and set gridData to an empty array. Our actual data will come from Hamoni Sync, which we set up from the mounted lifecycle hook. Hamoni Sync is a service that allows you to store and synchronize data/application state in real time. This will allow us to store data for the data table and get a real-time update when a record changes. You will have to replace YOUR_APP_ID and YOUR_ACCOUNT_ID in the mounted function with your Hamoni Sync’s account details. Follow these steps to register for an account and create an application on the Hamoni server.

  1. Register and login to Hamoni dashboard.
  2. Enter your preferred application name in the text field and click the create button. This should create the app and display it in the application list section.
  3. Expand the Account ID card to get your account ID.

Hamoni Sync has what is called Sync primitives as a way to store and modify state. There are three kinds of Sync primitives: Value, Object, and List primitives. We’re going to use List primitive because it provides an API for us to store and modify data that needs to be stored in an array-like manner. You can read more about sync primitives from the docs.

In the last code you added, there’s a line that calls hamoni.connect() to connect to the server once you’ve gotten a token. While we had the code to retrieve the token in there, it is recommended to have it behind a server you control and only return a token from an endpoint you control. This is to avoid giving away your account ID to the public. To get or store data, you first need to get an object that represents the sync primitive you want to use. This is why we called hamoni.get(), passing it the name of the state we want to access. If it exists, we get an object with which we can manipulate state on Hamoni.

The first time we’ll use the app, the sync primitive will not exist; this is why in the catch block we call initialise() to create a sync primitive with a default data. If it exists, we call primitive.getAll() to get data and assign it to gridData so the grid gets data to display. Later on we will add implementation for subscribeToUpdate(), which will be used to subscribe to data updates events from Hamoni Sync.

We’ve referenced methods so far from the template and code in the mounted hook. Add the code below after the computed property.

methods: {
    itemChange: function(e) {
      Vue.set(e.dataItem, e.field, e.value);
    },
    insert() {
      const dataItem = { inEdit: true, Discontinued: false };
      this.gridData.push(dataItem);
    },
    edit: function(e) {
      Vue.set(e.dataItem, "inEdit", true);
    },
    save: function(e) {
      if (!e.dataItem.ProductID) {
        const product = { ...e.dataItem };
        delete product.inEdit;
        product.ProductID = this.generateID();

        this.gridData.pop();
        this.listPrimitive.add(product);
      } else {
        const product = { ...e.dataItem };
        delete product.inEdit;
        const index = this.gridData.findIndex(
          p => p.ProductID === product.ProductID
        );
        this.listPrimitive.update(index, product);
      }
    },
    generateID() {
      let id = 1;
      this.gridData.forEach(p => {
        if (p.ProductID) id = Math.max(p.ProductID + 1, id);
      });
      return id;
    },
    update(data, item, remove) {
      let updated;
      let index = data.findIndex(
        p =>
          JSON.stringify({ ...p }) === JSON.stringify(item) ||
          (item.ProductID && p.ProductID === item.ProductID)
      );
      if (index >= 0) {
        updated = Object.assign({}, item);
        data[index] = updated;
      }

      if (remove) {
        data = data.splice(index, 1);
      }
      return data[index];
    },
    cancel(e) {
      if (e.dataItem.ProductID) {
        Vue.set(e.dataItem, "inEdit", undefined);
      } else {
        this.update(this.gridData, e.dataItem, true);
      }
    },
    remove(e) {
      e.dataItem.inEdit = undefined;
      const index = this.gridData.findIndex(
        p =>
          JSON.stringify({ ...p }) === JSON.stringify(e.dataItem) ||
          (e.dataItem.ProductID && p.ProductID === e.dataItem.ProductID)
      );
      this.listPrimitive.remove(index);
    },
    cancelChanges(e) {
      let dataItems = this.gridData.filter(p => p.inEdit === true);

      for (let i = 0; i < dataItems.length; i++) {
        this.update(this.gridData, dataItems[i], true);
      }
    },
    initialise(hamoni) {
      hamoni
        .createList(primitiveName, [
          {
            ProductID: 1,
            ProductName: "Chai",
            UnitsInStock: 39,
            Discontinued: false,
            FirstOrderedOn: new Date(1996, 8, 20)
          }
        ])
        .then(primitive => {
          this.listPrimitive = primitive;
          this.gridData = this.listPrimitive.getAll();
          this.subscribeToUpdate();
        })
        .catch(alert);
    },
    subscribeToUpdate() {
      this.listPrimitive.onItemAdded(item => {
        this.gridData.push(item.value);
      });

      this.listPrimitive.onItemUpdated(item => {
        //update the item at item.index
        this.gridData.splice(item.index, 1, item.value);
      });

      this.listPrimitive.onItemRemoved(item => {
        //remove the item at item.index
        this.gridData.splice(item.index, 1);
      });
    }
  }

In the initialise() method, we call hamoni.createList() to create a sync primitive to store data. When this succeeds, we update the grid data and then subscribe to change events using subscribeToUpdate(). The subscribeToUpdate() method has code to listen for changes in the sync primitive for when data is added, updated, or removed.

The rest of the methods are used by Kendo UI’s Vue Grid. The insert method triggers insert and creates a new object with property inEdit set to true and the grid component notices this and enters edit mode. The edit() method does a similar thing and sets inEdit to true for the current selected row data. In the remove() method, we remove data from Hamoni Sync by calling this.listPrimitive.remove(index), passing it the index of data to delete. The save() method handles saving new or existing data. To add new record, we call this.listPrimitive.add(), passing it an object to add, and this.listPrimitive.update(product) to update a product.

All looking good so far. The next thing for us is to create the DropDownCell and CommandCell component we referenced earlier. In the components folder, add a new file named DropDownCell.vue.

<template>
  <td v-if="dataItem && !dataItem.inEdit" :class="className">{{ dataItem[field]}}</td>
  <td v-else>
    <select class="k-textbox" @change="change">
      <option>True</option>
      <option>False</option>
    </select>
  </td>
</template>

<script>
export default {
  name: "DropDownCell",
  props: {
    field: String,
    dataItem: Object,
    format: String,
    className: String,
    columnIndex: Number,
    columnsCount: Number,
    rowType: String,
    level: Number,
    expanded: Boolean,
    editor: String
  },
  methods: {
    change(e) {
      this.$emit("change", e, e.target.value);
    }
  }
};
</script>

That code will render a dropdown for a column if it’s in edit mode; otherwise, it displays the text for a cell.

Add a new file in the same folder called CommandCell.vue.

<template>
  <td v-if="dataItem && !dataItem['inEdit']">
    <button class="k-primary k-button k-grid-edit-command" @click="editHandler">Edit</button>
    <button class="k-button k-grid-remove-command" @click="removeHandler">Remove</button>
  </td>
  <td v-else>
    <button
      class="k-button k-grid-save-command"
      @click="addUpdateHandler"
    >{{this.dataItem.ProductID? 'Update' : 'Add'}}</button>
    <button
      class="k-button k-grid-cancel-command"
      @click="cancelDiscardHandler"
    >{{this.dataItem.ProductID? 'Cancel' : 'Discard'}}</button>
  </td>
</template>

<script>
export default {
  name: "CommandCell",
  props: {
    field: String,
    dataItem: Object,
    format: String,
    className: String,
    columnIndex: Number,
    columnsCount: Number,
    rowType: String,
    level: Number,
    expanded: Boolean,
    editor: String
  },
  methods: {
    onClick: function(e) {
      this.$emit("change", e, this.dataItem, this.expanded);
    },
    editHandler: function() {
      this.$emit("edit", this.dataItem);
    },
    removeHandler: function() {
      this.$emit("remove", this.dataItem);
    },
    addUpdateHandler: function() {
      this.$emit("save", this.dataItem);
    },
    cancelDiscardHandler: function() {
      this.$emit("cancel", this.dataItem);
    }
  }
};
</script>

The code above will render buttons in a cell based on if it is in edit mode or not.

Now we’re all ready to try out our code. Open the terminal and run npm run serve.

Conclusion

Isn’t it awesome to build a real-time editable data table so easily and in under 10 minutes like we just did? Kendo UI for Vue allows you to quickly build high-quality, responsive apps. It includes all the components you’ll need, from grids and charts to schedulers and dials. I’ve shown you how to use the Grid component and we only used the edit functionality. There are more features available with it than what we’ve covered. Check out the documentation to learn more about other possibilities with the Grid component from Kendo UI for Vue.

For the real-time data we used Hamoni Sync. Hamoni Sync is a service that allows you store and synchronize data/application state in real-time. This allows you to store data for the grid and get a real-time update when a record changes.

You can download or clone the project with source code on GitHub.

For More on Vue:

Want to learn about creating great user interfaces with Vue? Check out Kendo UI for Vue, our complete UI component library that allows you to quickly build high-quality, responsive apps. It includes all the components you’ll need, from grids and charts to schedulers and dials.

30s ad

Learn by Doing: Vue JS 2.0 the Right Way

Vue.js 2 Essentials: Build Your First Vue App

Sıfırdan İleri Seviye Vue.JS Eğitimi ve Uygulama Geliştirme

Programador FullStack JS Vue Node: Proj Galeria Vídeo e CRUD

What are the differences between the various JavaScript frameworks? E.g. Vue.js, Angular.js, React.js

What are the differences? Do they each have specific use contexts?

What are the differences? Do they each have specific use contexts?

Ember.js vs Vue.js - Which is JavaScript Framework Works Better for You

Ember.js vs Vue.js - Which is JavaScript Framework Works Better for You

In this article we will discuss full details and comparison of both Ember.js and Vue.js

JavaScript was initially created to work for web applications. But today they have become the favorite of mobile app developers. Most of the developers prefer to work with frameworks based on JavaScript. It simplifies coding. You can use JavaScript with almost any framework.

The use of a particular framework will decide how easy and fast it is to create the app. So, you must choose the best one suited for the app that you are planning to build. You must make a wise choice so that you benefit in the end. Among the crowded market, two of the frameworks stand out. We will make a comparison between Ember.js and Vue.js.

Why Do You Select A Particular Framework?

Before we start comparing the two frameworks, we should understand the factors that lead to the choice of a framework. Each developer chooses a framework before he or she goes to work on an app. Let us see the reasons for the selection.

● The codes must be easy to understand and transparent.

● The framework should give the maximum power with the least amount of coding.

● The framework should provide a well laid out structure to work on.

● Does the framework support an in-built router or an external plug-in router?

● The framework should be able to transfer more data on a full page-load so that it becomes a single-page app. A single-page app is more beneficial for the application.

● In single page architectures if there is a need for users to share links to sub-screens within the interface, then the framework should have the capacity to route based on the URL.

● A tighter template option can help in enabling two-way binding.

● The framework should not conflict any third-party library.

● Testing the codes inside the framework should be easy.

● The framework should provide the HTTP client service for AJAX calls

● The documentation is essential. It should be complete and up-to-date.

● The framework should be compatible with the latest version of the browser.

● The framework has to fulfill the above conditions for easy construction of the app. You must ensure that the framework you choose meets the conditions.

Vue.js Explained

Developers are always looking at new frameworks to build their apps. The main requirements are speed and low cost. The framework should be easy to use by even new developers. You should be able to use it at low cost. Other considerations are about simple coding, proper documentation, etc.

Vue.js combines a lot of good when it comes to software language for web app development. The architecture of Vue.js is easy to put in use. The apps developed using Vue.js are easy to integrate with new apps.

Vue.js is a very lightweight framework. It makes it fast to download. It is also much faster than other frameworks. The single-file component nature of the framework is also beneficial. The size has made it very popular.

You can further decrease weight. With Vue.js you can separate the template-to-virtual DOM and compiler. You can only deploy the minified and zipped interpreter which is only 12 KB. You can compile the templates in your machine.

Another significant advantage of Vue.js is that it can integrate easily with existing applications created with JavaScript. It will make it easy for using this framework to make changes to applications already present.

Vue.js also integrates easily with other front-end libraries. You can plug in another library and make up for any deficiency in this framework. This feature makes this tool a versatile one.

Vue.js uses the method of rendering on the streaming-side server. You can render your component and get a readable stream. You can then send this to the HTTP server. It makes the server highly responsive. Your users will get the rendered content very quickly.

Vue.js is very SEO friendly. As the framework supports server-side rendering, the views are rendered directly on the server. The search engines list these.

But the most important thing for you is the ease with which you can learn Vue.js. The structure is elementary. Even new developers will find it easy to use it to build their apps. This framework helps in developing both small and large templates. It helps to save a lot of time.

You can go back and check your errors very easily. You can travel back and inspect all the states apart from testing your components. It is another important feature as far as any developer is concerned.

Vue.js also has very detailed documentation. It helps in writing your applications very quickly. You can build a web page or app with the basic knowledge of HTML or JavaScript.

● Vue.js has pure architecture. It helps in integration with other apps

● Vue.js is lightweight and fast. It can be made lighter by deploying only the interpreter

● You can separate the compiler and the template-to-virtual DOM.

● Due to smooth integration, you can use this to make changes to existing apps

● To make up for any shortfall, you can plug-in any library and makeup.

● As Vue.js uses streaming-side server rendering, your users can get quick responses.

● The server-side rendering also helps in being ranked higher by search engines.

● It has a simple structure. Easy to use for any new developer

● You can go back and check and correct your errors.

● You can check all the existing states.

● Detail documentation also helps build the web page or application very quickly.

Ember.js Decoded

Ember.js is an MVVM model framework. It is open-source software. This platform is mostly used for creating complex multi-page applications. It maintains up-to-date features without discarding any of the old features.

With this framework, you have to follow the architecture of the framework strictly. The JS framework is very tightly organized. It reduces the flexibility that other frameworks might offer.

There is a very refined and developed control system for its platforms and tools. You can integrate it with the new version with the tools provided. There is strict guidance about avoiding outdated APIs.

You can understand Ember’s APIs easily. They are also easy to work. You can make use of highly complex functionalities simply and straightforwardly.

The performance is better as similar jobs are processed together. It creates batches of similar bindings and DOM updates to improve the performance. It means that the browser needs to process them in one go. It will avoid recomputing for each task, wasting a lot of time.

You can write the codes in a simple manner and modules. You can use any of Ember’s APIs. It is possible due to the presence of Promises everywhere.

Ember comes with a well-written guide. The API is recorded in a useful manner. It is a front-end framework that is loaded. Ember has a router, pipeline, services, etc. of its own.

The basis for views, controllers, models, and framework is the Ember Object Model. All components come from the same objects. The framework is firm and steady. The reason is that all elements have similar jobs and characteristics.

Ember has made the general application, organization, and structure clear so that you don’t make any mistakes. You will have no chance to complicate the application unnecessarily. If you have to go out of the defined limits, you will have to force your way out.

The language used for templating in Embers is Handlebars. This language helps Embers to keep its logic out of view. The clean syntax of Handlebars makes it easy for you to read and understand the templates. Handlebar templates are faster to load.

Another advantage you gain from Handlebar is that you don’t have to update your template every time you add or remove data from the page. It will be done automatically by the language itself.

A community that is continually improving the framework supports Ember. They are updating the framework with the latest technology. They also make sure that backward compatibility is possible.

● Ember.js is an open-source MVVM model framework suitable for complex multiple-page applications.

● It offers both the latest and old features.

● It has a very tightly structured framework which doesn’t offer much flexibility

● A very refined control system helps you to integrate with new versions without any problem.

● There is strict guidance about avoiding outdated API versions.

● Ember’s APIs help you to use complex functionalities in a simple manner

● There is no recomputing for each task as the framework allows the browser to do similar functions together.

● Promises allow you to write modular and straightforward code using any API of Ember.js.

● Ember.js is a fully loaded, front-end framework.

● The framework is stable because all components have the same functionalities and properties.

● It has well-defined limitations which will prevent your complicating your application

● Handlebars, the language used by Ember.js allows you to read and understand templates easily. It also helps to load the templates faster.

● Handlebars will ensure to update the template every time you add or remove data.

● Ember.js has an active community that updates the framework regularly and facilitates backward compatibility.

A Comparison Between Ember.js And Vue.js

This article intends to compare the features of both frameworks. Let us see how the characteristics of these frameworks compare. It will help you to make use of the right framework for your web application.

When you need a modern engine for an old application, it is Vue.js which will help you. It combines the best properties of other frameworks. Vue.js is a developing framework. A ready-to-use library of interface elements does not exist. However, many third-party libraries can help you.

Ember.js offers you a well-organized and trustworthy framework. When the development team is big, this is the framework that suits best. It allows everyone to understand the written code and contribute to a common project. The technology will be up-to-date, and the platform will be stable.

Vue.js can help you use the syntax of different kinds. It helps in writing the codes with ease. It is also an SEO friendly framework. Ember is a fully loaded front-end framework and can help you develop the applications very fast. But it is not suitable for developing small projects.

It is not easy to say this is better than that. It will depend on what kind of project you have undertaken. Both have their pluses and minuses. The below table will help in a better comparison.

Final Thoughts

It is not easy to conclude as to which is better. It all depends on the application that you want to develop. Both frameworks are developing. Both are getting updates. Both the communities are working on the frameworks.

While Vue.js is more comfortable for writing codes, Ember is a full-stack framework allowing the development of apps very fast. It is suitable for big projects. It is too complicated to be used for smaller projects.

We hope you had a great time reading this article. If you’ve any questions or suggestions related to this blog, then feel free to ask them in the comment section. Thank You.!