Tie!

An experiment to tie properties to HTML elements.

by JeyDotC

HTML

<form id="todos-form">
  <p tie-visible="hasText">
    This sould not be visible unless there is some text in the textarea.
  </p>
  <p tie-visible=": this.text.length > 0">
    This is an expression based binding!
  </p>
  <p tie-text="help">Loading...</p>
  <p>
    This is an inner binding repeating the text.
    <span tie-text="help">loading 2...</span>
  </p>
  <textarea tie-value="text"></textarea>
  <ul tie-each="todos">
    <li tie-text="text">Something</li>
  </ul>
  <button tie-click="add">Add TODO</button>
  <button tie-click="reset">Clear</button>
</form>

JavaScript

function TodosView() {
	const defaultHelp = 'This is a one-direction binding.';
  
  this.help = defaultHelp;
  this.text = '';
  
  this.hasText = function (){
  	return this.text.length > 0;
  };

  this.add = function() {
    this.help = this.text;
  };
  
  this.reset = function (){
  	this.text = '';
    this.help = defaultHelp;
  };
}

// Library code.

function isFunction(functionToCheck) {
 return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
}

const tie = {};
const dummy = x => x;

function textTie(context) {
  context.$el.text(context.initialValue);

  this.get = dummy;
  this.set = function(value) {
    context.$el.text(value);
  };
  this.propertyChanged = dummy;
}

function valueTie(context) {
  context.$el.val(context.initialValue);

  this.get = value => context.$el.val();
  this.set = value => context.$el.val(value);
  this.propertyChanged = dummy;
  
  context.$el.on('change', context.propertyChanged);
}

function visibleTie(context) {
	var _internalValue = context.initialValue;
  var self = this;
  
  this.value = function(){
  	if(isFunction(_internalValue)){
    	return _internalValue.call(context.viewModel);
    }
    
    return _internalValue;
  };
  
  this.get = value => self.value();
  this.set = value => {  
  	_internalValue = value;
    
  }
  this.propertyChanged = updateEl;

  updateEl();

  function updateEl() {
    self.value() ? context.$el.show() : context.$el.hide();
  }
}

function clickTie(context) {
  this.get = value => value;
  this.set = value => value;
  this.propertyChanged = dummy;

  context.$el.on('click', function(event) {
    event.preventDefault();
    event.stopPropagation();
    context.initialValue.call(context.viewModel, event);
  });
}

function tiePropertyDescriptor(initialValue, propertyChanged) {
  var self = this;
  self.ties = [];
  self.internalValue = initialValue;
  self.get = function() {
    let value = self.internalValue;
    $.each(self.ties, function(k, tie) {
   ...