I’m accessing an API which returns some JSON about nutritional information. I’m able to store the response in the model, display it, all that good stuff. I just chuck it into $scope.response = data.item.name
but there is another property which I would like to use to form a new request to the server.
I want to take data.item.ndbno, store it in $scope.querySelection = data.item.ndbno
and use it as a parameter in the new request. I have tried using ng-value={{item.ndbno}}
, and accessing it directly via index in the model alone. Basically for the end resoult, I would like to be able to click on any result in the list, and send a get request with that ndbno to the server. Currently the code sends an undefined
ndbno like so
POST http://api.nal.usda.gov/ndb/reports/?ndbno=undefined&type=b&api_key=DEMO_KEY&format=json&callback=JSON_CALLBACK 400 (Bad Request)
.
I don’t know what I’m doing wrong. I’m sorry if this has an obvious solution to someone who’s seasoned, but I’m a newbie, and I never used jQuery.
Here’s my complete code. And just as a show of gratitude, whomever can help me, I will credit in the credits of the finished app.
<!DOCTYPE html>
<html lang="en" ng-app="sugarApp">
<head>
<meta charset="UTF-8"/>
<title>Sugar App</title>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/angular_material/0.9.4/angular-material.min.css">
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/css/bootstrap.css"/>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js"></script>
</head>
<body ng-controller="loadingController">
<div class="alert alert-info" ng-show="loading">Loading</div> <!-- show/hide based on the truthy or falsey value of $scope.loading-->
<div ng-controller="sugarController">
<form name="searchForm" ng-submit="doSearch()">
<input type="text" ng-model="queryInput" placeholder="Search a food or food product">
<input type="submit" value="Search">
</form>
<ul>
<div ng-show="query">
Results for '{{baseList.q}}'
<li ng-repeat="item in queryResult">
<!-- the problem : ndbno parameter is not being passed, and as a result the request has an undefined value
tried: baseList.ndbno, item.ndbno, $scope.baseList.ndbno, ng-value, bracket syntax [], other things i'm forgetting-->
<a href ng-click="showResults()">{{item.name}}, {{item.ndbno}}</a>
<span ng-model="ndbnum" ng-bind="item.ndbno"></span>>
</div>
</li>
<md-card>
<md-card-content>
The amount of sugar in <strong>{{prodDetail.nutrients[8].measures[3].eqv * .0353}}</strong>oz of <strong>{{prodDetail.name}}</strong> is <strong>{{prodDetail.nutrients[8].measures[3].value}}g</strong>, or <strong>{{prodDetail.nutrients[8].measures[3].value / 7}} circus peanuts</strong>, or <strong>{{prodDetail.nutrients[8].measures[3].value / 4}} teaspoons</strong> of granulated sugar.
<footer>
<small>Source: National Nutrient Database for Standard Reference - Release {{baseReport.sr}}</small>
</footer>
</md-card-content>
</md-card>
</div>
</ul>
<div ng-show="result"> <!-- show/hide based on the truthy or falsey value of $scope.result-->
The amount of sugar in {{baseList.sr}} of {{prodDetail.name}} is {{prodDetail.amount}} or circus peanuts or teaspoons of granulated sugar.
</div>
</div>
<script>
/* TODO
high
clean up code: remove redundancies
figure out how to pass the ndbno result to $scope.querySelection
low
replace deprecated .success with .then
reformat get requests into factory
*/
angular.module('sugarApp',[]).controller('sugarController',['$scope','$http',function($scope,$http){
$scope.doSearch = function(){
$scope.$emit('LOAD'); //using $emit to signal when/vhen not to show the loading indicator
$scope.$emit('UNQUERY'); //using $emit to signal when/when not to show the search results view
$scope.searchUrl = 'http://api.nal.usda.gov/ndb/search/';
$scope.testUrl = 'http://api.nal.usda.gov/ndb/reports/?ndbno=14400&type=f&format=json&api_key=DEMO_KEY';
$scope.api_key = '&api_key=DEMO_KEY';
$scope.fmtJson = '?format=json';
$scope.q = '&q=';
$scope.callback = '&callback=JSON_CALLBACK';
$scope.query = $scope.queryInput;
$scope.fullUrl= $scope.searchUrl + $scope.fmtJson + $scope.q + $scope.query + $scope.api_key + $scope.callback;
$scope.placeholder = "Search for a food or food product";
//temporary comment out $scope.baseReport = {}; //initialize a blank baseReport array
$http.get($scope.fullUrl)
.success(function(data){
//$scope.baseReport=data.report;
$scope.baseList=data.list;
$scope.queryResult=data.list.item;
$scope.ndbnum = data.list.item.ndbno;
$scope.$emit('UNLOAD');
$scope.$emit('QUERY');
$scope.$emit('NORESULT');
})}
$scope.showResults = function(){
$scope.$emit('UNQUERY');
$scope.$emit('LOAD');
$scope.$emit('RESULT');
$scope.resultBaseUrl = 'http://api.nal.usda.gov/ndb/reports/';
$scope.ndb = '?ndbno=';
$scope.querySelection = $scope.ndbnum;
$scope.rtype = '&type=b'
$scope.fmtJson = '&format=json';
$scope.api_key = '&api_key=DEMO_KEY';
$scope.callback = '&callback=JSON_CALLBACK';
//temporary comment out $scope.baseReport = {};
$scope.resultUrl= $scope.resultBaseUrl + $scope.ndb + $scope.querySelection + $scope.rtype
+ $scope.api_key + $scope.fmtJson + $scope.callback;
$http.post($scope.resultUrl)
.success(function(data){
$scope.baseReport=data.report;
$scope.prodDetail=data.report.food;
$scope.$emit('UNLOAD');
})
}
}])
//setting up scope emit flags for use in showing/hiding view elements
//used for showing or hiding results div
.controller('resultController', ['$scope', function($scope){
$scope.$on('RESULT',function(){$scope.result=true});
$scope.$on('NORESULT',function(){$scope.result=false});
}]) //used for showing or hiding query list view div
.controller('queryController', ['$scope', function($scope){
$scope.$on('QUERY',function(){$scope.query=true});
$scope.$on('NOQUERY',function(){$scope.query=false});
}]) // used for showing or hiding the loading indicator div
.controller('loadingController',['$scope',function($scope){
$scope.$on('LOAD',function(){$scope.loading=true});
$scope.$on('UNLOAD',function(){$scope.loading=false});
}])
</script>
</body>
</html>
2
Answers
In your code you used
ndbno
as a property ofitem
but
ndbno
is not a direct property ofdata.list.item
instead it’s a property of a object which is in arrayIf wanna access
ndbno
you have to access via indexlike
Or without an index you could try something like this.
The html:
The angular:
It can get overly complicated to track by
$index
, because each ng-repeat has its own$index
, and those can be nested, so it can be difficult to tell which$index
is being used in a large template.I would recommend just passing the value directly to the controller. However, if you need to know which object it did come from then using
$index
is your next best.Angular will automatically attach a
$index
to theng-repeat
scope, and its not necessary to do atrack by
you can just use$index
, but then it gets confusing which$index
is being used, figuring out a parents$index
can get tricky unless you explicitly set thetrack by
to some other variable name other than$index