chrismarx chrismarx - 1 year ago 68
AngularJS Question

Angularjs - Cleanest way to add promises to scope, now that Angular deprecated auto unwrapping of promises

I really like the clean (and I think easy to follow) way that promises were autounwrapped:

$scope.myData = DataService.query({something:"etc"}); // done;

And I really don't care for what seems to be the standard way of doing it now, without the automatic unwrapping:

DataService.query({something:"etc"}).$promise.then(function (data){
$scope.myData = data;

What I'd like to see is something like this:

$scope.pulseData = $scope.setPromise(CitsciAnalytics.pulse({

But I can't see how to make that happen. The closest I got was:

$scope.pulseData = $scope.setPromise("pulseData", CitsciAnalytics.pulse({

Using a function added to the root scope:

.run(["$rootScope", "$log", function ($rootScope, $log) {
//parent method to avoid promise unwrapping boilerplate
$rootScope.setPromise = function (scopeVar, promise) {
if (arguments.length === 2 && promise && promise.$promise) {
var scope = this;
promise.$promise.then(function (data){
scope[scopeVar] = data;
} else {
$log.error("$rootScope.setPromise has invalid arguments");

but I don't like the unDRY requirement of having to pass the scope variable name as an additional string. Has anyone else tackled this, or see a way to do this more cleanly?

Answer Source

First of all you don't need to use

    $scope.myData = data;

which clearly refers to a $resource, because $resource will return an empty array or object and fill it with data as they arrive.

So, with a $resource class, you can still use

$scope.myData = DetaService.query(...);

$resource's paradigm is also a good approach to follow in your own "data-fetching" services: Return and empty array and fill it with data as they arrive.


.factory('DataService', function ($http) {
    function query(params) {
        var data = [];
        $http.get('/some/url/with/params').then(function (response) {
   (item) {
        return data; 

    return {
        query: query

.controller('someCtrl', function ($scope, DataService) {
    $ = DataService.query({...});

If you have to use thrid-party services that return a promise, you can implement your generic function to offer similar functionality:

.run(function ($rootScope) {
    $rootScope.promiseToArray = function (promise) {
        var arr = [];
        promise.then(function (data) {
            data.forEach(function (item) {
        return arr;

.controller('someCtrl', function ($scope, ThirdPartyService) {
    $ = $scope.promiseToArray(ThirdPartyService.fetchData());

See, also, this short demo.

The above samples are just for illustration purposes and not production-ready code.
I a real-world app, you would need to gracefully handle exceptions, rejections etc.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download