Angular Edit-in-Place Directive

by hamzeen hameem

HTML

<div>
  <div ng-controller="ContactsCtrl">
    <h2>Contacts</h2>
    <br />
    <ul>
        <li ng-repeat="contact in contacts">
            <edit-in-place value="contact.name"></edit-in-place>
        </li>
    </ul>
    <br />
    <p>Here we repeat the contacts to ensure bindings work:</p>
    <br />
    <ul>
        <li ng-repeat="contact in contacts">
            {{contact.name}}
        </li>
    </ul>
    
  </div>
</div>

CSS

.edit-in-place span {
  cursor: pointer;
  font-size:26px;
  height:30px;
}

.edit-in-place input {
  display: none;
  outline:none;
}

.edit-in-place.active span {
  display: none;
  width:200px;
  padding-top:5px;
  padding-bottom:5px;
  
  line-height:30px;
}

.edit-in-place.active input {
  display: inline-block;
  width:500px;
  padding-top:5px;
  padding-bottom:5px;
  height:30px;
  font-size:26px;
  line-height:30px;
  
  background:transparent;
}

JavaScript

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

app.directive( 'editInPlace', function() {
  return {
    restrict: 'E',
    scope: { value: '=' },
    template: '<span ng-click="edit()" ng-bind="value"></span><input ng-model="value"></input>',
    link: function ( $scope, element, attrs ) {
      // Let's get a reference to the input element, as we'll want to reference it.
      var inputElement = angular.element( element.children()[1] );
      
      // This directive should have a set class so we can style it.
      element.addClass( 'edit-in-place' );
      
      // Initially, we're not editing.
      $scope.editing = false;
      
      // ng-click handler to activate edit-in-place
      $scope.edit = function () {
        $scope.editing = true;
        
        // We control display through a class on the directive itself. See the CSS.
        element.addClass( 'active' );
        
        // And we must focus the element. 
        // `angular.element()` provides a chainable array, like jQuery so to access a native DOM function, 
        // we have to reference the first element in the array.
        inputElement[0].focus();
      };
      
      // When we leave the input, we're done editing.
      inputElement.prop( 'onblur', function() {
        $scope.editing = false;
        element.removeClass( 'active' );
      });
    }
  };
});

app.controller('ContactsCtrl', function ( $scope ) {
  $scope.contacts = [
    { name: 'Sharon'},
    { name: 'Steve'}
  ];
});