title: Knockout.js autocomplete bindingHandler
body: <p>I'm trying my hand at an autocomplete handler for Knockout.js, and I'm looking for some feedback.  This currently works, but I'm trying to see if I can get the job done without so many Eval()s all over the place, and for the sake of reusability, see if there is a way to reference the ViewModel without presupposing it is named 'vm' as below.</p>
  
  <p>Usage:</p>
  
  <pre><code>&lt;input placeholder="Test..." type="search" data-bind="autoComplete:$root.persons, source:'/api/Person/', parameterName:'searchString', labelKey:'displayName', valueKey:'urid', onSelected:'addPerson'" autocomplete="off" /&gt;
  </code></pre>
  
  <p>JS:</p>
  
  <pre><code>ko.bindingHandlers.autoComplete = {
      init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) {
          var postUrl = allBindingsAccessor().source; // url to post to is read here
          var param = allBindingsAccessor().parameterName;
          var labelKeyName = allBindingsAccessor().labelKey;
          var valueKeyName = allBindingsAccessor().valueKey;
          var selectedFunction = allBindingsAccessor().onSelected;
          var selectedObservableArrayInViewModel = valueAccessor();
  
          $(element).autocomplete({
              minLength: 2,
              autoFocus: true,
              source: function (request, response) {
                  $.ajax({
                      url: param != null ? postUrl : postUrl + request.term,
                      data: param == null ? '' : param + "=" + request.term,
                      dataType: "json",
                      type: "GET",
                      success: function (data) {
                          response($.map
                              (data, function (obj) {
                                  return {
                                      label: eval("obj." + labelKeyName),
                                      value: eval("obj." + valueKeyName)
                                  };
                              }));
                      }
                  });
              },
              select: function (event, ui) {
                  if (selectedFunction != null) {
                      var functionCall = 'vm.' + selectedFunction + "(event, ui)";
                      eval(functionCall);
                  }
              }
          });
      }
  };
  </code></pre>