JSFiddle - React, Tailwind, and code Playground

by romanych

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/3.4.1/knockout-debug.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.4.1/knockout.mapping.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.17.1/moment.js"></script>
<script type="text/html" id="questions-editor-tpl">
  <div data-bind="foreach: questions">
    <input type="text" data-bind="textInput: question" placeholder="Question text" />
    <button data-bind="click: $parent.deleteQuestion">x</button>
    <ul data-bind="foreach: options ">
      <li>
        <input type="text" data-bind="textInput: text" placeholder="Option " />
        <button data-bind="click: $parent.removeOption, visible: $data.hideDelete ? $data.hideDelete() : true ">x</button>
      </li>
    </ul>
    <br />
    <p>
      <label>
        <input type="checkbox" data-bind="checked: anonymous" />Anonymous</label>
      <a href="#" data-bind="click: toggleSettings">Settings</a>
    </p>
    <div data-bind="visible: showSettings">
      <p>
        User need to choose
        <select data-bind=" value: max_options, options: availableMaxOptions ">
        </select>
      </p>
      <p>
        End accept answers:
        <select data-bind="
    value: end_date, 
    valueAllowUnset: true, 
    optionsCaption: 'Never', 
optionsText: 'caption',
optionsValue: 'date',
    options: availableEndDates"></select>
        <br />
        <label>
          <input type="checkbox" data-bind="checked: show_results_after_end, enable: end_date" />Show results only when survey ends</label>
      </p>
      <p>
      </p>
    </div>

  </div>
  <button data-bind="click: addQuestion ">Add question</button>
  <br />

</script>
<div id="questions-editor ">
  <div data-bind="template: {name: 'questions-editor-tpl'} ">

  </div>
  <pre data-bind="text: JSON.stringify(ko.mapping.toJS(questions), null, 2) "></pre>
</div>

JavaScript

var questions = [{
  "id": 1,
  "anonymous": false,
  "end_date": "2017-04-01",
  "show_results_after_end": true,
  "question": "Question 1",
  "max_options": 1,
  "options": [{
    "id": 1,
    "text": "Q1 O1"
  }, {
    "id": 2,
    "text": "Q1 O2"
  }, {
    "id": 3,
    "text": "Q1 O3"
  }, {
    "id": 4,
    "text": "Q1 O4"
  }]
}, {
  "id": 2,
  "anonymous": true,
  "end_date": null,
  "show_results_after_end": false,
  "max_options": 2,
  "options": [{
    "id": 5,
    "text": "Q2 O1"
  }, {
    "id": 6,
    "text": "Q2 O2"
  }, {
    "id": 7,
    "text": "Q2 O3"
  }]
}];

function getAvailableEndDates() {
  var result = [];

  var days = 31;
  var d = moment();
  for (var i = 1; i <= days; i++) {
    d.add(1, 'days');
    result.push({
      date: d.format("YYYY-MM-DD"),
      caption: d.format("LL")
    })
  };

  return result;
}

function createNewOption() {
  var newOption = {
    "text": ko.observable(),
    "new": true
  };
  newOption.hideDelete = ko.computed(function() {
    return !!this.text();
  }, newOption)

  return newOption;
}

function QuestionViewModel(question) {
  if (!question) {
    question = {
      question: "",
      max_options: 1,
      options: [],
      anonymous: false,
      end_date: null,
      show_results_after_end: false
    }
  };
  
  var isDefaultSettins = question.max_options === 1 && question.end_date === null && question.show_results_after_end === false;
  
  
  ko.mapping.fromJS(question, {}, this);
  var self = this;

  self.showSettings = ko.observable(!isDefaultSettins);
  self.toggleSettings = function() {
    self.showSettings(!self.showSettings());
  }
  self.removeOption = function(option) {
    self.options.remove(option);
  }

  self.availableMaxOptions = ko.computed(function() {
    var count = self.options().filter(o => !!o.text()).length;
    var result = [1];
    for (var i = 2; i <= count; i++) {
      result.push(i);
    }
    return result;
  });

  self.availableEndDates =...