skip to Main Content

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


  1. In your code you used ndbno as a property of item

    $scope.ndbnum = data.list.item.ndbno;
    

    but ndbno is not a direct property of data.list.item instead it’s a property of a object which is in array

    enter image description here

    If wanna access ndbno you have to access via index

    like

    console.log(data.list.item[0].ndbno);
    
    Login or Signup to reply.
  2. Or without an index you could try something like this.

    The html:

        <li ng-repeat="item in queryResult track by $index">
            <a href ng-click="showResults(item.ndbno, $index)">{{item.name}}, {{item.ndbno}}</a>
        </li>
    

    The angular:

    $scope.showResults = function(ndbno, id){
        .
        .
        .
        // with an index
        $scope.ndbnum = queryResult[id].ndbno
        // OR a bit easier without an index
        $scope.ndbnum = ndbno
        .
        .
        .
    }
    

    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 the ng-repeat scope, and its not necessary to do a track 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 the track by to some other variable name other than $index

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search