From 2f96fbd17577685bc013a4f7ced06664af253944 Mon Sep 17 00:00:00 2001
From: Oren Avissar
Date: Thu, 4 Apr 2013 18:17:58 -0700
Subject: feat(ngIf): add directive to remove and recreate DOM elements
This directive is adapted from ui-if in the AngularUI project and provides a complement
to the ngShow/ngHide directives that only change the visibility of the DOM element and
ngSwitch which does change the DOM but is more verbose.
---
angularFiles.js | 1 +
src/AngularPublic.js | 1 +
src/ng/directive/ngIf.js | 83 ++++++++++++++++++
test/ng/directive/ngIfSpec.js | 191 ++++++++++++++++++++++++++++++++++++++++++
4 files changed, 276 insertions(+)
mode change 100644 => 100755 angularFiles.js
mode change 100644 => 100755 src/AngularPublic.js
create mode 100755 src/ng/directive/ngIf.js
create mode 100755 test/ng/directive/ngIfSpec.js
diff --git a/angularFiles.js b/angularFiles.js
old mode 100644
new mode 100755
index 30c65df1..2c2e4e0c
--- a/angularFiles.js
+++ b/angularFiles.js
@@ -49,6 +49,7 @@ angularFiles = {
'src/ng/directive/ngController.js',
'src/ng/directive/ngCsp.js',
'src/ng/directive/ngEventDirs.js',
+ 'src/ng/directive/ngIf.js',
'src/ng/directive/ngInclude.js',
'src/ng/directive/ngInit.js',
'src/ng/directive/ngNonBindable.js',
diff --git a/src/AngularPublic.js b/src/AngularPublic.js
old mode 100644
new mode 100755
index a66c35b3..1fd18ce2
--- a/src/AngularPublic.js
+++ b/src/AngularPublic.js
@@ -82,6 +82,7 @@ function publishExternalAPI(angular){
ngController: ngControllerDirective,
ngForm: ngFormDirective,
ngHide: ngHideDirective,
+ ngIf: ngIfDirective,
ngInclude: ngIncludeDirective,
ngInit: ngInitDirective,
ngNonBindable: ngNonBindableDirective,
diff --git a/src/ng/directive/ngIf.js b/src/ng/directive/ngIf.js
new file mode 100755
index 00000000..f1ceccda
--- /dev/null
+++ b/src/ng/directive/ngIf.js
@@ -0,0 +1,83 @@
+'use strict';
+
+/**
+ * @ngdoc directive
+ * @name ng.directive:ngIf
+ * @restrict A
+ *
+ * @description
+ * The `ngIf` directive removes and recreates a portion of the DOM tree (HTML)
+ * conditionally based on **"falsy"** and **"truthy"** values, respectively, evaluated within
+ * an {expression}. In other words, if the expression assigned to **ngIf evaluates to a false
+ * value** then **the element is removed from the DOM** and **if true** then **a clone of the
+ * element is reinserted into the DOM**.
+ *
+ * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
+ * element in the DOM rather than changing its visibility via the `display` css property. A common
+ * case when this difference is significant is when using css selectors that rely on an element's
+ * position within the DOM (HTML), such as the `:first-child` or `:last-child` pseudo-classes.
+ *
+ * Note that **when an element is removed using ngIf its scope is destroyed** and **a new scope
+ * is created when the element is restored**. The scope created within `ngIf` inherits from
+ * its parent scope using
+ * {@link https://github.com/angular/angular.js/wiki/The-Nuances-of-Scope-Prototypal-Inheritance prototypal inheritance}.
+ * An important implication of this is if `ngModel` is used within `ngIf` to bind to
+ * a javascript primitive defined in the parent scope. In this case any modifications made to the
+ * variable within the child scope will override (hide) the value in the parent scope.
+ *
+ * Also, `ngIf` recreates elements using their compiled state. An example scenario of this behavior
+ * is if an element's class attribute is directly modified after it's compiled, using something like
+ * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
+ * the added class will be lost because the original compiled state is used to regenerate the element.
+ *
+ * Additionally, you can provide animations via the ngAnimate attribute to animate the **enter**
+ * and **leave** effects.
+ *
+ * @animations
+ * enter - happens just after the ngIf contents change and a new DOM element is created and injected into the ngIf container
+ * leave - happens just before the ngIf contents are removed from the DOM
+ *
+ * @element ANY
+ * @scope
+ * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
+ * the element is removed from the DOM tree (HTML).
+ *
+ * @example
+
+
+ Click me:
+ Show when checked: I'm removed when the checkbox is unchecked
+
+
+ */
+var ngIfDirective = ['$animator', function($animator) {
+ return {
+ transclude: 'element',
+ priority: 1000,
+ terminal: true,
+ restrict: 'A',
+ compile: function (element, attr, transclude) {
+ return function ($scope, $element, $attr) {
+ var animate = $animator($scope, $attr);
+ var childElement, childScope;
+ $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
+ if (childElement) {
+ animate.leave(childElement);
+ childElement = undefined;
+ }
+ if (childScope) {
+ childScope.$destroy();
+ childScope = undefined;
+ }
+ if (toBoolean(value)) {
+ childScope = $scope.$new();
+ transclude(childScope, function (clone) {
+ childElement = clone;
+ animate.enter(clone, $element.parent(), $element);
+ });
+ }
+ });
+ }
+ }
+ }
+}];
diff --git a/test/ng/directive/ngIfSpec.js b/test/ng/directive/ngIfSpec.js
new file mode 100755
index 00000000..081ba5bf
--- /dev/null
+++ b/test/ng/directive/ngIfSpec.js
@@ -0,0 +1,191 @@
+'use strict';
+
+describe('ngIf', function () {
+ var $scope, $compile, element;
+
+ beforeEach(inject(function ($rootScope, _$compile_) {
+ $scope = $rootScope.$new();
+ $compile = _$compile_;
+ element = $compile('