Skip to main content Skip to footer

How to Bind a JavaScript Datagrid to GraphQL Service

As a front-end developer, GraphQL seems too good to be true. It can be used to simplify data access, which makes our jobs much easier. What is GraphQL? It is an abstraction layer that sits on top of any number of data sources and gives you a simple API to access all of it.

The beauty of GraphQL is that you can define exactly what data you want to come back from the server and how you want it formatted. It also lets you get data from many sources in a single request. GraphQL also uses a type system to provide better error checking and messaging. 

Ready to Test It Out? Download Wijmo's 30-Day Free Trial Today!

Let's take a look at a really basic GraphQL sample. 

This is the URL for the service we will be working with: https://demodata.grapecity.com/northwind/graphql

Conveniently, there is a nice UI for testing queries in GraphQL too! Here is the query tester: https://demodata.grapecity.com/northwind/ui/graphql

For this example, we are using the classic Northwind database from Microsoft. Let's say we want to get a list of products, but we only need the product ID and name fields. Here is what our query should look like:

{
  products {
    productId
    productName
  }
}

And here are the results in our query tester:

JavaScript Datagrid GraphQL

That's how simple GraphQL is!

Let's use it in a JavaScript application and bind a powerful JavaScript DataGrid (FlexGrid) to the data.

For this simple application, we will just use the fetch API to call our GraphQL service. Feel free to follow along with this live example: https://stackblitz.com/edit/wijmo-with-graphql-lruhgx

Let's use a similar query as above, but add some more fields to it. Here is how our fetch request looks:

fetch("https://demodata.grapecity.com/northwind/graphql", {
 method: "POST",
 headers: {
 "Content-Type": "application/json",
 Accept: "application/json"
 },
 body: JSON.stringify({
 query:
 "{ products { productId, productName, unitPrice, unitsInStock, unitsOnOrder, reorderLevel, discontinued, categoryId }}"
 })
})

If we look in the JS console, we can see the results come back with an array of products we can use to bind to. 

JavaScript Datagrid GraphQL

Let's add some Wijmo to this application so we can give this data some proper User Interface. To install Wijmo, use the following command:

npm install @grapecity/wijmo.all

First, we will need to import Wijmo CSS along with the @grapecity/wijmo and @grapecity/wijmo.grid modules. In our case, we have a single index.ts file in our application where we will add this:

import "@grapecity/wijmo.styles/wijmo";
import * as wjcCore from "@grapecity/wijmo";
import * as wjcGrid from "@grapecity/wijmo.grid";

And the FlexGrid will need a DOM element to host it. So in the index.html file, we will add an empty <div> with a unique ID:

 <div id="results"></div>

Now we can create two components:

  1. CollectionView - this is the observable collection (array) that we will populate with data and bind our grid to
  2. FlexGrid - this is our JavaScript DataGrid that will be used to display data

Here is how we can initialize both components and bind the grid to the CollectionView:

let productView = new wjcCore.CollectionView([]);

let grid = new wjcGrid.FlexGrid("#results");
grid.itemsSource = productView;

Now that we have the data and the components, we can put it all together. After our fetch call, we will add then() promises to convert to JSON and populate our CollectionView with the results. 

fetch("https://demodata.grapecity.com/northwind/graphql", {
 ...
})
 .then(r => r.json())
 .then(data => bindData(data));

function bindData(data) {
 productView.sourceCollection = data.data.products; //populate CollectionView with results
}

Our DataGrid is already bound to the CollectionView (and the CollectionView is observable), so the grid will render the data as soon as the CollectionView is populated! That's the beauty of using observable collections and components that support them. It is true data-binding since updates from one component automatically propagate to others. 

Here is what our grid looks like when it renders:

JavaScript Datagrid GraphQL

And with just that little bit of code, we get a fully functional DataGrid bound to a GraphQL source! It's amazing how productive you can be working with GraphQL and powerful components like Wijmo. 

If you want to try this application yourself, here is a live example: https://stackblitz.com/edit/wijmo-with-graphql-lruhgx

More Advanced DataGrid and GraphQL Features

Let's take this a step further by using some more features from GraphQL and Wijmo!

Lookup Tables and DataMaps

One of the most interesting features of GraphQL is aggregating many different queries into a single request. This feature can be used to minimize round trips to the server, which could improve the responsiveness of your application. Of course, it is still appropriate to make multiple round trips to the server, but this is a really neat feature to use.  

In our example, we loaded products. We also got a categoryID for each product because each product is associated with a category from another dataset. The categoryID is used to look up the Category. The cool thing about GraphQL is that we can load both products and categories in one query!

Let's expand our query to include categories like so:

{
  products {
    productId
    productName
    unitPrice
    unitsInStock
    unitsOnOrder
    reorderLevel
    discontinued
    categoryId
  }
  categories {
    categoryId
    categoryName
  }
}

If we put this in our query tester, we can see that we now get two arrays (one for products and the other for categories)

JavaScript Datagrid GraphQL

Now that we are loading in Categories as well as Products, we will need another CollectionView. 

let categoryView = new wjcCore.CollectionView();

And FlexGrid supports these lookup tables with an API called DataMaps. You can use DataMaps to point an index column to look up its text value and even automatically get a nice dropdown editor that lists all available options. To use this feature, we create a DataMap and bind it to our new Category CollectionView.

let categoryMap = new wjcGrid.DataMap(
  categoryView,
  "categoryId",
  "categoryName"
);

Finally, we point the Category column in our grid to this new DataMap.

let grid = new wjcGrid.FlexGrid("#results", {
  columns: [
    ...
    {
      header: "Category",
      binding: "categoryId",
      dataMap: categoryMap
    },
    ...
  ]
});

Let's take a look at the results. Instead of seeing just a CategoryID in our Category column, we now see the correlating Category Name. And if we edit the cell, we see a list of all Categories to choose from. This is a simple way to implement lookup tables in GraphQL and Wijmo!

JavaScript Datagrid GraphQL

Typed Data 

Another nice feature of GraphQL is that they include typed data structures. Let's use these typed objects in our data to provide better formatting and editors based on the data type.

Formatting Typed Values

First, let's format the data to look more user-friendly. Wijmo has built-in formatting that uses our globalization API. So values are formatted for the current culture. Formatting in the FlexGrid is as simple as providing a format property to the column you want to format. The format syntax is based on the .net standard. FlexGrid also will infer dataType based on the first row of data, but it's always best to explicitly set the dataType on columns that need formatting or special editors. 

Here we set the three numeric columns to a Number type, and we set the Price column to be formatted as currency (format: "c"), which shows two decimal places. Next, we set the In Stock and On Order columns to numeric format (format: "n0"), which shows zero decimal places. Currency makes sense to show decimal places, but we should not show decimals for items with only whole number values. 

let grid = new wjcGrid.FlexGrid("#results", {
  columns: [
    ...
    {
      header: "Price",
      binding: "unitPrice",
      dataType: wjcCore.DataType.Number,
      format: "c"
    },
    {
      header: "In Stock",
      binding: "unitsInStock",
      dataType: wjcCore.DataType.Number,
      format: "n0"
    },
    {
      header: "On Order",
      binding: "unitsOnOrder",
      dataType: wjcCore.DataType.Number,
      format: "n0"
    },
    ...
  ]
});

And here are the results:

JavaScript Datagrid GraphQL

User-friendly Editors Based on Data Type

Now, just by setting the dataType property on columns in FlexGrid, you will automatically get some improved editing. For example, the grid will prevent numeric columns from taking any input other than numbers. But let's use custom editors to make editing an excellent user experience.

FlexGrid columns have an editor property that allows you to replace the built-in editor with a custom one. Wijmo includes an input module that has some really nice editors for numbers, currency, dates, collections, masks, and more. So we can easily use those to enhance the editing experience.

First, let's replace the editor in the Price column. We will use an InputNumber control and some settings to make it more user-friendly for editing currency. Note that we use the same format string that we used in the column. This will make the editor consistent with the displayed value.

let grid = new wjcGrid.FlexGrid("#results", {
  columns: [
   ...
    {
      header: "Price",
      binding: "unitPrice",
      dataType: wjcCore.DataType.Number,
      format: "c",
      editor: new wjcInput.InputNumber(document.createElement("div"), {
        format: "c"
      })
    },
    ...
  ]  
});

Now our editor uses a numeric input box and is formatted to look like currency. 

JavaScript Datagrid GraphQL

We can do something similar with our In Stock and On Order columns as well. Let's use an InputNumber control but add some more settings to make changing these units more user-friendly. We will set the format to "n0" to match our column. We will also use the step property to ensure the control shows increment and decrement buttons. And let's also set a minimum and maximum value to restrict editing within that range.

let grid = new wjcGrid.FlexGrid("#results", {
  columns: [
    ...
    {
      header: "In Stock",
      binding: "unitsInStock",
      dataType: wjcCore.DataType.Number,
      format: "n0",
      editor: new wjcInput.InputNumber(document.createElement("div"), {
        format: "n0",
        step: 1,
        min: 0,
        max: 10000
      })
    },
    {
      header: "On Order",
      binding: "unitsOnOrder",
      dataType: wjcCore.DataType.Number,
      format: "n0",
      editor: new wjcInput.InputNumber(document.createElement("div"), {
        format: "n0",
        step: 1,
        min: 0,
        max: 10000
      })
    },
    ...
  ],
});

The result is a numeric input with nice buttons for increasing or decreasing the value by one unit. 

JavaScript Datagrid GraphQL

Using Validation 

The next thing we will do is add validation to our application. Wijmo's CollectionView has a simple yet powerful validation method called getError. When this is defined, it gets honored by any FlexGrid bound to the same CollectionView.

So let's write a getError handler and add some validation rules. This data is for inventory management and already has a few properties that can be used to make rules. 

function getError(item, propName) {
  switch (propName) {
    case "unitsInStock":
      return item.discontinued == false &&
        item.unitsInStock < item.reorderLevel &&
        item.unitsOnOrder == 0
        ? "Units too low and none on order!"
        : "";
  }
  return null;
}

In this validation handler, we look at unitsInStock to determine if new units should be ordered. We ensure the item isn't discontinued; we show the error message if the unitsInStock is lower than the reorderLevel (and unitsOnOrder is 0). 

Now that we have the handler ready, we can add it to the CollectionView initialization:

let productView = new wjcCore.CollectionView([], { getError });

Now the CollectionView will run that handler anytime the dataset changes or is attempted to change. Here is how FlexGrid renders the error:

JavaScript Datagrid GraphQL Error

Adding Full-text Search

Another helpful feature in datagrids is full-text search. FlexGrid has an optional extension that makes the search easy. FlexGrid also has Excel-like filtering that's just as easy to add too. But in this instance, we will use search.

To add this extension, we add a container for the search box in HTML:

<div id="search"></div>

Then we import the search module:

import * as wjcGridSearch from "@grapecity/wijmo.grid.search";

Lastly, we initialize the FlexGridSearch component and point it at our instance of FlexGrid to bind to.

let search = new wjcGridSearch.FlexGridSearch("#search", {
  placeholder: "Search Records...",
  grid: grid
});

 When we run the app, we will have a full-text search working in FlexGrid. 

JavaScript Datagrid GraphQL

Go Beyond

GraphQL is an excellent tool for managing data in JavaScript applications. And it pairs very well with Wijmo, especially our CollectionView and FlexGrid components. This tutorial showed how simple GraphQL and Wijmo make building applications. Both GraphQL and Wijmo have many more features to explore so that you can take things far beyond this example. Give it a try yourself, and let us know what you build!

Ready to Test It Out? Download Wijmo's 30-Day Free Trial Today!

Tags:

comments powered by Disqus