title: Knockout: viewModel is not defined
body: <p>When using <a href="http://jsfiddle.net/rniemeyer/qwgrf/" rel="nofollow">this JSFiddle</a> as a reference to build a grid with organizable contents I ran into a problem. An error message says <code>Error: viewModel is not defined</code>.</p>
  
  <p>It should normally work as in the example, since my <code>viewModel</code> is defined on the first line in JS. It may have something to do with requesting <code>viewModel</code> from within the template.</p>
  
  <p>When checking other answers, they all were too generic. I didn't find one that answers one that solves my problem.</p>
  
  <p>The full error:</p>
  
  <pre><code>Uncaught ReferenceError: Unable to process binding "template: function (){return { name:'gridTmpl',foreach:gridItems,templateOptions:{ parentList:gridItems}} }"
  Message: Unable to process binding "template: function (){return { name:'rowTmpl',foreach:rowItems,templateOptions:{ parentList:rowItems}} }"
  Message: Unable to process binding "visible: function (){return $data !== viewModel.selectedRowItem() }"
  Message: viewModel is not defined
  </code></pre>
  
  <p><div class="snippet" data-lang="js" data-hide="false">
  <div class="snippet-code">
  <pre class="snippet-code-js lang-js prettyprint-override"><code>var viewModel = {
    gridItems: ko.observableArray(
      [{
        "rowItems": [{
          "name": "Item 1"
        }, {
          "name": "Item 2"
        }, {
          "name": "Item 3"
        }]
      }, {
        "rowItems": [{
          "name": "Item 4"
        }]
      }, {
        "rowItems": [{
          "name": "Item 5"
        }, {
          "name": "Item 6"
        }]
      }]
    ),
    selectedRowItem: ko.observable(),
    selectRowItem: function(rowItem) {
      this.selectedRowItem(rowItem);
    }
  };
  
  //connect items with observableArrays
  ko.bindingHandlers.sortableList = {
    init: function(element, valueAccessor, allBindingsAccessor, context) {
      $(element).data("sortList", valueAccessor()); //attach meta-data
      $(element).sortable({
        update: function(event, ui) {
          var item = ui.item.data("sortItem");
          if (item) {
            //identify parents
            var originalParent = ui.item.data("parentList");
            var newParent = ui.item.parent().data("sortList");
            //figure out its new position
            var position = ko.utils.arrayIndexOf(ui.item.parent().children(), ui.item[0]);
            if (position &gt;= 0) {
              originalParent.remove(item);
              newParent.splice(position, 0, item);
            }
  
            ui.item.remove();
          }
        },
        connectWith: '.container'
      });
    }
  };
  
  //attach meta-data
  ko.bindingHandlers.sortableItem = {
    init: function(element, valueAccessor) {
      var options = valueAccessor();
      $(element).data("sortItem", options.item);
      $(element).data("parentList", options.parentList);
    }
  };
  
  //control visibility, give element focus, and select the contents (in order)
  ko.bindingHandlers.visibleAndSelect = {
    update: function(element, valueAccessor) {
      ko.bindingHandlers.visible.update(element, valueAccessor);
      if (valueAccessor()) {
        setTimeout(function() {
          $(element).focus().select();
        }, 0); //new RowItems are not in DOM yet
      }
    }
  }
  
  ko.applyBindings(viewModel);</code></pre>
  <pre class="snippet-code-css lang-css prettyprint-override"><code>.sortable {
    list-style-type: none;
    margin: 0;
    padding: 0;
    width: 60%;
  }
  
  .sortable li {
    margin: 0 3px 3px 3px;
    padding: 0.4em;
    padding-left: 1.5em;
    font-size: 1.4em;
    height: 18px;
    cursor: move;
  }
  
  .sortable li span {
    position: absolute;
    margin-left: -1.3em;
  }
  
  .sortable li.fixed {
    cursor: default;
    color: #959595;
    opacity: 0.5;
  }
  
  .sortable-grid {
    width: 100% !important;
  }
  
  .sortable-row {
    height: 100% !important;
    padding: 0 !important;
    margin: 0 !important;
    display: block !important;
  }
  
  .sortable-item {
    border: 1px solid black;
  }</code></pre>
  <pre class="snippet-code-html lang-html prettyprint-override"><code>&lt;script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"&gt;&lt;/script&gt;
  &lt;link href="https://code.jquery.com/ui/1.12.0-beta.1/themes/smoothness/jquery-ui.css" rel="stylesheet" /&gt;
  &lt;script src="https://code.jquery.com/ui/1.11.4/jquery-ui.js"&gt;&lt;/script&gt;
  &lt;link href="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet" /&gt;
  &lt;script src="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"&gt;&lt;/script&gt;
  &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.2.0/knockout-min.js"&gt;&lt;/script&gt;
  
  &lt;ul class="sortable sortable-grid" data-bind="template: { name: 'gridTmpl', foreach: gridItems, templateOptions: { parentList: gridItems} }, sortableList: gridItems"&gt;
  &lt;/ul&gt;
  
  &lt;script id="gridTmpl" type="text/html"&gt;
    &lt;li class="sortable-row"&gt;
      &lt;table style="width:100%"&gt;
        &lt;tbody&gt;
          &lt;tr class="sortable container" data-bind="template: { name: 'rowTmpl', foreach: rowItems, templateOptions: { parentList: rowItems} }, sortableList: rowItems"&gt;
          &lt;/tr&gt;
        &lt;/tbody&gt;
      &lt;/table&gt;
    &lt;/li&gt;
  &lt;/script&gt;
  
  &lt;script id="rowTmpl" type="text/html"&gt;
    &lt;td class="item" data-bind="sortableItem: { item: $data, parentList: $item.parentList }"&gt;
      &lt;a href="#" data-bind="text: name, click: function() { viewModel.selectRowItem($data); }, visible: $data !== viewModel.selectedRowItem()"&gt;&lt;/a&gt;
      &lt;input data-bind="value: name, visibleAndSelect: $data === viewModel.selectedRowItem()" /&gt;
    &lt;/td&gt;
  &lt;/script&gt;</code></pre>
  </div>
  </div>
  </p>