AngularJS : How use $http in a filter

Or you could use a stateful filter:

    angular.module("app").filter('companyName', function($http) {
        var cached = {};
        var apiUrl = 'http://my.service.com';
        function companyNameFilter(company_id) {
            if (company_id) {
                if (company_id in cached) {
                    // avoid returning a promise!
                    return typeof cached[company_id].then !== 'function' ?
                        cached[company_id] : undefined;
                } else {
                    cached[company_id] = $http({
                        method: 'GET',
                        url: apiUrl + company_id
                    }).success(function (companyName) {
                            cached[company_id] = companyName;
                        });
                }
            }
        }
        companyNameFilter.$stateful = true;
        return companyNameFilter;
})

and use it like so: {{company_id | companyName}}

Beware: The function companyNameFilter will be called on each digest cycle.

Also, you would need to figure out a way to reset the cache if it grows too big.

See: https://glebbahmutov.com/blog/async-angular-filter/

And the plunker (the link above won't display it, so here's a direct link): http://plnkr.co/edit/EK2TYI1NZevojOFDpaOG?p=preview


I think you should not use filters that way. Filters are for transforming inputs based on optional params.

The problem here would be that you're immediately returning a promise from the filter function. And that's nothing Angular can deal with as a result from a filter.

My suggestion therefore would be this - fetch the result first, work with the filter based on the result:

var app = angular.module("my.module");

app.controller("MyCtrl", ['$http', '$scope', function(http, scope) {
  scope.hello = "foo";
  http.get('http://my.service.com').then(function(data) {
    scope.filterParams = data;
  }, function(err) {
    scope.filterParams = undefined;
  });
}]);

app.filter("filterHello", function() {
  return function(input, params) {
    if(typeof params === "undefined") {
      return "";
    }
    //work with the params here
  };
});

and in the Template:

<div ng-controller="MyCtrl">
  {{hello|filterHello:filterParams}}
</div>

Edit: Just read your explanation. To me, this would be a candidate for a directive:

app.directive("companyName", ['$http', function(http) {
  return {
    template: "<span>{{name}}</span>",
    scope: {
      companyId: "="
    },
    link: function(scope) {
      http.get("http://my.service.com/companies/" + scope.id).then(function(result) {
        scope.name = result.name;
      }, function(err) {
        scope.name = "unknown";
      });
    }
  }
}]);

and in the template:

<span company-name company-id="user.company_id"></span>

If you have a lot of companies, you should preload the names (maybe send them with the first response initially?), as you'd be bombarding your server quite a bit with requests.

Tags:

Angularjs