1
votes

I am using JS Knockout for displaying Search results from the Four Square API. I have this View Model in my Javascript code

var ViewModel = function(){  

    var self = this;
    // Foursquare API Call :  

    this.foursquareURL = 'https://api.foursquare.com/v2/venues/search?ll=37.8,-122.4&query=croissant&client_id=CLIENT_ID&client_secret=CLIENT_SECRET';

     this.fs_ApiCall = function()
     {

    $.getJSON(foursquareURL, function(data){

     $foursquareElem.text('Get a croissant');

    var venues = data.response.venues;
        self.venueList = ko.observableArray([]);

        for (var i=0; i<venues.length; i++){
        self.venueList.push ({

                name: venues[i].name,
                lat: venues[i].location.lat,
                lng: venues[i].location.lng

        });   

        }
        }).error(function() {
    $foursquareElem.text( "No data available" );
    });
    };

    };

    ko.applyBindings(new ViewModel());

This is how I apply the binding in the HTML doc

<div id="foursquare-venues"> 
<ul data-bind= "foreach:venueList">
<li id="li-name" data-bind = "text:name">

</li>

</ul>  

Uncaught ReferenceError: Unable to process binding "foreach: function (){return venueList }" Message: venueList is not defined

I was not sure if I did use the right way to push the API response in an API , but the error message seems to say that the array isn’t even defined (?) I am not sure what is going wrong here.

2

2 Answers

0
votes

That is because you instanciate venueList in the getJSON callback, which is invoked after bindings are applied.

You should instead do:

  var ViewModel = function() {

    var self = this;
    self.venueList = ko.observableArray([]); // instanciate here

    // Foursquare API Call :  
    this.foursquareURL = 'https://api.foursquare.com/v2/venues/search?ll=37.8,-122.4&query=croissant&client_id=CLIENT_ID&client_secret=CLIENT_SECRET';

    this.fs_ApiCall = function() {

        $.getJSON(foursquareURL, function(data) {
            // you might want to clear venueList here

            $foursquareElem.text('Get a croissant');

            var venues = data.response.venues;

            for (var i = 0; i < venues.length; i++) {
                self.venueList.push({

                    name: venues[i].name,
                    lat: venues[i].location.lat,
                    lng: venues[i].location.lng

                });

            }
        }).error(function() {
            // and here
            $foursquareElem.text("No data available");
        });
    };

};

ko.applyBindings(new ViewModel());
0
votes

Instantiate the observableArray, venueList initially, so that it can be accessible in the html. Giving code below for the js.

var ViewModel = function() {

var self = this;
self.venueList = ko.observableArray([]); 

this.foursquareURL = 'https://api.foursquare.com/v2/venues/search?ll=37.8,-122.4&query=croissant&client_id=CLIENT_ID&client_secret=CLIENT_SECRET';

this.fs_ApiCall = function() 
{

    $.getJSON(foursquareURL, function(data) {
        // you might want to clear venueList here

        $foursquareElem.text('Get a croissant');

        var venues = data.response.venues;

        for (var i = 0; i < venues.length; i++) {
            self.venueList.push({

                name: venues[i].name,
                lat: venues[i].location.lat,
                lng: venues[i].location.lng

            });

        }
    }).error(function() {
        // and here
        $foursquareElem.text("No data available");
    });
   };
};

ko.applyBindings(new ViewModel());

Also in the HTML make the change for the text binding as below:-

<div id="foursquare-venues"> 
    <ul data-bind= "foreach:venueList">
        <li id="li-name" data-bind = "text: $data.name"> //Use $data.name instead of using just name.
        </li>
    </ul>  
</div>

Use text : $data.name instead of using text : name. Refer foreach binding for more knowledge.