2

I am fetching the details from an API using Angular Service and I want to return only the matching items. Meaning, after I type some text, I will click a button, which will call a function in a Controller which will call the Service to get the details.

Now my problem, is that it returns the entire list not the filtered list, I have stored filter result into an array I want to return that array(foundItems).

This is my code

(function() {
angular.module('NarrowItDownApp',[])
.constant('url',"https://davids-restaurant.herokuapp.com/menu_items.json")
.controller('NarrowItDownController',['$scope','MenuSearchService',function($scope,MenuSearchService) {
    var items=this;
    items.searchitem="";
    items.getitems=function() {
        MenuSearchService.getMatchedMenuItems(items.searchitem).then(function(response) {
            this.found=response.data;
            console.log(this.found);
        })
        .catch(function(response) {
            this.found=response.data;
            console.log(this.found);
        });
    };
}])
.service('MenuSearchService',['$http','url',function($http,url) {
    var service=this;
    service.getMatchedMenuItems=function(searchitem)
    {
        var foundItems=[];
        var key;
        return $http.get(url).success(function(data) {
            for(var i=0;i<data.menu_items.length;i++)
            {
                var temp=data.menu_items[i];
                //Old method
                /*for(key in temp)
                {
                    if(temp.hasOwnProperty(key))
                    {
                        console.log(temp[key])
                    }
                }*/
                Object.keys(temp).forEach(function(items)
                {
                    if(searchitem==temp[items])
                    {
                        foundItems.push(temp);
                    }
                });
            };
            console.log(foundItems);
            return foundItems;
        })
        .error(function(data) {
            console.log('error');
            return data;
        });
        return foundItems;
    };
}]);
})();
georgeawg
  • 48,608
  • 13
  • 72
  • 95
Kannan T
  • 1,639
  • 5
  • 18
  • 29
  • 2
    Not an answer per se, but if it were me, I would download whole json and expose it in the controller. From then on the search can be done using a simple filter in the html. Think that leaves a better user experience as it only requires a single async http request. – cYrixmorten Apr 04 '17 at 15:57
  • See [Why are angular $http success/error methods deprecated? Removed from v1.6?](http://stackoverflow.com/a/35331339/5535245). The `.success` and `.error` methods **ignore** return values. – georgeawg Apr 04 '17 at 16:36

2 Answers2

3

Now my problem, is that it returns the entire list not the filtered list, I have stored filter result into an array I want to return that array(foundItems).

The reason that the service returns the entire list is that the .success and .error methods ignore return values. Use .then and .catch instead.

service.getMatchedMenuItems=function(searchitem)
{
    var foundItems=[];
    var key;
    //return $http.get(url).success(function(data) {
    //USE .then method
    return $http.get(url).then(function(response) {
        var data = response.data;
        for(var i=0;i<data.menu_items.length;i++)
        {
            var temp=data.menu_items[i];
            Object.keys(temp).forEach(function(items)
            {
                if(searchitem==temp[items])
                {
                    foundItems.push(temp);
                }
            });
        };
        console.log(foundItems);
        return foundItems;
    })
    //.error(function(data) {
    //USE .catch method
    .catch(function(errorResponse) {
        console.log(errorResponse.status);
        //return data;
        //THROW to chain rejection
        throw errorResponse;
    });
    //return foundItems;
};

Also it is important to use a throw statement in the rejection handler. Otherwise the rejected promise will be converted to a successful promise.

For more information, see Angular execution order with $q.

Community
  • 1
  • 1
georgeawg
  • 48,608
  • 13
  • 72
  • 95
  • It works perfectly bro i have a query now as i have already checked for errors in service do i need to check it again in controller i mean am asking about then(promise). Is it necessary? – Kannan T Apr 04 '17 at 17:23
  • 1
    No you don't need to `.catch` the errors in the controller because they are `.caught` and logged in the service. However it is important to re-throw the error so that it doesn't get **converted** to a success. – georgeawg Apr 04 '17 at 17:31
-1

You can use promise for that Promise

(function() {
angular.module('NarrowItDownApp', [])
.constant('url', "https://davids-restaurant.herokuapp.com/menu_items.json")
.controller('NarrowItDownController', ['$scope', 'MenuSearchService', function($scope, MenuSearchService) {
    var items = this;
    items.searchitem = "";
    items.getitems = function() {
        MenuSearchService.getMatchedMenuItems(items.searchitem).then(function(data) {
                for (var i = 0; i < data.menu_items.length; i++) {
                    var temp = data.menu_items[i];
                    //Old method
                    /*for(key in temp)
                    {
                        if(temp.hasOwnProperty(key))
                        {
                            console.log(temp[key])
                        }
                    }*/
                    Object.keys(temp).forEach(function(items) {
                        if (searchitem == temp[items]) {
                            foundItems.push(temp);
                        }
                    });
                };

                this.found = foundItems);
                console.log(this.found);
            })
            .catch(function(response) {
                this.found = response.data;
                console.log(this.found);
            });
    };
}])
 .service('MenuSearchService', ['$http', 'url', function($http, url) {
    var service = this;
    service.getMatchedMenuItems = function(searchitem) {
        var foundItems = [];
        var key;
        return $http.get(url);            
    };
}]);
 })();
Amit Malik
  • 184
  • 8
  • 1
    See [Why are angular $http success/error methods deprecated? Removed from v1.6?](http://stackoverflow.com/a/35331339/5535245). – georgeawg Apr 04 '17 at 16:35
  • thanks @georgeawg for the update. Updated the code for the same. – Amit Malik Apr 04 '17 at 16:45
  • 1
    There is no need to manufacture a promise with `$q.defer` as the `$http` service already returns a promise. See [Is this a “Deferred Antipattern”?](http://stackoverflow.com/questions/30750207/is-this-a-deferred-antipattern). In addition the promise will hang with errors because that is not handled properly. – georgeawg Apr 04 '17 at 16:45
  • 1
    yeah he should be doing the filtering in controller itself so that he dont have to worry about the result which is coming async. As in controller the two way data binding will update the view when filtered result comes up. – Amit Malik Apr 04 '17 at 16:48
  • 1
    @AmitMalik Dude if i remove return from return $http.get(url) then an error pops up it says MenuSearchService.getMatchedMenuItems(items.searchitem).then(function(response) is not a function – Kannan T Apr 04 '17 at 16:57
  • @georgeawg So if we check promises in factory as well as controller it becomes anti pattern? that is what i read in that answer bro. – Kannan T Apr 04 '17 at 17:00
  • @AmitMalik Yes it will be easy to filter in controller but requirements is to filter in the service itself – Kannan T Apr 04 '17 at 17:01
  • @kannucodert14 The anti-pattern was using `$q.defer` when $http returns a promise. He subsequently edited it from his answer. – georgeawg Apr 04 '17 at 17:04
  • yup updated my answer after @georgeawg comments. I hope answer is good now. – Amit Malik Apr 04 '17 at 17:06
  • @AmitMalik and georgeawg Bro's i know by sending the full list into controller and filtering it what i want is i want to perform filter in service itself so that i can access from different controllers too any lead for that? – Kannan T Apr 04 '17 at 17:12
  • you can use transformresponse provide by $http – Amit Malik Apr 04 '17 at 17:21