Unspaguetti

Toggle class name on click in jQuery

by jeyssonguevara

HTML

<div id="app">
  <strong>Full Name: </strong>
  <span data-tag="name" data-text></span>
  <span data-tag="lastName" data-text></span>
  <div>
    <input id="name" type="text" placeholder="First Name" data-tag="name" data-value />
    <input id="lastName" type="text" placeholder="Last Name" data-tag="lastName" data-value />
    <button id="submit" type="submit" data-tag="isValid" data-visible>
      Submit
    </button>

    <button id="clear">Cancel</button>
  </div>
  <table>
    <thead>
      <tr>
        <th>Name</th>
        <th>Last Name</th>
      </tr>
    </thead>
    <tbody data-tag="people" data-each>
      <tr>
        <td data-tag="people.name" data-text>Yo</td>
        <td data-tag="people.lastName" data-text>Yo</td>
      </tr>
    </tbody>
  </table>
</div>

CSS

#app {
  background-color: #ffffff;
}

JavaScript

function Unspaguetti($context) {
  const appState = {};
  let hasRunFirstTime = false;

  this.calculated = (name, callback) => {
    appState[name] = callback;
    return callback;
  };

  this.state = (name, initial) => {
    appState[name] = initial;
    return [
      () => appState[name],
      value => {
        appState[name] = value;
        updateUI();
      }
    ];
  };

  this._firstRun = () => !hasRunFirstTime && updateUI();

  function updateUI() {
    Unspaguetti.stateHandlers.forEach(handler => {
      $(`[data-${handler.name}]`, $context).each((index, el) => {
        const $el = $(el);
        const tag = $el.attr("data-tag");
        const state = appState[tag];
        const value = typeof state === "function" ? state() : state;
        handler.handle($el, value, tag);
      });
    });
  }
}

Unspaguetti.stateHandlers = [];
Unspaguetti.addStateHandler = (name, handle) => Unspaguetti.stateHandlers.push({
  name,
  handle
});

// Add standard state handlers
Unspaguetti.addStateHandler('text', ($el, value) => $el.text(value));

Unspaguetti.addStateHandler('visible', ($el, value) => $el.toggle(!!value));

Unspaguetti.addStateHandler('value', ($el, value) => $el.val(value));

const eachTemplates = {};

Unspaguetti.addStateHandler('each', ($el, value, tag) => {
  if (!eachTemplates[tag]) {
    eachTemplates[tag] = $el.find(":first-child").clone().detach();
  }
  const $template = eachTemplates[tag];
  $el.empty();
  (value || []).map(item => Unspaguetti.run(function(u) {
    Object.entries(item).map(([name, value]) => u.state(`${tag}.${name}`, value));
  }, $template.clone(false, false).appendTo($el).show()));
});

Unspaguetti.run = function(component, $context) {
  const unspaguetti = new Unspaguetti($context);
  component(unspaguetti);
  unspaguetti._firstRun();
}


function App(unspaguetti) {
  // Declare state management
  const [getName, setName] = unspaguetti.state("name");
  const [getLastName, setLastName] = unspaguetti.state("lastName");
 ...