JSFiddle - React, Tailwind, and code Playground

by Santosh Giridhara

HTML

<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.3/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js"></script>
<h4>Angular editing bounds</h4>
<div ng-app="app" ng-controller="Ctrl"> 
    <!-- template -->
    <script type="text/ng-template" id="/tpl">
   <div>
          <a href="" class="ps-widgets-clickable" ng-click="showForm()" ng-show="!formVisible" ng-transclude></a>
          <form name="frm" ng-show="formVisible" ng-submit="submit($event)" ng-class="{'error': error, 'control-group form-inline': true}">
            <label>{{ lowerLabel }}</label>
            <input type="number" name="lower" class="input-small" ng-change="validate()" lazy-model="lower">
            <label>{{ higherLabel }}</label>
            <input type="number" name="higher" class="input-small" ng-change="validate()" lazy-model="higher">
            <button type="submit" ng-disabled="frm.$invalid" class="btn btn-primary"><span>Ok</span></button>
            <button type="reset" class="btn" ng-click="hideForm()"><span>Cancel</span></button>
            <div class="editable-error help-block" ng-show="frm.$invalid">Minimum value has to be lower than maximum value.</div>
          </form>
        </div>     
        
    </script>
     
<a ng-click="change()">Change higher</a>
<my-bounds lower-label="Min" higher-label="Max" lower="myBounds.lower" higher="myBounds.higher">     
    The value is bounded from {{myBounds.lower}} to {{myBounds.higher}}
</my-bounds>
       
       
</div>

CSS

div[ng-app] { margin: 50px; }

JavaScript

var app = angular.module("app", []);

app.controller('Ctrl', function($scope) {
  $scope.myBounds = {
      lower: 90,
      higher: 100  
  };
  $scope.change = function() {
      $scope.myBounds.lower = 101; 
  };
});

app.directive('myBounds', function() {
    return {
      restrict: 'E',
      scope: {
        lower: '=',
        higher: '=',
        visible: '=',
        lowerLabel: "@",
        higherLabel: "@"
      },
      transclude: true,
      replace: true,
      templateUrl: '/tpl',
      controller: function($scope) {
          
        //$scope.error = null;
          $scope.validate = function() {
            if (this.frm.lower.$modelValue >= this.frm.higher.$modelValue) {
                this.frm.$setValidity('lower', false);
            } else {
                this.frm.$setValidity('lower', true);
            }
        };  
        $scope.submit = function(e) {
            console.log('controller submit');
       //   if ($scope.lower >= $scope.higher) {
        //    e.preventDefault();
            // show validation error here
       //     $scope.error = ''
       //   } else {
            $scope.formVisible = false;
       //   }
        };
        $scope.showForm = function() {
          $scope.formVisible = true;
          $scope.validate();  
        //  $scope.error = null;
        };
        $scope.hideForm = function() {
          $scope.formVisible = false;
        }
      }
    };
  });

// == lazyModel directive ==
app.directive('lazyModel', function($parse, $compile) {
  return {
    restrict: 'A',  
    priority: 500,
    terminal: true, 
    require: '^form',
    scope: true,
    compile: function compile(elem, attr) {
        // getter and setter for original model
        var ngModelGet = $parse(attr.lazyModel);
        var ngModelSet = ngModelGet.assign;  
        // set ng-model to buffer in isolate scope
        elem.attr('ng-model', 'buffer');
        // remove lazy-model attribute to exclude recursion
       ...