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" />

    <ul data-bind="foreach: options ">
      <li>
        <input type="text" data-bind="textInput: text" placeholder="Add new option" />
        <button data-bind="click: $parent.removeOption, visible: $data.hideDelete ? $data.hideDelete() : true ">x</button>
      </li>
    </ul>
   
    </div>

  </div>
  

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

  </div>
 
</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"
  }]
}];

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 = getAvailableEndDates();

  ko.computed(function() {
    var needToAdd = true;
    self.options().forEach(function(option) {
      if (!option.text()) {
        if (option.new) {
          needToAdd = false;
        }
      }
    })

    if (needToAdd) {
      setTimeout(function() {
        self.options.push(createNewOption());
      });
    }
 ...