Link to home
Start Free TrialLog in
Avatar of Leonard Zakoor
Leonard Zakoor

asked on

How do I pass data to my factory properly using ngRoute and ngResource?

I'm new to Angular and still learning. I have an angular ecommerce app I'm building.

I have a category partial and a product partial. I'm using `ng-view` and `$routeProvider` for the navigation.

What I'm unable to figure out is how to pass this `PartNumber` to my product service factory in order to get the details. I'm not sure I setup the factory right.  

Here's my controller:

    var unarcoQS = angular.module('unarcoQS',['ngResource', 'ngCart', 'ngRoute', 'angular.filter']);

    // Factories
    unarcoQS.factory('categoryService', function ($resource) {
      return $resource('http://example.com:7444/api/products/', {});
    });

    unarcoQS.factory('productService', function ($resource) {
      return $resource('http://example.com:7444/api/products/:PartNumber',{PartNumber: "@PartNumber"});
    });

    unarcoQS.config(['$routeProvider', '$locationProvider',
      function($routeProvider, $locationProvider){
        $routeProvider
        .when('/',{
          templateUrl:'template/home.html', 
          controller: "homeCtrl"
        })
        .when('/category/',{
          templateUrl:'template/category.html', 
          controller: "catCtrl"
        })
        .when('/product/:PartNumber', {
          templateUrl: 'template/product.html',
          controller: ['$routeParams', function($routeParams) {
                          var self=this;
                          self.id = $routeParams;
                          return $routeParams;
                      }],
          controllerAs: 'prodCtrl'
        })
        .otherwise({redirectTo:'/'});

        // console.log($routeParams);
        $locationProvider.html5Mode(false);
    }]);

    // Controllers
    unarcoQS.controller ('homeCtrl', ['$scope', 'productService', 'ngCart', '$filter', function($scope, productService, ngCart) {

    }]); //end homeCtrl

    unarcoQS.controller ('catCtrl', ['$scope', 'categoryService', 'ngCart', '$filter', function($scope, categoryService, ngCart) {
      ngCart.setTaxRate(7.5);
      ngCart.setShipping(2.99);

      var queryParams = {};
      categoryService.query(queryParams, {}, function (response) {
        $scope.products = response;
      });

      $scope.filtering = function(filter){
        $scope.catFilter = filter;
        // console.log(filter);
      };
    }]); //end catCtrl


    unarcoQS.controller ('prodCtrl', ['$scope', 'productService', 'ngCart', '$route', '$routeParams', '$resource', function($scope, productService, ngCart, $route, $routeParams, $resource) {
      id = $routeParams.PartNumber
      $scope.product = productService.get({PartNumber: id});

      console.log($scope.product);

    }]); //end prodCtrl

Open in new window


Here's a link to the demo:
http://ur.430designs.com/quick-ship/#/category/

Click on a product to go to the product detail page
Any and all help is appreciated!
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

I have not looked at your code in depth and the link you provided does not seem to show products - however this is the way you would do it
function yourController(productService)
{
  var ctrl = this;
  var partNumber = 3; // Change to set current partNumber
  // Then call service like this
  ctrl.product =  productSevice.get({PartNumber : partNumber});
}

Open in new window

Avatar of Leonard Zakoor
Leonard Zakoor

ASKER

Hi Julian,
I do kind of have that setup already on line 68. I did modify it per your suggestion.

If you go here: https://goo.gl/HT5rTE you can see it's throwing an error. It says:
TypeError: V is not a function

Is something with my service?
I do kind of have that setup already on line 68
Your code only goes up to line 65.
This sample should demonstrate the concept
<html ng-app="app">
<body>
<div class="wrapper" ng-controller="mainCtrl as ctrl">
	<input ng-model="productId" type="text" placeholder="Product ID" />
	<button class="btn btn-sm btn-primary" ng-click="ctrl.getProduct(productId)">Load</button>
	<h2>Product Details</h2>
	<div class="row">
		<label class="col-md-2">{{ctrl.product.ProductName}}</label>
		<div class="col-md-4"><span class="text-right">{{ctrl.product.price}}</span></div>
	</div>
</div>
</body>
</html>

Open in new window

Angular
<script>
(function() {
	'use strict';
	angular.module('app',['ngResource'])
		.factory('productService', productService)
		.controller('mainCtrl', mainController);
	
	function productService($resource) 
	{
		return $resource('t2237.service.php');
	}
	
	function mainController(productService)
	{
		var ctrl = this;
		ctrl.getProduct = function(id) {
			ctrl.product = productService.get({product: id});
		};
	}
})();
</script>

Open in new window


Working sample here
Thanks for that Julian. Maybe I'm over complicating it.  I'm still getting the V is not a function error.

Here's my current code that I was referring to:
unarcoQS.controller ('prodCtrl', ['$scope', 'productService', 'ngCart', '$route', '$routeParams', '$resource', function($scope, productService, ngCart, $route, $routeParams, $resource) {
  var ctrl = this;
  id = $routeParams.PartNumber
  
  console.log(id);

  ctrl.product = productService.get({PartNumber : id});


}]); //end prodCtrl

Open in new window

I have not figured out why yet but your parameter name PartNumber seems to be the culprit. Try changing factory to
unarcoQS.factory('productService', function ($resource) {
	return $resource('http://qsapi.unarcorack.com:7444/api/products/:PartNumber',{PartNumber: "@_PartNumber"});
});

Open in new window

And your invoke to
$scope.product = productService.query({_PartNumber: id});

Open in new window


This should get rid of the V is not a function bit but you still have a problem that a Resource GET expects a single object return and the GET in this case is returning an array - take a look at the results of this query
http://qsapi.unarcorack.com:7444/api/products/PP-CN101-UNARCOYELLOW

Open in new window

You will see it is an array of objects not a single object.
Thanks for that Julian. So is my factory wrong or my service? I didn't write the service so honestly I'm not sure why it's not doing that.

If I'm getting an array back, is there another way to show those results?
Yes you can do a query instead of a get - the query expects an array rather than a single record.

$scope.product = productService.query({_PartNumber: id});

Open in new window


You will then also need to change your view (or controller) to either display all the records returned or (in the controller) select which one is relevant to show in the view
Hey Julian!

Thanks for that. Unfortunately I'm not getting that specific array back. Take a look here and look at the console. I'm doing
unarcoQS.controller ('prodCtrl', ['$scope', 'productService', 'ngCart', '$route', '$routeParams', '$resource', function($scope, productService, ngCart, $route, $routeParams, $resource) {
  var ctrl = this;
  id = $routeParams.PartNumber

  $scope.product = productService.query({_PartNumber: id});
  console.log($scope.product);
}]); //end prodCtrl

Open in new window



But in my console, I'm receiving about 160 records back. Is there something wrong with my controller?

I'm still new to Angular, but I do appreciate your time.
That's what I'm seeing when I hit the API directly.

When I use my angular factory, I'm getting over 150 results. This is my first time using Angular services/factories, so I'm wondering if there's something wrong with how I've done my factory.
Please post your factory code and your controller code together. Since you made the change to _PartNumber you only posted the controller code.

The factory is simple - it just returns a Resource.
The resource takes a URL as a parameters that optionally specifies parameters to add to the URL - you use this if the URL requires a specific format for example
my.site.com/subfolder/:ID

You can submit parameters as part of the get / query that you don't specify in the URL component - these just get sent as GET or POST parameters and can be accessed as such on the other side.

In this case the API expects the PART NUMBER to be part of the URL - so in your factory you need to tell Resource how to create that url with the _Part_Number - if you don't get that part right the URL will not include the Part Number - but it will still work and the
.query({_PartNumber: 1}) will just submit the part number data as a GET request.
Sorry about that.  Here's my entire controller.js file :
var unarcoQS = angular.module('unarcoQS',['ngResource', 'ngCart', 'ngRoute', 'angular.filter', 'ngPageTitle']);

// Factories
unarcoQS.factory('categoryService', function ($resource) {
  return $resource('http://qsapi.unarcorack.com:7444/api/products/', {});
});

unarcoQS.factory('productService', function ($resource) {
  return $resource('http://qsapi.unarcorack.com:7444/api/products/:PartNumber',{PartNumber: "@_PartNumber"});
});

unarcoQS.config(['$routeProvider', '$locationProvider',
  function($routeProvider, $locationProvider){
    $routeProvider
    .when('/',{
      data: {
        pageTitle: "Unarco Rack Quick Ship - Home"
      },
      templateUrl:'template/home.html', 
      controller: "homeCtrl"
    })
    .when('/category/',{
      data: {
        pageTitle: "Unarco Rack Quick Ship - Category"
      },
      templateUrl:'template/category.html', 
      controller: "catCtrl"
    })
    .when('/product/:PartNumber', {
      data: {
        pageTitle: "Unarco Rack Quick Ship - Product"
      },
      templateUrl: 'template/product.html',
      controller: ['$routeParams', function($routeParams) {
                      var self=this;
                      self.id = $routeParams;
                      return $routeParams;
                  }],
      controllerAs: 'prodCtrl'
    })
    .otherwise({redirectTo:'/'});

    // console.log($routeParams);
    $locationProvider.html5Mode(false);
}]);

// Controllers
unarcoQS.controller ('homeCtrl', ['$scope', 'productService', 'ngCart', '$filter', function($scope, productService, ngCart) {

}]); //end homeCtrl

unarcoQS.controller ('catCtrl', ['$scope', 'categoryService', 'ngCart', '$filter', function($scope, categoryService, ngCart) {
  ngCart.setTaxRate(7.5);
  ngCart.setShipping(2.99);

  var queryParams = {};
  categoryService.query(queryParams, {}, function (response) {
    $scope.products = response;
  });

  $scope.filtering = function(filter){
    $scope.catFilter = filter;
    // console.log(filter);
  };
}]); //end catCtrl


unarcoQS.controller ('prodCtrl', ['$scope', 'productService', 'ngCart', '$route', '$routeParams', '$resource', function($scope, productService, ngCart, $route, $routeParams, $resource) {
  var ctrl = this;
  id = $routeParams.PartNumber

  $scope.products = productService.query({_PartNumber: id}, function(product){
    $scope.product = product;
    console.log(product);
  }); 

}]); //end prodCtrl

Open in new window

Can you look in your console for this URL
http://qsapi.unarcorack.com:7444/api/products/PP-CN101-UNARCOYELLOW

It should be a GET - expand it, click the Response tab and paste a screen shot of that.
Not quite what I was after - you need to click the actual request in the left window (bottom) so it shows the response detail on the right
User generated image
Oh, I see what you were looking for. Sorry.

So I'm receiving the the correct response. Why isn't this what's being shown in my controller?
Hey Julian,
One thing I noticed now is in the call it has a query string rather than a flat URL.

I need a call like this:
http://qsapi.unarcorack.com:7444/api/products/PP-CN101-UNARCOYELLOW

I'm getting this in the response:
http://qsapi.unarcorack.com:7444/api/products?_PartNumber=PP-CN101-UNARCOYELLOW
ASKER CERTIFIED SOLUTION
Avatar of Julian Hansen
Julian Hansen
Flag of South Africa image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
That was it! I had NO clue that ng resource and angular both had to be the same version. Thanks so much!!!
You are welcome.