<!DOCTYPE html>
<html ng-app="views-directive">

  <head>
    <script data-require="jquery@*" data-semver="2.0.3" src="http://code.jquery.com/jquery-2.0.3.min.js"></script>
    <script data-require="angular.js@*" data-semver="1.2.9" src="http://code.angularjs.org/1.2.9/angular.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular-animate.js"></script>
    
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body>
    <h1>AngularJS Directives Example</h1>
    <views>
      <view name="show" initial>
        <p>Hi, {{ user.name }}</p>
        <button view-target="edit">
          Edit
        </button>
      </view>
      <view name="edit">
        <p>
          <input ng-model="user.name" />
        </p>
        <button view-target="show">
          Done
        </button>
      </view>
    </views>
  </body>
</html>
var m = angular.module('views-directive', ['ngAnimate']);

m.directive('views', function() {
  return {
    restrict: 'E',
    controller: function() {
      var views = {};
      
      this.$addView = function(ctrl) {
        views[ctrl.$name] = ctrl;
      };
      
      this.$switchTo = function(viewName) {
        for (var k in views) {
          if (k == viewName) {
            views[k].$show();
          } else {
            views[k].$hide();
          }
        }
      };
    },
    link: function(scope, el, attrs, viewsCtrl) {
      el.on('click', '[view-target]', function() {
        var viewName = angular.element(this).attr('view-target')
        viewsCtrl.$switchTo(viewName);
      });
      
      // Make the view controls available on the scope
      scope.$views = viewsCtrl;
    }
  };
});

m.directive('view', function($animate) {
  return {
    restrict: 'E',
    require: ['view', '^views'],
    controller: function($element, $attrs) {
      this.$name = $attrs.name;
      this.$show = function() { $animate.removeClass($element, 'view-hide'); }
      this.$hide = function() { $animate.addClass($element, 'view-hide'); }
    },
    link: function(scope, el, attrs, ctrls) {
      var viewCtrl = ctrls[0];
      var viewsCtrl = ctrls[1];
      
      viewsCtrl.$addView(viewCtrl);
    
      if (attrs.initial !== undefined) {
        viewCtrl.$show();
      } else {
        viewCtrl.$hide();
      }
    }
  };
});
views {
  position: relative;
}

view {
  position: absolute;
  top: 0;
  width: 500px;
}
  
view.view-hide-remove,
view.view-hide-add {
  display: block!important;
}

view.view-hide-add {
  -webkit-animation: .3s hide;
  animation: .3s hide;
}
view.view-hide-remove {
  -webkit-animation: .3s show;
  animation: .3s show;
}

view.view-hide {
  display: none;
}

@keyframes hide {
  from { opacity:1; }
  to { opacity:0; }
}

@-webkit-keyframes hide {
  from { opacity:1; }
  to { opacity:0; }
}

@keyframes show {
  from { opacity:0; }
  to { opacity:1; }
}

@-webkit-keyframes show {
  from { opacity:0; }
  to { opacity:1; }
}