JSFiddle - React, Tailwind, and code Playground

HTML

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>
<p><b>AngularJS lazyModel directive</b><br/>
Original model gets updated only when "save" clicked</p>
<div ng-app="app" ng-controller="Ctrl">
    <span>Username: <strong>{{user.name}}</strong></span>
    <button ng-click="formVisible=true" ng-show="!formVisible">edit</button>
    <form ng-submit="formVisible=false" ng-show="formVisible">
      <input type="text" lazy-model="user.name">
      <button type="submit">save</button>
      <button type="reset" ng-click="formVisible=false">cancel</button>
    </form>    
</div>

CSS

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

JavaScript

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

app.controller('Ctrl', function($scope) {
  $scope.user = {
      name: 'vitalets'
  }; 
});

// == lazyModel directive ==
app.directive('lazyModel', function($parse, $compile) {
  return {
    restrict: 'A',  
    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
        elem.removeAttr("lazy-model");
        return function postLink(scope, elem, attr) {
          // initialize buffer value as copy of original model 
          scope.buffer = ngModelGet(scope.$parent);
          // compile element with ng-model directive poining to buffer value   
          $compile(elem)(scope);
          // bind form submit to write back final value from buffer
          var form = elem.parent();
          while(form[0].tagName !== 'FORM') {
            form = form.parent();
          }
          form.bind('submit', function() {
            scope.$apply(function() {
                ngModelSet(scope.$parent, scope.buffer);
            });
         });
         form.bind('reset', function(e) {
            e.preventDefault();
            scope.$apply(function() {
                scope.buffer = ngModelGet(scope.$parent);
            });
         });
        };  
     }
  };
});