This tutorial will introduce the OData capabilities of the JayData library and gives you all the necessary information to succeed with your OData service via JavaScript. After going through the concept, we will implement a Northwind product editor – full read/write capable - app with JayData and jQuery. We will develop a HTML5/JavaScript client that is using a remote OData endpoint with the unified JavaScript Language Query (JSLQ) syntax. After we are finished with this first version, you will see how easy it is to sync the entities from our OData endpoint to a in-browser WebSQL or IndexedDB storage to have an online/offline app.

image_thumb

 

Target audience

After this tutorial you will be able to

Things you will need to start

What is JayData

JayData is a JavaScript data manager library that provides a friendly, unified developer experience over a number of different online and offline data APIs and data sources like IndexedDB, WebSQL or OData. For local databases, JayData provides automatic database creation and schema management (keys, indices). For OData services, JayData supports the translation of the service metadata document into an intelligent client environment where you can interact with data naturally using JavaScript. I would say JayData library is the „jQuery of data management”.

The JayData concept

Before we continue to the coding part, we have to understand the common terms of the library that will ring the bell to Entity Framework developers.

JavaScript Language Query (JSLQ)

The JavaScript Language Query is the unified syntax of JayData that was invented in order to manage all storages and cloud services with this unified API. JSLQ is natural for JavaScript developers and provides a friendly environment for developers who have used .NET LINQ before. To developers who use OData, this means the end of long string concatenations – let’s see an example how to get ONLY the product names from the list of products that are either Beverages (Category_Id = 1) or contain tofu in the product name regardless of the case, sorted by the product name.

[gist id="5975739" file="01 retrieve Northwind products - jQuery.js"]

[gist id="5975739" file="02 retrieve Northwind products with JayData.js"]

Read more about the syntax in JSLQ 101.

Storage providers

The library lets you to use pure JavaScript syntax to manage your data, this happens with the help of storage providers that transform JavaScript instructions to the storage-specific operations and parse the results to JavaScript objects. For example the OData storage provider builds the OData requests, initializes the HTTP connection, manages the protocol operations, parses the results and turnes them into typed JavaScript objects, meanwhile the IndexedDB provider initializes the IndexedDB connection, creates collections and indices, builds Cursor API statements and reads recordsets. As you can see, the JayData providers take care of all the dirty job to make you able to concentrate on your business logic.

Entities

JayData provides the data management capabilities with typed entities, all the managed types derive from the $data.Entity class, this way you get more than records: you can operate with data AND metadata (type description), state tracking, validation, events handlers. If you’re using the OData provider, entity definitions are built from the $metadata of the service endpoint. The declaration of JayData is the model definition of our application.

[gist id="5975739" file="03 JayData model: Northwind Product entity.js"]

The example below shows a part from the Northwind data model. This definition can be built manually or – for OData only – generated by JaySvcUtil.exe.

Entity sets

As the databases store the records in tables, OData publishes them through EntitySets. JayData kept this concept and behavior, and maps all the collections to a derived type of the EntitySet class. The collections publish the API to CRUD the entities and manages the associations.

Entity context

JayData contexts are similar to Entity Framework contexts, so this is the entry point of your code. Entity contexts can be defined by enlisting the EntitySets in it, and initialized by specifying a storage provider name – and optionally its configuration. The context tracks the changes of the entities in the entity sets and performs the necessary actions on them. Adding, updating, deleting entities happen through the context, which holds the reference to the added, updated and deleted objects and dispatches the operations (HTTP requests) to the OData endpoint after calling the context.saveChanges().

Just like the Entities, EntityContexts can be defined manually or generated the JaySvcUtil.exe if you work with an OData service.

[gist id="5975739" file="04 JayData context definition.js"]

Context initialization static data model generated by JaySvcUtil

The JaySvcUtil.exe is a tool packed with the JayData Nuget package, and you can also download the latest version from JaySvcUtil CodePlex page. This tiny tool grabs the result of the $metadata of your service and generates JayData entity and context defintions from it to a JavaScript file, which you can include in your project structure to avoid writing the model definition by hand.

[gist id="5975739" file="05 Using JaySvcUtil.exe to generate JavaScript model from metadata service.cmd"]

JaySvcUtil generates TypeScript files as well, your can read our post how to use your OData endpoint with TypeScript.

Once you have the northwind.js included in your project, you can instantiate the context with the following lines.

[gist id="5975739" file="06  Init OData context with JayData - static model.js"]

As you can see the constructor of the context accepts parameters that configure the data provider. The beauty here is that you only need to change the parameters to work with different storage technologies. The initialization happens asynchronously, this is why you must perform all your operations with your context inside the onReady().

Developing the client app using JaySvcUtil.exe in parallel with the server-side development means you have to run the tool and copy the output to your project from time to time. If you see yourself re-generating model definitions often, consider using the dynamic context initialization with the $data.initService() function.

Dynamic context creation with $data.initService()

If you looking for an agile way to consume OData via JavaScript- that doesn’t require leaving your beloved text editor – the $data.initService() function will be your friend. This tiny tool does everything what you can achieve by combining JaySvcUtil.exe, the constructor of the Entity Context and the onReady() event handler – initService creates a ready-to-use OData proxy for your JavaScript app.

[gist id="5975739" file="07 Init OData context with JayData - dynamic model.js"]

This is simple and really easy to use, and it can be customized with a second configuration parameter, this will be explained in the advanced section.

Note that initService() requires the $metadata document to be accessible from the origin of your app, plus jQuery for promise management.

Benefits of using context with static model

Benefits of using context with dynamic model

Building a Northwind editor with JayData

In this chapter we will walk through all the steps you need to perform to create a Northwind product editor only with JayData and jQuery. The application will use a remote OData endpoint and implement the following features:

Before we begin developing the Northwind product editor, we will need a working OData endpoint.

We will use a static data model pre-generated by JaySvcUtil.exe, so let’s open our command prompt, enter the folder where we saved JaySvcUtil.exe, and run the command we already know from the previous chapter.

[gist id="5975739" file="05 Using JaySvcUtil.exe to generate JavaScript model from metadata service.cmd"]

Now we copy our brand-new northwind.js to our project directory and include it in our project.

Let’s create an index.html page with the following JavaScript files included:

[gist id="5975739" file="08 Include necessary libraries to work with OData.html"]

We will use jQuery to access DOM elements and JayData requires data.js only for OData requests.

Rendering the category list

We will retrieve the list of the product categories using JayData and insert the result to a HTML table with jQuery.

HTML template in our body:

[gist id="5975739" file="09 Northwind product editor HTML template.html"]

Now it is time to initialize our context with our service URL and retrieve the list of categories with JayData.

[gist id="5975739" file="10 Northwind product editor - entry point.js"]

JayData loads the necessary OData provider from the jaydataproviders folder based on the name passed to the context constructor. This auto-load behavior happens using all JayData providers.

After retrieving the array of categories, we render them to the list to the HTML table by calling therenderCategories function in the success callback.

[gist id="5975739" file="11 render category list.js"]

Listing the products in the selected category

As we can see in the renderCategories(), we want to list the products of the selected categories by calling theloadProduct() function in the onClick event handler of each category. This loadProduct() is a simple function with a JavaScript Language Query (JSLQ) syntax that makes requests to our OData endpoint to filter the products by the selected categoryID.

[gist id="5975739" file="12 load products by category.js"]

To keep the data management and the representation a little bit separated, we implement the rendering mechanism to the renderProducts() function. This function gets an array of typed Product entities from JayData.

[gist id="5975739" file="13 render product list.js"]

The necesessary HTML:

[gist id="5975739" file="14 productTable HTML template.html"]

Now we can list the categories and the products assigned to the selected category.

Displaying the selected product

We can see the editProduct() function call in the onClick event of the product list elements. This function uses JayData to retrieve a Product entity through OData by the selected ProductID, then we render the properties of the entity to the form.

HTML:

[gist id="5975739" file="15 product editor HTML template.html"]

Our code to display the product properties:

[gist id="5975739" file="16 get single product and render its properties.js"]

Great, we can read the categories and the products, it’s high time to save something back to our OData endpoint!

Updating products

Updating entities through OData means a custom HTTP request with MERGE or PATCH verbs and the changed properties in the body. We are lucky, because we don’t have to worry about this, JayData arranges this for use, we only have to write typed JavaScript code. Since we retrieved the selected product entity by JayData, we have the reference to this object, we can modify the properties of this entity and save it. It is important to attach the entity to the JayData context before we begin to modify the properties, this way JayData can track the changes of the entity and update only the changed fields.

[gist id="5975739" file="17 update existing product with JayData.js"]

Now we have a read/write capable product editor client that uses JayData to consume our OData service with a developer-friendly JavaScript API.

Data synchronization - Online/offline scenario

The goal: retrieve categories and products from our OData endpoint, save it to a local in-browser database and use the application on the local database with minimal changes to the code.

As JayData provides the same JSLQ syntax and set of data management practices for all storage technologies, you can use the entities retrieved from one datasource to save it to an other storage. You only need to create two contexts: one for the OData endpoint and one for the local in-browser database.

About the local database

JayData supports WebSQL/SQLite, IndexedDB and HTML5 local storage databases in the browser, developers instruct the library which provider to use by modifying the name parameter of the context constructor to ‘webSql’, ‘indexedDb’, ‘LocalStore’. This isn’t all what JayData is capable to – you can set ‘local’ to the name of the provider and JayData will find the available storage in the current browser.

Advanced $data.initService()

The initService() function was described in the first chapter with its easiest usage, but it supports more advanced scenarios. We would like to build a local database schema without specifying the model by hand, reusing the model of the OData endpoint would be great, and it is because the initService() helps you reuse the model of a context.

[gist id="5975739" file="18 sync - init local DB from OData model using JayData.js"]

The promise returned by the initService() function has three arguments.

  1. the ready-to-use context
  2. the context factory method that you can call with or without parameters to initialize a new context instance
  3. the type of the context

We can look for the snippet marked with “main” in the comment and change it to the following code

[gist id="5975739" file="19 online-offline data sync with JayData.js"]

Our code initializes an OData context, retrieves the data model from the $metadata service of the end-point, creates a local database context according to the available storage technology (WebSQL/IndexedDB/HTML5 localStorage). After the resetLocal() function cleans the local database, we are ready to retrieve all the categories and products from our OData datasource and insert it to the clean DB.

Please note, that JayData supports not only the addition of a single entity using the add(), but to add an array of entities using the addMany().

he example code on Github shows how you can do the same sync process using static model generated by JaySvcUtil.

Further improvements

UI library integration

We used jQuery to manipulate our DOM elements, which seems natural, but you can save many of this code if you use the JayData library with Kendo UIKnockout.js or Handlebars.

The synchronization process

The data sync process in this example was very basic, you can prepare your application for more records by retrieving the records in chunks. Read more about this in our blog - Synchronized Online/Offline data applications, part 2: Syncing large tables and tables with foreign relations

Summary

We have learned how to manage OData endpoints with JayData leveraging our JavaScript and jQuery experience, created the skeleton of a simple online/offline application with data synchronization to a local WebSQL or IndexedDB storage. We did all of this with the developer-friendly JSLQ syntax that you can use to consume OData service of Microsoft Dynamics CRM, too.

You can a working example from JayData Github repository and try the app on your machine.

Follow the latest developer news in the JayData blog and read about awesome JayData Pro features in JayStack blog.