Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

In an effort to learn more about AngularJS directives, I decided to create a simple, edit-in-place directive. I built a simple directive that would display a value, along with an edit link and the edit link would toggle visibility of an input and the save/cancel links. From there, I wanted a setup where I could make multiple properties of an object editable, and I wanted to share the link controls and trigger updates to each property together.

I decided to create a wrapper directive to handle the links and ended up with a working version in which I ended up broadcasting events from the parent(wrapper) directive and taking action in the nested directives based on that. I feel like there is probably a better approach, but this is what I was able to make work.

The HTML:

<html ng-app="editInPlaceApp">
<head>
    <script data-require="angular.js@*" data-semver="1.3.6" src="https://code.angularjs.org/1.3.6/angular.js"></script>
    <link rel="stylesheet" href="style.css" />

  </head>

  <body>
    <div ng-controller="MainController">
      <ul>
        <li ng-repeat="p in people">
          <wrap-in-place>
            <value-in-place value="p.fname"></value-in-place>
            <value-in-place value="p.lname"></value-in-place>
          </wrap-in-place>
        </li>
      </ul>
    </div>

    <script src="script.js"></script>
  </body>

</html>

The JavaScript:

  var app = angular.module('editInPlaceApp',['myDirectives']);
  app.controller('MainController', ['$scope', 'PersonService', function($scope, PersonService){
    $scope.people = PersonService.loadPeople();
  }])
  .factory('PersonService', function(){
    var factory = {};

    factory.loadPeople = function(){
      var peeps = [{"id":"abc0", fname:"John", lname:"Doe"},
        {"id":"abc1", fname:"Jane", lname:"Smith"},
        {"id":"abc2", fname:"Bob", lname:"Jones"}];

      return peeps;
    };

    return factory;
  });

  angular.module('myDirectives',[])
  .directive('wrapInPlace', function(){
    return {
      restrict: 'E',
      transclude: true,
      scope:true,
      template: '<span ng-transclude></span> <a href="#" ng-click="edit()" ng-show="!editChildren">edit</a> <span ng-show="editChildren"><a href="#" ng-click="saveChildren()">save</a> <a href="#" ng-click="cancel()">cancel</a></span>',
      link: function($scope, element, attrs){
        $scope.edit = function(){
          $scope.editChildren = true;
          $scope.$broadcast('editChildren',{"val":$scope.editChildren});
        };

        $scope.cancel = function(){
          $scope.editChildren = false;
          $scope.$broadcast('editChildren',{"val":$scope.editChildren});
        };

        $scope.saveChildren = function(){
          $scope.editChildren = false;
          $scope.$broadcast('saveChildren');
        };
      }
    };
  })
  .directive('valueInPlace', function(){
    return {
      restrict: 'E',
      scope: {
        value: '='
      },
      template: '<span ng-show="!editing">{{value}}</span><input type="text" ng-model="updatedValue" ng-show="editing">',
      link: function ( $scope, element, attrs ) {
        $scope.editing = false;
        $scope.updatedValue = $scope.value;

        $scope.$on('editChildren', function(event, args){
          $scope.editing = args.val;
          if(!args.val){
            $scope.updatedValue = $scope.value;
          }
        });

        $scope.$on('saveChildren', function(event, args){
          $scope.editing = false;
          $scope.value = $scope.updatedValue;
        });

      }
    };
  });

The full working example can be found here.

share|improve this question

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.