JsViews bind to two-dimensional array

by BorisMoore

HTML

<script src="http://www.jsviews.com/download/jsviews.js"></script>
<script src="http://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.js"></script>
<link rel="stylesheet" href="http://www.jsviews.com/download/sample-tag-controls/jsonview/jsonview.css">
<link rel="stylesheet" href="http://www.jsviews.com/samples/mvvm/change-log.css">
  <div class="left">
    <div id="result"></div>
  </div>

  <div class="logBox">
    <label>Change Log:</label>
    <button class="clear">Clear</button>
    <div class="messages"></div>
  </div>

    <script id="personTmpl" type="text/x-jsrender">
    <div>
      <button data-link="{on ~insertRow}">Insert Row</button>
    </div>
    <table>
      <tbody>
        {^{for lists}}
        <tr>
          <td>
            <button data-link="{on ~removeRow}">Remove row</button><br/>
            <button data-link="{on ~insertCol}">Insert col</button>
          </td>
            {^{for #data ^~outerIndex=#index ^~rowLength=length}}
            {{!--Use ^~ syntax to data-link to contextual template params, for live updates--}}
          <td>
              Row {^{:~outerIndex}} Length: {^{:~rowLength}}<br/>
            Col {^{:#index}} Prop: {^{:someProp}}<br/>
            <input data-link="title{:someProp} {:someProp:}" />
            <span class="remove" data-link="{on ~removeCol}"></span>
          </td>
          {{/for}}
        </tr>
        {{/for}}
      </tbody>
    </table>
    {{jsonview/}}
  </script>

CSS

.remove:after {
	color: #be614c;
	font-weight: bold;
	padding: 0 6px 2px;
	content: 'x';
	cursor: pointer;
    font-family: Arial;
    font-size: 14pt;
}

.remove:hover:after {
	color: red;
	background-color: #dbffe0;
}

td {
    border: solid grey 1px;
    padding: 5px;
}

JavaScript

var appData = {
      lists: [
        [{ someProp: 1, ss: 33 }, { someProp: 2, foo: 22 }]
      ]
    };

    var methods = {
      insertRow: function(ev, eventArgs) {
        var view = eventArgs.view;
        $.observable(this.lists).insert([[{ someProp: 1 }, { someProp: 2 }]]);
      },
      insertCol: function(ev, eventArgs) {
        var view = eventArgs.view;
        $.observable(this).insert({ someProp: this.length + 1 });
      },
      removeRow: function(ev, eventArgs) {
        var view = eventArgs.view;
        $.observable(view.get("array").data).remove(
          view.index
        )
      },
      removeCol: function(ev, eventArgs) {
        var view = eventArgs.view;
        $.observable(view.get("array").data).remove(
          view.index
        )
      }
    }

    $(".clear").on("click", function() {
      $(".messages").empty();
    });

    var tmpl = $.templates("#personTmpl");

    tmpl.link("#result", appData, methods);

    $.observable(appData).observeAll(changeHandler);

    function changeHandler(ev, eventArgs) {
      var message = "";
      if (ev.data.observeAll) {
        message += "<div><em>observeAll path:</em> " + ev.data.observeAll.path() + "</div>"
      }
      for (var key in eventArgs) {
        message += "<div><em>" + key + ":</em> " + JSON.stringify(eventArgs[key]) + "</div>";
      }
      $(".messages").append("<div>" + message + "</div>");
    }