After this tutorial you will be able to
- Develop online/offline data manager apps with remote-to-local data synchronization
- Bind your OData records to your HTML5 user interface
- Develop online-offline applications with data synchronization capabilities
Things you will need to start
- Your favorite Text Editor
- The latest version of JayData library - You can download it from JayData.org or from NuGet
- An available OData service – You might want to use a live sample service if you don’t want to build an own one
- You will need a Visual Studio 2012 to run your own OData service from the pre-packed project
What is JayData
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.
[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.
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.
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.
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
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()
[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
- IntelliSense/autocomplete support
- TypeScript support
- Faster context initialization (the app already has the metadata)
Benefits of using context with dynamic model
- No need to re-generate entity model in case of schema-changes
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:
- list the categories
- list the products in the selected category
- display the details of the selected product
- modify products
Before we begin developing the Northwind product editor, we will need a working OData endpoint.
- You can build it from scratch by following our tutorial – How to build a simple OData-based AJAX application
- You can download a pre-built solution and run it from Visual Studio
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.
Now we copy our brand-new northwind.js to our project directory and include it in our project.
[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
[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.
[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!
[gist id="5975739" file="17 update existing product with JayData.js"]
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.
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.
- the ready-to-use context
- the context factory method that you can call with or without parameters to initialize a new context instance
- 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.
UI library integration
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
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.