title: Unable to process binding - bind is not a function
body: <p>I am using knockoutjs for my single page application, and I am currently stuck on a mysterious problem.</p>
  
  <p>I am trying to display a dropdown menu, and populate it using knockout bindings. For this purpose, I am using a foreach that iterates over all elements:</p>
  
  <pre><code>&lt;div data-bind="foreach: favPlaces" class="dropdown-menu" aria-labelledby="dropdownMenuButton"&gt;
       &lt;a data-bind="text: name, click: $parent.openInfoWindow" class="dropdown-item"&gt;Place Name&lt;/a&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>Then, in my viewModel, I have the openInfoWindow function (which is supposed to be called when a dropdown-item is clicked):</p>
  
  <pre><code>// View Model
  var TokyoViewModel = function() {
      var self = this;
  
      // All the favorite places
      this.favPlaces = ko.observableArray([]);
      mFavPlaces.forEach(function(place) {
          self.favPlaces.push(new FavPlace(place));
      });
  
      this.openInfoWindow = function(favPlace) {
          console.log("Success!");
      }
  
  }
  </code></pre>
  
  <p>The problem is, when I add the click: openInfoWindow binding to the dropdown-item element, I get the following error:</p>
  
  <pre><code>Uncaught TypeError: Unable to process binding "foreach: function (){return favPlaces }"
  Message: Unable to process binding "click: function (){return $parent.openInfoWindow }"
  Message: u(...).bind is not a function
      at Object.p (knockout-3.4.1.js:17)
      at knockout-3.4.1.js:89
      at Object.b (knockout-3.4.1.js:9)
      at init (knockout-3.4.1.js:89)
      at init (knockout-3.4.1.js:103)
      at knockout-3.4.1.js:72
      at Object.w (knockout-3.4.1.js:39)
      at knockout-3.4.1.js:72
      at Object.q (knockout-3.4.1.js:11)
      at m (knockout-3.4.1.js:71)
  </code></pre>
  
  <p>The text: name binding works perfectly on its own.</p>
  
  <p>Where did I commit a mistake?</p>
  
  <p>EDIT:</p>
  
  <p>Here is more details about the implementation. Note that the map div is a map that uses the Google Maps API.</p>
  
  <pre><code>&lt;body&gt;
      &lt;div id="full-height"&gt;
          &lt;div id="map"&gt;&lt;/div&gt;
          &lt;nav class="navbar navbar-inverse bg-inverse navbar-toggleable-md navbar-light bg-faded"&gt;
              &lt;a class="navbar-brand" href="#"&gt;
                  &lt;i id="foursquare-logo" class="fa fa-foursquare" aria-hidden="true"&gt;&lt;/i&gt;
              &lt;/a&gt;
              &lt;div id="location-dropup" class="btn-group dropup"&gt;
                  &lt;button type="button" class="btn btn-secondary"&gt;Best locations&lt;/button&gt;
                  &lt;button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"&gt;
                      &lt;span class="sr-only"&gt;Toggle Dropdown&lt;/span&gt;
                  &lt;/button&gt;
                  &lt;div data-bind="foreach: favPlaces" class="dropdown-menu" aria-labelledby="dropdownMenuButton"&gt;
                      &lt;a data-bind="text: name, click: $parent.openInfoWindow" class="dropdown-item"&gt;Place Name&lt;/a&gt;
                  &lt;/div&gt;
              &lt;/div&gt;
  
          &lt;/nav&gt;
  
      &lt;/div&gt;
      &lt;!-- Foursquare logo --&gt;
      &lt;script src="https://use.fontawesome.com/5228693ec0.js"&gt;&lt;/script&gt;
      &lt;!-- Bootstrap --&gt;
      &lt;script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"&gt;&lt;/script&gt;
      &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"&gt;&lt;/script&gt;
      &lt;script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"&gt;&lt;/script&gt;
      &lt;!-- KnockoutJS --&gt;
      &lt;script src="js/lib/knockout-3.4.1.js"&gt;&lt;/script&gt;
      &lt;script src="js/app.js"&gt;&lt;/script&gt;
      &lt;script async defer src="https://maps.googleapis.com/maps/api/js?key=AIzaSyDtODGjlNobKNCo4OX_voxjIkNkHCfQ3I4&amp;callback=initMap"&gt;&lt;/script&gt;
  &lt;/body&gt;
  </code></pre>
  
  <p>Here is more details about the relevant javascript used.</p>
  
  <pre><code>var mFavPlaces = [
  
      {
          name: "Takeshita Street",
          lat: 35.6715659,
          lng: 139.7031469,
          imgSrc: "img/favPlaces/takeshita.jpg"
      }, {
          name: "Nakamise Street",
          lat: 35.7113873,
          lng: 139.794207,
          imgSrc: "img/favPlaces/asakusa.jpg"
      }, {
          name: "Yodobashi-Akiba",
          lat: 35.6995227,
          lng: 139.7734171,
          imgSrc: "img/favPlaces/akihabara.jpg"
      }, {
          name: "Meiji Jingu",
          lat: 35.6763976,
          lng: 139.6993259,
          imgSrc: "img/favPlaces/meiji.jpg"
      }, {
          name: "Shibuya Crossing",
          lat: 35.6594087,
          lng: 139.6981677,
          imgSrc: "img/favPlaces/shibuya.jpg"
      }
  
  ];
  
  // Stores the Google maps markers for the favPlaces
  var mMarkers = {};
  
  var mQueryInfo = {
      "near": "Tokyo",
      "client_id": "AG5MATDOQ5HAXLODDIV1YALJZA4IN3LS5XEUOPWQIGHG0BHL",
      "client_secret": "PPJYHED0SI5WLWC05LXGD1E3T1JDQI23EWNSTQLI2MO0WEAF",
      "version": "20170220"
  };
  
  function httpGetAsync(theUrl, callback, infoWindow, placeIndex, marker) {
      var xmlHttp = new XMLHttpRequest();
      xmlHttp.onreadystatechange = function() {
          if (xmlHttp.readyState == 4 &amp;&amp; xmlHttp.status == 200) {
              callback(xmlHttp.responseText, infoWindow, placeIndex, marker);
          }
      }
      xmlHttp.open("GET", theUrl, true); // true for asynchronous 
      xmlHttp.send(null);
  }
  
  function setFavPlaceInfo(placeName, infoWindow, placeIndex, marker) {
      var url = "https://api.foursquare.com/v2/venues/search?limit=1&amp;near=" + mQueryInfo.near + "&amp;query=" + placeName + "&amp;v=" + mQueryInfo.version + "&amp;client_id=" + mQueryInfo.client_id + "&amp;client_secret=" + mQueryInfo.client_secret;
      httpGetAsync(url, setInfoWindowContent, infoWindow, placeIndex, marker);
  }
  
  function setInfoWindowContent(placeDetailsText, infoWindow, placeIndex, marker) {
  
      var placeDetails = JSON.parse(placeDetailsText);
  
      // Extract info to display in infoWindows
      var completeName = placeDetails.response.venues[0].name;
      var address = placeDetails.response.venues[0].location.address;
      var websiteUrl = placeDetails.response.venues[0].url;
      var numberCheckins = placeDetails.response.venues[0].stats.checkinsCount;
  
      var contentString = '&lt;div class="infoWindow"&gt;' + '&lt;img class="img-fluid img-thumbnail" src="' + mFavPlaces[placeIndex].imgSrc + '" style="margin-bottom:1rem;" alt="' + completeName + '" /&gt;' + '&lt;h4&gt;' + completeName + '&lt;/h4&gt;' + '&lt;b&gt;Checkins: &lt;/b&gt;' + numberCheckins + '&lt;br&gt;' + '&lt;b&gt;Website: &lt;/b&gt; &lt;a href="' + websiteUrl + '"&gt;' + websiteUrl + '&lt;/a&gt;' + '&lt;br&gt;' + '&lt;b&gt;Address: &lt;/b&gt; ' + address + '&lt;/div&gt;';
  
      infoWindow.setContent(contentString);
      infoWindow.open(mMap, marker);
  }
  
  // Object representation of a favorite place
  var FavPlace = function(data) {
      this.name = ko.observable(data.name);
      this.imgSrc = ko.observable(data.imgSrc);
  }
  
  // View Model
  var TokyoViewModel = function() {
      var self = this;
  
      // All the favorite places
      this.favPlaces = ko.observableArray([]);
      mFavPlaces.forEach(function(place) {
          self.favPlaces.push(new FavPlace(place));
      });
  
      this.openInfoWindow = function(favPlace) {
          console.log("Success!");
      }
  }
  
  // Initialize the map and adds markers with infoWindows
  function initMap() {
  
      var center = { lat: 35.6809814, lng: 139.7538745 };
      mMap = new google.maps.Map(document.getElementById('map'), {
          zoom: 12,
          center: center
      });
  
      // Get details of favorite places 
      var placeIndex;
      for (placeIndex = 0; placeIndex &lt; mFavPlaces.length; placeIndex++) {
          var marker = new google.maps.Marker({
              position: { lat: mFavPlaces[placeIndex].lat, lng: mFavPlaces[placeIndex].lng },
              map: mMap,
          });
  
          var infowindow = new google.maps.InfoWindow({});
  
          // Use a closure to add listeners
          google.maps.event.addListener(marker, 'click', (function(marker, placeIndex) {
              return function() {
                  // Set infoWindow's content
                  setFavPlaceInfo(mFavPlaces[placeIndex].name, infowindow, placeIndex, marker);
  
                  // Set marker animation (lasts for 1 cycle == 750ms)
                  marker.setAnimation(google.maps.Animation.BOUNCE);
                  setTimeout(function() { marker.setAnimation(null); }, 750);
              }
          })(marker, placeIndex));
  
          // Store the marker
          mMarkers[mFavPlaces[placeIndex].name] = marker;
      }
  
  
  }
  
  // Activates knockout.js
  ko.applyBindings(new TokyoViewModel());
  </code></pre>