Breeze.JS to use angular.js http

2k Views Asked by At

I am trying to make Breeze.JS to make use of angular's http service for ajax calls. I followed the the docs (http://www.breezejs.com/documentation/customizing-ajax) and applied it. However it doesn't work.

Further more when I checked breeze source code I saw the following:

fn.executeQuery = function (mappingContext) {

    var deferred = Q.defer();
    var url = mappingContext.getUrl();

    OData.read({
            requestUri: url,
            headers: { "DataServiceVersion": "2.0" }
        },
        function (data, response) {
            var inlineCount;
            if (data.__count) {
                // OData can return data.__count as a string
                inlineCount = parseInt(data.__count, 10);
            }
            return deferred.resolve({ results: data.results, inlineCount: inlineCount });
        },
        function (error) {
            return deferred.reject(createError(error, url));
        }
    );
    return deferred.promise;
};

It simply calls OData.read without doing anything about http service. Thus OData makes use of builtin ajax. I don't understand with above code, how it is possible to customize ajax of Breeeze.JS

2

There are 2 best solutions below

10
Ward On BEST ANSWER

The problem is that the Breeze OData path does NOT use the Breeze Ajax adapter. Changing the Breeze Ajax Adapter (as the "Breeze Angular Service" does) won't help.

At the moment, both the "OData" and "webApiOData" DataService Adapters delegate to the 3rd party datajs library for AJAX services (and for other OData-related support).

You could replace its odata.defaultHttpClient with a version of your own based on $http. That's not a trivial task. Look here for the source code; it's roughly 160 lines.

I suppose we could write one. It hasn't been a priority.

Until somebody does it or we abandon datajs (not soon if ever), you're stuck with the datajs ajax.

Sorry about that.

p.s. Just about everyone who talks to OData data sources uses the datajs library. Maybe you can talk to the authors of that library and try to get them to support$http.

0
Michael Bromley On

Quick and dirty hack to simulate $http service

I ran into this issue today. Since the external datajs AJAX methods are used rather than Angular's $http service (as explained by Ward), Breeze queries do not trigger a digest and the models do not get updated.

As with any external-to-angular changes, the simple solution is to wrap any assignments from your queries in a $scope.$apply() function. However, this will quickly clutter up your app so it's a bad idea.

I came up with a quick and dirty hack that so far seems to work well:

  1. I have a dataContextservice which encapsulates all my Breeze queries and exposes methods like getCustomers(), getProducts() etc (inspired by the example on the Breeze site).
  2. When any of these data-access methods completes (ie the promise resolves), I call a triggerAngularDigest() method.
  3. This method simple calls $rootScope.$apply() inside a $timeout().
  4. The $timeout() causes Angular to run the digest on the next tick, i.e. after the data from your Breeze query has been assigned to your models.
  5. All your models update just like when you use $http, no need to call $apply() in your controllers.

Simplified version:

function dataContext($rootScope, $timeout, breeze) {

    // config of entity manager etc snipped

    return {
        getCustomers: function () {
            return breeze.EntityQuery.from('Customers')
                .using(manager)
                .execute()
                .then(function(data) {
                    triggerAngularDigest(); // <-- this is the key
                    return data;
                });
        }
    };

    function triggerAngularDigest() {
        $timeout(function() {
            $rootScope.$apply();
        }, 0);
    }
}

myApp.factory('dataContext', dataContext);

Then:

// some controller in your app
dataContext.getCustomers().then(function(data) {
    scope.customers = data;
});