Showing posts with label Breeze JS. Show all posts
Showing posts with label Breeze JS. Show all posts

Friday, 1 November 2013

Using Breeze JS to Consume ASP.NET Web API OData in an Angular JS Application

In last post, we saw how Breeze JS eases the job of querying OData services. It will be a lot of fun to use this great library with our favourite SPA framework, Angular JS. In this post, we will see how to hook up these two libraries to create data rich applications.

As stated in previous post, Breeze required data.js for to understand OData conventions. All functions performing CRUD operations in Breeze return a Q promise. Any changes made to properties of $scope inside then method of Q are not watched automatically by Angular, as 
callbacks hooked up to Q are executed in non-angular world. If the same thing can be done using $q, we don’t have to call $scope.$apply to make the changes visible to Angular’s dirty checking. For this purpose, Breeze team has created a module (use$q). This module can be installed in the project via NuGet: Breeze.Angular.Q. This package adds a JavaScript file to the application, breeze.angular.q.js. Once this file is included and the module is loaded, we don’t need q.js anymore.

Following is the list of scripts to be included on the page:

<script src="Scripts/angular.js"></script>
<script src="Scripts/datajs-1.1.1.js"></script>
<script src="Scripts/breeze.min.js"></script>
<script src="Scripts/breeze.angular.q.js"></script>

We don’t need jQuery anymore as Breeze detects presence of Angular and configures its AJAX adapter to use $http. (Check release notes of Breeze 1.4.4)

As both Angular and Breeze are JavaScript libraries, they can be easily used together. But we can’t enjoy the usage unless we follow the architectural constraints of Angular JS. The moment we include Breeze.js in an HTML page, the JS object “breeze” is available in the global scope. It can be used directly in any of the JavaScript components, Angular controllers and services are no exceptions. Best way to use an object in any Angular component is through Dependency Injection. Any global object can be made injectable by creating a value.
var app=angular.module(‘myApp’, []);
app.value(‘breeze’, breeze);
app.service(‘breezeDataSvc’, function($q, breeze){
 //logic in the service
});

We need to ask breeze to use $q as soon as the Angular JS application kicks off. For this, we need to register the following run block:
app.run(['$q','use$q', function ($q, use$q) {
    use$q($q);
}]);
Breeze has to be configured to work with OData service and use Angular’s AJAX API instead of jQuery. It is done by the following statement:
breeze.config.initializeAdapterInstances({ dataService: "OData" });

Now all we need to do is instantiate an EntityManager and start querying. Following is the complete implementation of the service including a function that does a basic OData request:
app.service('breezeDataSvc', function (breeze, $q) {
    breeze.config.initializeAdapterInstances({ dataService: "OData" });
            
    var manager = new breeze.EntityManager("/odata/");
    var entityQuery = new breeze.EntityQuery();
            
    this.basicCustomerQuery = function () {
        var deferred = $q.defer();
        manager.executeQuery(entityQuery.from("Customers").where("FirstName", "contains", "M")) .then(function (data) {
            deferred.resolve(data.results);
        }, function (error) {
            deferred.reject(error);
        });
        return deferred.promise;
    };
});

Following is a simple controller that uses the above service and sets the obtained results to a property in scope:
app.controller('SampleCtrl', function ($scope, breezeDataSvc) {
    function initialize() {
        breezeDataSvc.basicCustomerQuery().then(function (data) {
            $scope.customers = data.results;
        }, function (err) {
            alert(err.message);
        });
    };

    initialize();
});

Run this page on browser and see the behaviour.

Update: This post was updated on 11th January 2014 as per Breeze Angular Q-Promises page in documentation of Breeze

Happy coding!

Tuesday, 29 October 2013

Querying ASP.NET Web API OData using Breeze JS

A few days back I blogged about the query options supported by ASP.NET Web API OData. Though we get a number of options to query data from clients through REST-based URLs, building the URLs at runtime is not an easy task. One of the very popular ways to call services from rich JavaScript applications is through jQuery AJAX. While jQuery AJAX abstracts the pain of dealing with browser and configuring parameters, it expects an absolute URL. Writing a set of fixed URLs can be easy, but in larger applications we will have a number of scenarios where we need to build most part of an OData URL based on decisions. We can’t inspect any of the URLs unless a request is sent to them. It would be good to have an abstraction that generates the queries for us.

Breeze JS is the right library in such case. Breeze is built with OData query standards. But it is not limited to querying OData. Breeze can manage complex object graphs, cache data, query cached local objects, save complex objects to server, and perform validations and more. Breeze solves all the problems that one might face while working with data in rich JavaScript applications. In this post, we will see how Breeze simplifies querying OData services. We will explore some other essential features Breeze in future posts. To learn more about Breeze, make sure to check their official documentation and interactive tutorials on Breeze website.

Breeze uses jQuery for AJAX and Q for promises. Breeze needs data.js to talk to OData sources. Getting these scripts in Visual Studio is easy through the following NuGet packages:


Now add references to these libraries on the page.

<script src="~/Scripts/jquery-1.9.1.min.js"></script>
<script src="~/Scripts/datajs-1.1.1.min.js"></script>
<script src="~/Scripts/q.min.js"></script>
<script src="~/Scripts/breeze.min.js"></script>


Breeze heavily uses metadata of the data structure on which it has to work. ASP.NET Web API OData service exposes the metadata through its endpoint. But we need to set an important property to the OData configuration, it is Namespace. Adding the following statement to the Web API OData endpoint configuration:
modelBuilder.Namespace = "WebAPI_EF_OData.Models";

Make sure to check Brian Noyes’ step-by-step tutorial on Consuming ASP.NET Web API OData using Breeze. Brian does a nice job by explaining each step in detail.

Let’s set up Breeze on the client side. Add the following code to the page in which you want to perform breeze operations:

$(function () {
    var baseAddress = "/odata";
    breeze.config.initializeAdapterInstances({ dataService: "OData" });
    var manager = new breeze.EntityManager(baseAddress);
});

Now we can start using Breeze’s querying capabilities against the OData endpoint. Breeze uses LINQ-like operators to specify conditions on the data source. Following snippet shows a basic Breeze request to the EntitySet Customers and captures the response once it gets from the server:
var query = breeze.EntityQuery.from("Customers");
manager.executeQuery(query, function (data) {
    //Manipulate UI
}, function (err) {
    //Show Error Message
});

The above query sends a request to the URL http://localhost:/odata/Customers. Following query applies a simple condition on the above query:
var queryWithCondition = breeze.EntityQuery.from("Customers")
                                           .where("ContactTitle", "equals", "Owner");

This query corresponds to the URL http://localhost:/odata/Customers?$filter=ContactTitle eq 'Owner'. As stated earlier, Breeze is capable of expressing any OData URL. It has operators defined for orderby, checking length of strings, substrings, date operators, querying data as pages, expanding navigation properties and many others. Following listing shows a set of OData URLs and their corresponding Breeze queries.
// http://localhost:<port-no>/odata/Customers?$filter=startswith(ContactName,'Ana') eq true
var queryStartsWith = breeze.EntityQuery.from("Customers")
                                        .where("ContactName", "startsWith", "Ana");

// http://localhost:<port-no>/odata/Customers?$filter= not startswith(ContactName,'Ana') eq true
var Predicate = breeze.Predicate;
var predicate = new Predicate("ContactName", "startsWith", "Ana").not();
var queryNotStartsWith = breeze.EntityQuery.from("Customers")
                                           .where(predicate);

// http://localhost:<port-no>/odata/Customers?$filter=substringof('ill',CompanyName) eq true
var queryContainsSubstring = breeze.EntityQuery.from("Customers")
                                               .where("CompanyName", "contains", "ill");

// http://localhost:<port-no>/odata/Customers?$filter=length(ContactName) gt 10 and length(ContactName) lt 20
var queryCheckingLength = breeze.EntityQuery.from("Customers")
                                                           .where("length(ContactName)", "greaterThan", "10")
                                                            .where("length(ContactName)", "lessThan", "20");

// http://localhost:<port-no>/odata/Customers?$orderby=Country
var queryOrderBy = breeze.EntityQuery.from("Customers")
                                     .orderBy("Country");

// http://localhost:<port-no>/odata/Customers?$top=10
var queryTop10 = breeze.EntityQuery.from("Customers")
                                   .top(10);

// http://localhost:<port-no>/odata/Customers?$skip=40&$top=10
var queryTopAndSkip = breeze.EntityQuery.from("Customers")
                                        .top(10).skip(40);

// http://localhost:<port-no>/odata/Customers?$inlinecount=allpages
var queryInlineCount = breeze.EntityQuery.from("Customers")
                                         .inlineCount(true);

// http://localhost:<port-no>/odata/Customers?$expand=Orders/Employee
var queryExpand = breeze.EntityQuery.from("Customers")
                                    .expand("Orders/Employee");

// http://localhost:<port-no>/odata/Customers?$select=CustomerID,ContactName
var querySelect = breeze.EntityQuery.from("Customers")
                                    .select("CustomerID, ContactName");

This is not the end. I created this list as it will serve as a one stop reference for me and hopefully for you as well! Most of the operators look and behave like LINQ operators. Check API documentation on the official site to get details on each of the operators used above.

Happy coding!