o.js is a small (minified 14.4 KB) client-side library for requesting data from an OData service. It is designed to run in a browser environment, however it also runs in node.js. In a browser environment it has no dependencies on other libraries and can be used standalone. The main goal of the library is, to provide a simple solution to query OData services from any browser. If you like to use it you can install it via
npm install odata or just download the o.min.js file from this GitHub repository and add it to your webpage in a
In this tutorial I will show you how easy you can use it in your web application and explain to you the example app. This application using some extended routing functionalities of o.js in combination with knockout.js to display detailed information about the OData TripPinService, a example service provided by odata.org.
Getting started with o.js
The installation of o.js is simple. You just need to include the
o.js file into your page and you are ready to query OData services:
o.js adds a
o() function to the global namespace. This function can be used to define a query. It returns a oHandler, which then allows to retrive, change or push data to the service:
The example above shows how to get the data from the defined handler with the
get() function. The
get()-function accepts an success- and error-callback to get the return of the request. If you prefer to use promise, you can use q.js. The following example shows how to get data from the endpoint and manipulate the result with promise:
If you include q.js you can call the
get() function without a callback and it returns a promise. The data is then stored in a
o.data which you can manipulate and save by calling save(). The
save() itself is used for POST and PUT request to the database and returns a second promise. This way the function above requested a resource, manipulates it and saves the manipulated data back to the service.
As you can see the requested service URL is quite long. If you use o.js to query one endpoint often you can configure o.js to use the same endpoint all the time:
From now on you can use only the resource name to query an endpoint. The following example uses the configured endpoint and the
save() function to POST, PUT and DELETE data to the TripPinService:
In the promise chain above o.js first adds a new user using
post() and saves it to the service. When this is promised we initializing a new handler to find the person which was added and modify him with the
patch() function. Afterwards we delete him from the service by using the
Chaining the query
We already used the chained function
find() to find a specific person. o.js allows multiple functions to detail your query. The
find() is a special case, because it allows to find a specific resource by the key. But you can also use functions to limit the result. For example you can chain your query with
.skip(2).take(5) to request only the first 5 rows skipped by the first 2 rows. There are many more chained function and you can find a complete list in the o.js readme. Mostly you will use the where function to find something:
whererequest, you need to use the OData equivalent (e.g.
FirstName eq "foo").
As mentioned you can chain multiple functions to build a query. The following example shows a pagination function which expands the result with the Trip result:
Complex pages with routing
o.js has a build in hash-routing functionality. This allows you to map a oHandler to a route. It allows an easy way to display data from a OData service on a Single Page Application. The o.js example uses the TripPinService, knockout.js and only 70 lines of code to display some useful information from the page.
For the example we will use the
route() function of o.js and bind the data to the DOM with knockout.js. I will not go in detail of knockout.js. If you want to learn more about knockout, you should try the excellent tutorials on knockoutjs.com.
If you try the example you will see a top navigation point
People. This is basically a typical html hash-link
<a href="#People">People</a> which does not change anything. But if we register a o.js route on this hash value, o.js automatically triggers the request to the configured endpoint. Therefore we first configure the endpoint:
The start and ready function defines what should be done when the request starts and what to do if the request ends. Here we just set a ko observable to true while the request is processed. We will later bind it to the DOM to display a loading spinner.
selfobject is a reference to this. This is usually done in knockout ViewModels-Function. For easier understanding the ViewModel-Function is left out here. You can find the full file here.
Afterwards you can define a route to map to the
The first parameter of the
route function is a string that maps to the hash. The second parameter is a callback that is triggered as soon as the first parameter and the hash is equal and the request to the OData service is done. When you now click on the top navigation link the callback gets triggered with the Data from the TripPinService. This callback then sets the knockout observable
self.route to ‘People’ and adds the data to the observableArray
self.People. Afterwards you only need to bind the data to your DOM with the knockout
self.route parameter is used to handle the visibility of a route. We then bind all the People returned by the OData service with the
ko foreach statement. In this statement we display the FirstName and LastName property to headings. Also we bind a href hash-link to the route
#People/Detail/ + UserName. To handle this route we register a second o.js route-handler:
The added route is a dynamic route. With
:0 the dynamic part of the route is defined. This dynamic part is added to the OData request as soon as the route matches. So for example, if you navigate to the hash
#People/Detail/russellwhyte the service request the resource
/People/?$format=json&$filter=UserName%20%20eq%20%20%27russellwhyte%27&$expand=Trips&$top=1. You can add multiple dynamic parts by defining them with
As you can see this routing also expands the Trips resource and saves all to the knockout observable
detailPeople. Therefore we can display the Trips of the person in the details by using the following DOM binding:
That’s all to display people from the TripPin-Example service and their Trips. With the
delete functions, explained in the beginning of this post, you can now add, modify or delete this data. In the full example you can find an example to delete Trips of a user.
One last thing is the loading animation. That is quite easy to do, because we already defined the
self.isLoading observable. By simply binding this to the DOM we can show a loading spinner to the user:
o.js is a simple way to query OData services fast. It allows to add CRUD operations on any OData-Service easily into your page. So everything perfect? Sadly not. o.js is not a complete OData-Solution. It only supports the basic OData functions and is not suitable for complex scenarios. For example the
batch operation is only supported rudimentary and ETag are not supported. However, if you need a quick request or want to display some OData service on a simple webpage, o.js is the right choice.