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. --- src/AngularPublic.js | 1 + src/ng/directive/ngIf.js | 83 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+) mode change 100644 => 100755 src/AngularPublic.js create mode 100755 src/ng/directive/ngIf.js (limited to 'src') 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); + }); + } + }); + } + } + } +}]; -- cgit v1.2.3