Question

A "working" copy of what I'm trying to do is below, I simply want to be able to add or edit data in the array but I have to do things like $('#examQuestion').val().

That seems more like a hack.

I assume there is an easy solution to this with data-linking, I'm just not sure how to fix this.

Here is the code in jsFiddle

<!doctype html>
<html class="no-js" lang="en">
<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <title>test</title>
</head>
<body>

<div id="main"></div>

<script id="newTmpl" type="text/x-jsrender">
    <table width="100%">
        <thead>
            <th>Question</th>
            <th>Questoin Type</th>
            <th>Actions</th>
        </thead>
        <tbody>
            <tr>
                <td>
                    <textarea placeholder="Exam Question" rows="10" id="examQuestion" name="examQuestion" cols="50"></textarea>
        </td>
                <td>
                    <select id="examQuestionType" name="examQuestionType"><option value="0" selected="selected">-- Please select question type --</option><option value="1">Radio Button</option><option value="2">Checkbox</option><option value="3">Textarea</option><option value="4">Text</option></select>
        </td>
                <td>
                    <button class="addOrUpdateQuestion" type="button">Add / update</button>
        </td>
            </tr>
            {^{for questions}}
                <tr>
                    <td>
                        {{:question}}
                    </td>
                    <td>
                        {{:typeName}}
                    </td>
                    <td>
                        <button class="editQuestion" type="button">Edit</button>
          </td>
                </tr>
            {{/for}}
        </tbody>
    </table>
</script>

  <script src="jquery.js"></script>
  <script src="jsviews.min.js"></script>
  <script>
    $(function() {
      var question = [];

      var app = {
        name: '',
        description: '',
        selectedQuestionId: -1,
        questions: question
      };

      var tmpl = $.templates("#newTmpl");
      tmpl.link("#main", app);

      $('#main').on('click', '.editQuestion', function() {
        var tmpData = $.view(this).data
        app.selectedQuestionId = $.view(this).index;
        $('#examQuestion').val(tmpData.question);
        $('#examQuestionType').val(tmpData.type);
      });

      $('#main').on('click', '.addOrUpdateQuestion', function() {
        if (app.selectedQuestionId == -1) {
          $.observable(question).insert({
            question: $('#examQuestion').val(),
            type: $('#examQuestionType').val(),
            typeName: $('#examQuestionType').find(':selected').text()
          });
        } else {
          var tmpItem = app.questions[app.selectedQuestionId];
          tmpItem.question = $('#examQuestion').val();
          tmpItem.type = $('#examQuestionType').val();
          tmpItem.typeName = $('#examQuestionType').find(':selected').text();
          app.questions[app.selectedQuestionId] = tmpItem;
          $.observable(question).refresh(question);
        }
      });
    });
  </script>
</body>
</html>
Was it helpful?

Solution

Well clearly JsViews is all about having UI automatically update when the model changes! Only the model can be the original data - raw object graph from a JSON request, for example, and does not have to be mapped to specific MVVM classes using specific types. (Responding here to the comments above on using Knockout - which does require specific wrappers). That said, JsViews also works very well with MVVM wrappers.

So here is a modified version of your example http://jsfiddle.net/BorisMoore/F9WF6/3/

Important to note: all the data-linking using data-link attributes or {^{... - which was missing in your example.

BTW this: data-link="selectedQuestion^type" is an example of deep linking, so it updates both when the selectedQuestion switches to another one, and when the type property of the current selectedQuestion changes. For more on this see http://www.jsviews.com/#observe - talking about leaf changes or deep changes.

<tr>
  <td>
    <textarea data-link="selectedQuestion^question" placeholder="Exam Question" rows="10" name="examQuestion" cols="20"></textarea>
  </td>
  <td>
    <select data-link="selectedQuestion^type" name="examQuestionType">
      <option value="" selected="selected">-- Please select question type --</option>
      <option value="1">Radio Button</option>
      <option value="2">Checkbox</option><option value="3">Textarea</option>
      <option value="4">Text</option>
    </select>
  </td>
  <td>
    <button data-link="disabled{:selectedQuestion !== newQuestion || !selectedQuestion.question || !selectedQuestion.type}"
       class="add" type="button">Add</button>
    <button class="new" type="button">New</button>
  </td>
</tr>
{^{for questions}}
  <tr>
    <td>
      {^{:question}}
    </td>
    <td>
      {^{:~typeName(type)}}
    </td>
    <td>
      <button class="editQuestion" type="button">Edit</button>
    </td>
  </tr>
{{/for}}

The code simplifies down to the following:

$('#main').on('click', '.editQuestion', function() {
  $.observable(app).setProperty("selectedQuestion", $.view(this).data);
});

$('#main').on('click', '.add', function() {
  $.observable(question).insert({
    question: newQuestion.question,
    type: newQuestion.type
  });
  $.observable(newQuestion).setProperty({ question: "", type: ""});
});

$('#main').on('click', '.new', function() {
  $.observable(app).setProperty("selectedQuestion", newQuestion);
});

Take a look at the following samples which show master-detail editing - so correspond to a related scenario to yours: http://www.jsviews.com/#samples/editable

BTW a lot more samples will be on the way soon for MVVM and using view model classes. But in the meantime here is a link which has not yet been exposed publicly on the jsviews.com site: http://www.jsviews.com/#explore/objectsorvm

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top