<!DOCTYPE html>
<html>

  <head>
    <script data-require="angular.js@1.4.0-beta.6" data-semver="1.4.0-beta.6" src="https://code.angularjs.org/1.4.0-beta.6/angular.js"></script>
    <script data-require="lodash.js@*" data-semver="3.5.0" src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body>
    <user-greeting></user-greeting>
    
    <p>
      <small>Double-click on the name above. Hit Enter to save changes.</small>
    </p>
  </body>

</html>
var m = angular.module('example', []);

// Fake service.
m.service('userService', function ($q) {
  this.get = function () {
    var deferred = $q.defer();
    deferred.resolve({name: 'Bob'});
    return deferred.promise;
  };
  
  this.save = function (userData) {
    var deferred = $q.defer();
    deferred.resolve(userData);
    return deferred.promise;
  };
});

// The container component that talks to userService.
m.directive('userGreeting', function () {
  return {
    template: '<user-greeting-message user="ctrl.user" ' +
                'on-save="ctrl.handleSave(user)"></user-gretting-message>',
    controller: function (userService) {
      this.userService = userService;
  
      // Data fetching, same as before.
      this.userService.get().then((function (user) {
        this.user = user;
      }).bind(this));
      
      this.handleSave = function (user) {
        this.userService.save(user).then((function (data) {
          this.user = data;
        }).bind(this));
      };
    },
    bindToController: true,
    controllerAs: 'ctrl'
  };
});

// The UI component that renders UI based on the user data passed into it.
m.directive('userGreetingMessage', function () {
  return {
    scope: {
      user: '=',
      saveCallback: '&onSave'
    },
    template: '<p>Hello ' +
      '<editable-user-name ' +
        'user="ctrl.user" ' +
        'on-save="ctrl.handleSave(user)">' +
      '</editable-user-name></p>',
    controller: function () {
      this.handleSave = function (user) {
        this.saveCallback({user: user});
      }
    },
    bindToController: true,
    controllerAs: 'ctrl'
  };
});

m.directive('editableUserName', function () {
  return {
    scope: {
      user: '=',
      saveCallback: '&onSave'
    },
    template: 
      '<span>' +
        '<span class="view" ng-dblclick="ctrl.edit()" ng-show="!ctrl.isEditing()">' +
          '{{ ctrl.user.name }}' +
        '</span>' +
        '<form ng-submit="ctrl.handleSave()">' +
          '<input ng-show="ctrl.isEditing()" ng-model="ctrl.userForm.name" ng-blur="ctrl.reset()" />' +
        '</form>' +
      '</span>'
    ,
    controller: function ($element) {
      this.edit = function () {
        this.userForm = _.extend({}, this.user);
        
        setTimeout(function(){
          $element.find('input')[0].focus();
        }, 10);
      };
  
      this.reset = function () {
        this.userForm = null;  
      };
      
      this.isEditing = function () {
        return !!this.userForm;
      };
  
      this.handleSave = function () {
        // Invoke callback from container.
        this.saveCallback({user: this.userForm});
        
        // Null out form to force use back to view mode.
        this.reset();
      };
    },
    bindToController: true,
    controllerAs: 'ctrl'
  };
});

angular.element(document).ready(function() {
  angular.bootstrap(document, ['example']);
});
body {
  font-family: "Helvetica Neue", Arial, sans-serif;
}

form {
  display: inline;
}

.view {
  border-bottom: 1px dashed black;
}