3

I have a json file where i am stocking informations from all the people in my database. I actually use it to display first name, last name in a web page and i want to add the possibility to display the details of every person.

To do so i'm using the id of the person like this :

.when('/people/:id', {templateUrl: 'partials/people-detail.html'})

It works pretty well, i have a page generated for every person, which is nice. But now I would like to get the information of the person back.

The easiest way would have been to have a json file for every person, but i don't particularly like the idea of having so much file. So my actual idea is to iterate through the people.json file to find the good one and using it but it's not working.

Here's my controller :

var PeopleController = angular.module ('PeopleController', []);

PeopleController.controller('PeopleDetailCtrl', ['$scope', '$routeParams', '$http',
    function($scope, $routeParams, $http) {
        $scope.search = function() {
            var url = 'data/people.json';
            $http.get(url).success(httpSuccess).error(function() {
                alert('Unable to get back informations :( ');
            });
        }
        httpSuccess = function(response) {
            $scope.persons = response;
        }

        function getById(arr, id) {
            for (var d = 0, len = arr.length; d < len; d += 1) {
                if (arr[d].id === id) {
                    return arr[d];  
                }
            }
        }
        $scope.search();
        $scope.person = getById($scope.persons,$routeParams.id);
    }]);

Well, maybe my solution is bad since it doesn't work, but i didn't find another way to do so.

Now i'm all yours :)

Thanks for reading.

3 Answers 3

4

The problem is that your $scope.search method contains $http.get() which is asynchronous.

What that means is your next line (the one that sets $scope.person) executes before the json file has been read. As such, $scope.persons is empty at the time it is executed.

You can take advantage of the fact that $http.get() returns a chainable promise here.

So if you change your search() function to return that promise, you can then use then() to populate person when everything has been successful:

$scope.search = function() {
  var url = 'data/people.json';

  return $http.get(url).success(httpSuccess).error(function() {
    alert('Unable to get back informations :( ');
  });

}

(note the return statement).

Then change the person population to take advantage of this:

$scope.search().then(function(){
  $scope.person = getById($scope.persons,$routeParams.id);
});
Sign up to request clarification or add additional context in comments.

6 Comments

Thanks for your help, it works ! I don't know if it's the best solution (if i have to iterate 1000 times each time it's not really cool^^) but it still works. Well, i don't really understand the utility of the then() method. The only difference is that it waits for the promise. Even if you are not sure the success() will returns the promise, in this case you will have the error() method to manage this problem, right ?
If it works, then success returns a promise, yes. You should read up on promises if you want to understand more. It's a javascript principle which is well documented. Regarding your solution for getting by ID: the better option is to store your information in a database and not a json file, then to query that database directly by exposing an API on your server.
I will search for that, thank you. Using a database and a server was my first idea but the application is also supposed to work offline (mobile app with cordova) so i choose to stock everything locally and add the possibility to update the files by asking to the server.
For relatively small numbers, the iterations shouldn't be too much of a problem. I imagine cordova gives access to device databases though - might be worth looking into if the performance becomes an issue
It's still working. Solved my problem! But, just to check. Is there a better way to do it? It's been a long time since your answer. And since i'm starting learning angular now, is there a better way to get the element by it's id?
|
0

I hope getting a person is a whole different event like on click. You can try grep:

$scope.person = function(_id) {
    return $.grep($scope.persons, function(item){
       return item.id == _id
    })[0];
}

Assuming you have all persons available otherwise this logic has to move inside the part of the success callback for the http call.

1 Comment

Thanks for your help but i'm not using any jquery.
0

I used ECMAScript 5 filter to get person by id and moved your search by id to success method since we are dealing with ajax call.

Example:

app.controller('PeopleDetailCtrl', ['$scope', '$routeParams', '$http',
    function($scope, $routeParams, $http) {
        $scope.search = function() {
            var url = 'data.json';
            $http.get(url).success(httpSuccess).error(function() {
                alert('Unable to get back informations :( ');
            });
        }
        httpSuccess = function(response) {
            $scope.persons = angular.fromJson(response);

            $scope.person = $scope.persons.filter(function(item){
             return item.id==routeParams.id //check for undefined; 
            });
        }


        $scope.search();

    }]);

Live Example: http://plnkr.co/edit/jPT6aC5UqLdHGJ1Clfkg?p=preview

2 Comments

I would argue it's better to keep the search by id separate, and return the promise, as with my answer. This makes it easy to use the same data retrieval function to perform other operations, or better, to migrate the data retrieval to a service.
filter creates an array.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.