Ralph Krimmel
Ralph Krimmel

Reputation: 13

Problems with angular js updating scope after getting async data from service

I like to implement a search against a http resource in angular js. Evertything is fine as long as I search from any other page than the result page. If i search at the result page again I get the result Objects but the scope would not update. You can find an example of this behaviour here: Example page.

Steps to reproduce:

  1. Enter "pax6" into the search field in the menu bar. Recognize you get forwarded to the result page.
  2. Staying on the search page, enter pax8 into the search field. You will receive the objects but the scope won't update.
  3. Click on any other link than search
  4. Click on search again, now the view shows the correct values

Here is how I implemented the feature:

angular.module('gp3').controller('SearchController',function($scope,$location,SearchService,$http) {
    $scope.keyword="";
    $scope.options={};
    $scope.results = SearchService.getResults();
    $scope.search = function() {
               SearchService.search($scope.keyword,$scope.options).then(function(data) {
                                $scope.results = data;
                                console.log(data);
                                $location.path('/search');
                        },function(reason) {
                                $scope.results = [];
                                $location.path('/search');
                        });
                };})

    .factory('SearchService',function($http,$q) {
        var SearchService = {};
        var results = [];

        SearchService.getResults = function() {
                return SearchService.results;
        };

        SearchService.search = function(keyword,options,callback) {
                        var def = $q.defer();
                        $http.get("/api/search/" + keyword,options)
                                 .success(function(data,status,headers,response){
                                        SearchService.results = data;
                                        def.resolve(data);
                                })
                                .error(function(status,headers,response){
                                        def.reject("Failed to search");
                                })
                        return def.promise;

                };
        return SearchService;})

I looked arround here at stackoverflow alot but I only can find solutions where the async (search) function is called when the controller loads and not with click on a button. If I missed any Information or the question is not well formatted please tell me, this is my first question I am asking. Thank you.

Upvotes: 1

Views: 248

Answers (1)

Tiago Roldão
Tiago Roldão

Reputation: 10649

A Controller in angularJS is by design a contained structure - it isn't a singleton. You have defined two separate instances of SearchController, one in the menu and the other in the results page.

The reason why it works in the first search is because you update SearchService's data and then move to the results view (which updates itself loading the service data on load)

You can see here that you have two distinct scopes, with two distinct search result arrays. The search controller in the menu bar:

SearchController in the menu bar

And the search controller in the main page:

enter image description here

A solution would be to use the service as the "owner" of the search results, and access those from the controllers. This would mean something like exposing SearchService to the $scope, and using in in your view, for instance:

.controller('SearchController',function($scope,$location,SearchService,$http) {
    $scope.keyword="";
    $scope.options={};
    $scope.group;
    $scope.SearchService = SearchService;

And in your template, doing

<div ng-repeat="result in SearchService.getResults()"></div>

Upvotes: 1

Related Questions