0

I'm trying to get a specific product by its id from a JSON file with products. I have some kind of problem as this question AngularJS : get back data from a json array with an id the code is similar. I read through that question and the accepted answer there, still can't figured this out. From what I understand the $scope.search() returns a promise which after success triggers the .then() to set get the correct person.

This line of code prints out the products array and also getting the product id from the url. However it prints out twice in the console.

console.log($scope.products + $routeParams.productId);

app.js

var app = angular.module('gtbApp', [
    'ngRoute',
    'productControllers'
]);

// Setting up the routes with right controllers and partials
app.config(['$routeProvider', function($routeProvider){
    $routeProvider
        .when('/main', {
            templateUrl: 'partials/product-grid.html',
            controller: 'ProductController'
        })
        .when('/product/:productId', {
            templateUrl: 'partials/product-detail.html',
            controller: 'ProductDetailCtrl'
        })
        .otherwise({
            redirectTo: '/main'
        });

}]);

controllers.js

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

// For product-grid.html
app.controller('ProductController', ['$http', function($http){
    var store = this;
    store.products = [];    
    $http.get('products.json').success(function(data){
        store.products = data;
    });

}]);

// For product-detail.html
app.controller('ProductDetailCtrl', ['$scope', '$routeParams', '$http', function($scope, $routeParams, $http){

$scope.search = function() {
    var url = 'products.json';
    // Return a promise object
    return $http.get(url).success(httpSuccess).error(function(){
        console.log('Unable to retrieve info form JSON file.');
    });
}

httpSuccess = function(response) {
    $scope.products = response;
}

function getById(arr, id) {
    for (var i = 0, len = arr.length; i < len; i++) {
        if (arr[i].id === id) {
            return arr[i];  
        }
    }
}

$scope.search().then(function(){
    // Prints out the products array and id twice
    console.log($scope.products + $routeParams.productId);
    $scope.product = getById($scope.products, $routeParams.productId);
    // Prints out twice "undefined"
    console.log($scope.product); 
});

}]);

The main question is how to get specific product based on id why in "ProductDetailCtrl"

$scope.product = getById($scope.products, $routeParams.productId); 

doesn't work.

Thanks in advance!

Update: Found out why $scope.product is undefined, it is just because the $routeParams.productId is a string, and in getById() need a integer in second args. However I don't know why console.log($scope.product); prints out twice.

2
  • 2
    Perhaps $scope.search() is called twice, and maybe the controller is used twice in your html code. Commented Oct 21, 2014 at 12:37
  • Update the question with more details. I'm only using $scope.search() and ng-view in my index.html file with 2 partials. Not sure if it has something to do with my controllers.js file. Commented Oct 21, 2014 at 14:00

2 Answers 2

2

I don't really understand what your main question is here. But anyways. When you use the $http service it will return a promise, which you eventually will have to unwrap. What you are doing in your code is that you are unwrapping it twice. Which is fine.

With $http response you can either use 'success'/'error' or just 'then' which can take a success and an error callback. Which means you could either unwrap in the search function or after you call the search function.

$scope.search = function() {
    var url = 'products.json';
    $http.get(url)
         .success(function(data){
             $scope.product = getById($scope.products, $routeParams.productId);
         })
         .error(function() {
            console.log('Unable to retrieve info form JSON file.');
         });
}

You could also do something like:

$scope.search = function() {
    var url = 'products.json';
    return $http.get(url);
}

$scope.search().then(function(data) {
    $scope.product = getById(data, $routeParams.productId);
}, errorCallback);

And the below would achieve the same result

$scope.search = function() {
    var url = 'products.json';
    return $http.get(url);
}

$scope.search()
      .success(function(data) {
          $scope.product = getById(data, $routeParams.productId);
      })
      .error(errorCallback);

or reference the promise:

$scope.search = function() {
    var url = 'products.json';
    return $http.get(url);
}

var dataPromise = $scope.search();

dataPromise.then(function(data) {
    $scope.product = getById(data, $routeParams.productId);
}, errorCallback);

What you need to know is that as long as you're returning something within a success/error/then function it will return a promise which you will have to unwrap in order to get the data.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the answers, anyone of them will work. Updated the question. The problem was the sneaky $routeParams.productId which is a string, I thought it was a integer. Hard to see in the console. However I don't know why console.log($scope.product); prints out twice.
0

You should be either using the .success() and .error() on the $http-promise or only then .then()

Do it like this:

app.controller('ProductController', ['$scope', '$routeParams', '$http', function($scope, $routeParams, $http){

    $scope.search = function() {
        var url = 'products.json';
        // Return a promise object
        return $http.get(url);
    }

    .....

    $scope.search()
        .success(function(data){      // --> data is the products.json
            ... // handle the successfull call
        } );
        .error(function(...) {
            ... // handle the error
        } );

     // or: 

     $scope.search().then(
        function(data){      // --> data is the products.json
            ... // handle the successfull call
        }, 
        function(...) {
            ... // handle the error
        });      

}]);

2 Comments

That's wrong. As long as you are returning the promise you can use as many .then as you want.
True that, I actually meant that he "should" probably be using just one of both approaches. I'll fix that

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.