'use strict'; /** * @ngdoc function * @name angular.directive * @description * * Angular directives create custom attributes for DOM elements. A directive can modify the * behavior of the element in which it is specified. Do not use directives to add elements to the * DOM; instead, use {@link angular.widget widgets} to add DOM elements. * * Following is the list of built-in Angular directives: * * * {@link angular.directive.ng:autobind ng:autobind} - An Angular bootstrap parameter that can * act as a directive. * * {@link angular.directive.ng:bind ng:bind} - Creates a data-binding between an HTML text value * and a data model. * * {@link angular.directive.ng:bind-attr ng:bind-attr} - Creates a data-binding in a way similar * to `ng:bind`, but uses JSON key / value pairs to do so. * * {@link angular.directive.ng:bind-template ng:bind-template} - Replaces the text value of an * element with a specified template. * * {@link angular.directive.ng:class ng:class} - Conditionally set a CSS class on an element. * * {@link angular.directive.ng:class-even ng:class-even} - Like `ng:class`, but works in * conjunction with {@link angular.widget.@ng:repeat} to affect even rows in a collection. * * {@link angular.directive.ng:class-odd ng:class-odd} - Like `ng:class`, but works with {@link * angular.widget.@ng:repeat} to affect odd rows. * * {@link angular.directive.ng:click ng:click} - Executes custom behavior when an element is * clicked. * * {@link angular.directive.ng:controller ng:controller} - Creates a scope object linked to the * DOM element and assigns behavior to the scope. * * {@link angular.directive.ng:hide ng:hide} - Conditionally hides a portion of HTML. * * {@link angular.directive.ng:href ng:href} - Places an href in the Angular namespace. * * {@link angular.directive.ng:init} - Initialization tasks run before a template is executed. * * {@link angular.directive.ng:show ng:show} - Conditionally displays a portion of HTML. * * {@link angular.directive.ng:src ng:src} - Places a `src` attribute into the Angular namespace. * * {@link angular.directive.ng:style ng:style} - Conditionally set CSS styles on an element. * * {@link angular.directive.ng:submit} - Binds Angular expressions to `onSubmit` events. * * For more information about how Angular directives work, and to learn how to create your own * directives, see {@link guide/dev_guide.compiler.directives Understanding Angular Directives} in * the Angular Developer Guide. * * @param {string} name Directive identifier (case insensitive). * @param {function(string, Element)} compileFn Also called "template function" is a function called * during compilation of the template when the compiler comes across the directive being * registered. The string value of the element attribute representing the directive and * jQuery/jqLite wrapped DOM element are passed as arguments to this function. * * The `compileFn` function may return a linking function also called an instance function. * This function is called during the linking phase when a Scope is being associated with the * template or template clone (see repeater notes below). The signature of the linking function * is: `function(Element)` where Element is jQuery/jqLite wrapped DOM Element that is being * linked. * * The biggest differenciator between the compile and linking functions is how they are being called * when a directive is present within an {@link angular.widget.@ng:repeat ng:repeat}. In this case, * the compile function gets called once per occurence of the directive in the template. On the * other hand the linking function gets called once for each repeated clone of the template (times * number of occurences of the directive in the repeated template). */ /** * @ngdoc directive * @name angular.directive.ng:init * * @description * The `ng:init` attribute specifies initialization tasks to be executed * before the template enters execution mode during bootstrap. * * @element ANY * @param {expression} expression {@link guide/dev_guide.expressions Expression} to eval. * * @example
{{greeting}} {{person}}!
it('should check greeting', function() { expect(binding('greeting')).toBe('Hello'); expect(binding('person')).toBe('World'); });
*/ angularDirective("ng:init", function(expression){ return function(element){ this.$eval(expression); }; }); /** * @ngdoc directive * @name angular.directive.ng:controller * * @description * The `ng:controller` directive assigns behavior to a scope. This is a key aspect of how angular * supports the principles behind the Model-View-Controller design pattern. * * MVC components in angular: * * * Model — The Model is data in scope properties; scopes are attached to the DOM. * * View — The template (HTML with data bindings) is rendered into the View. * * Controller — The `ng:controller` directive specifies a Controller class; the class has * methods that typically express the business logic behind the application. * * Note that an alternative way to define controllers is via the `{@link angular.service.$route}` * service. * * @element ANY * @param {expression} expression Name of a globally accessible constructor function or an * {@link guide/dev_guide.expressions expression} that on the current scope evaluates to a * constructor function. * * @example * Here is a simple form for editing user contact information. Adding, removing, clearing, and * greeting are methods declared on the controller (see source tab). These methods can * easily be called from the angular markup. Notice that the scope becomes the `this` for the * controller's instance. This allows for easy access to the view data from the controller. Also * notice that any changes to the data are automatically reflected in the View without the need * for a manual update.
Name: [ greet ]
Contact:
it('should check controller', function() { expect(element('.doc-example-live div>:input').val()).toBe('John Smith'); expect(element('.doc-example-live li:nth-child(1) input').val()) .toBe('408 555 1212'); expect(element('.doc-example-live li:nth-child(2) input').val()) .toBe('john.smith@example.org'); element('.doc-example-live li:first a:contains("clear")').click(); expect(element('.doc-example-live li:first input').val()).toBe(''); element('.doc-example-live li:last a:contains("add")').click(); expect(element('.doc-example-live li:nth-child(3) input').val()) .toBe('yourname@example.org'); });
*/ angularDirective("ng:controller", function(expression){ this.scope(function(scope){ var Controller = getter(scope, expression, true) || getter(window, expression, true); assertArgFn(Controller, expression); inferInjectionArgs(Controller); return Controller; }); return noop; }); /** * @ngdoc directive * @name angular.directive.ng:bind * * @description * The `ng:bind` attribute tells Angular to replace the text content of the specified HTML element * with the value of a given expression, and to update the text content when the value of that * expression changes. * * Typically, you don't use `ng:bind` directly, but instead you use the double curly markup like * `{{ expression }}` and let the Angular compiler transform it to * `` when the template is compiled. * * @element ANY * @param {expression} expression {@link guide/dev_guide.expressions Expression} to evaluate. * * @example * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
Enter name:
Hello !
it('should check ng:bind', function() { expect(using('.doc-example-live').binding('name')).toBe('Whirled'); using('.doc-example-live').input('name').enter('world'); expect(using('.doc-example-live').binding('name')).toBe('world'); });
*/ angularDirective("ng:bind", function(expression, element){ element.addClass('ng-binding'); return ['$exceptionHandler', '$parse', '$element', function($exceptionHandler, $parse, element) { var exprFn = parser(expression), lastValue = Number.NaN; this.$watch(function(scope) { // TODO(misko): remove error handling https://github.com/angular/angular.js/issues/347 var value, html, isHtml, isDomElement, hadOwnElement = scope.hasOwnProperty('$element'), oldElement = scope.$element; // TODO(misko): get rid of $element https://github.com/angular/angular.js/issues/348 scope.$element = element; try { value = exprFn(scope); // If we are HTML than save the raw HTML data so that we don't recompute sanitization since // it is expensive. // TODO(misko): turn this into a more generic way to compute this if ((isHtml = (value instanceof HTML))) value = (html = value).html; if (lastValue === value) return; isDomElement = isElement(value); if (!isHtml && !isDomElement && isObject(value)) { value = toJson(value, true); } if (value != lastValue) { lastValue = value; if (isHtml) { element.html(html.get()); } else if (isDomElement) { element.html(''); element.append(value); } else { element.text(value == undefined ? '' : value); } } } catch (e) { $exceptionHandler(e); } finally { if (hadOwnElement) { scope.$element = oldElement; } else { delete scope.$element; } } }); }]; }); var bindTemplateCache = {}; function compileBindTemplate(template){ var fn = bindTemplateCache[template]; if (!fn) { var bindings = []; forEach(parseBindings(template), function(text){ var exp = binding(text); bindings.push(exp ? function(scope, element) { return scope.$eval(exp); } : function() { return text; }); }); bindTemplateCache[template] = fn = function(scope, element, prettyPrintJson) { var parts = [], hadOwnElement = scope.hasOwnProperty('$element'), oldElement = scope.$element; // TODO(misko): get rid of $element scope.$element = element; try { for (var i = 0; i < bindings.length; i++) { var value = bindings[i](scope, element); if (isElement(value)) value = ''; else if (isObject(value)) value = toJson(value, prettyPrintJson); parts.push(value); } return parts.join(''); } finally { if (hadOwnElement) { scope.$element = oldElement; } else { delete scope.$element; } } }; } return fn; } /** * @ngdoc directive * @name angular.directive.ng:bind-template * * @description * The `ng:bind-template` attribute specifies that the element * text should be replaced with the template in ng:bind-template. * Unlike ng:bind the ng:bind-template can contain multiple `{{` `}}` * expressions. (This is required since some HTML elements * can not have SPAN elements such as TITLE, or OPTION to name a few.) * * @element ANY * @param {string} template of form * {{ expression }} to eval. * * @example * Try it here: enter text in text box and watch the greeting change.
Salutation:
Name:

       
it('should check ng:bind', function() { expect(using('.doc-example-live').binding('{{salutation}} {{name}}')). toBe('Hello World!'); using('.doc-example-live').input('salutation').enter('Greetings'); using('.doc-example-live').input('name').enter('user'); expect(using('.doc-example-live').binding('{{salutation}} {{name}}')). toBe('Greetings user!'); });
*/ angularDirective("ng:bind-template", function(expression, element){ element.addClass('ng-binding'); var templateFn = compileBindTemplate(expression); return function(element) { var lastValue; this.$watch(function(scope) { var value = templateFn(scope, element, true); if (value != lastValue) { element.text(value); lastValue = value; } }); }; }); /** * @ngdoc directive * @name angular.directive.ng:bind-attr * * @description * The `ng:bind-attr` attribute specifies that a * {@link guide/dev_guide.templates.databinding databinding} should be created between a particular * element attribute and a given expression. Unlike `ng:bind`, the `ng:bind-attr` contains one or * more JSON key value pairs; each pair specifies an attribute and the * {@link guide/dev_guide.expressions expression} to which it will be mapped. * * Instead of writing `ng:bind-attr` statements in your HTML, you can use double-curly markup to * specify an {{expression}} for the value of an attribute. * At compile time, the attribute is translated into an * ``. * * The following HTML snippet shows how to specify `ng:bind-attr`: *
 *   Google
 * 
* * This is cumbersome, so as we mentioned using double-curly markup is a prefered way of creating * this binding: *
 *   Google
 * 
* * During compilation, the template with attribute markup gets translated to the ng:bind-attr form * mentioned above. * * _Note_: You might want to consider using {@link angular.directive.ng:href ng:href} instead of * `href` if the binding is present in the main application template (`index.html`) and you want to * make sure that a user is not capable of clicking on raw/uncompiled link. * * * @element ANY * @param {string} attribute_json one or more JSON key-value pairs representing * the attributes to replace with expressions. Each key matches an attribute * which needs to be replaced. Each value is a text template of * the attribute with the embedded * {{expression}}s. Any number of * key-value pairs can be specified. * * @example * Enter a search string in the Live Preview text box and then click "Google". The search executes instantly.
Google for: Google (ng:bind-attr) | Google (curly binding in attribute val)
it('should check ng:bind-attr', function() { expect(using('.doc-example-live').element('a').attr('href')). toBe('http://www.google.com/search?q=AngularJS'); using('.doc-example-live').input('query').enter('google'); expect(using('.doc-example-live').element('a').attr('href')). toBe('http://www.google.com/search?q=google'); });
*/ angularDirective("ng:bind-attr", function(expression){ return function(element){ var lastValue = {}; this.$watch(function(scope){ var values = scope.$eval(expression); for(var key in values) { var value = compileBindTemplate(values[key])(scope, element); if (lastValue[key] !== value) { lastValue[key] = value; element.attr(key, BOOLEAN_ATTR[lowercase(key)] ? toBoolean(value) : value); } } }); }; }); /** * @ngdoc directive * @name angular.directive.ng:click * * @description * The ng:click allows you to specify custom behavior when * element is clicked. * * @element ANY * @param {expression} expression {@link guide/dev_guide.expressions Expression} to evaluate upon * click. * * @example count: {{count}} it('should check ng:click', function() { expect(binding('count')).toBe('0'); element('.doc-example-live :button').click(); expect(binding('count')).toBe('1'); }); */ /* * A directive that allows creation of custom onclick handlers that are defined as angular * expressions and are compiled and executed within the current scope. * * Events that are handled via these handler are always configured not to propagate further. * * TODO: maybe we should consider allowing users to control event propagation in the future. */ angularDirective("ng:click", function(expression, element){ return function(element){ var self = this; element.bind('click', function(event){ self.$apply(expression); event.stopPropagation(); }); }; }); /** * @ngdoc directive * @name angular.directive.ng:submit * * @description * Enables binding angular expressions to onsubmit events. * * Additionally it prevents the default action (which for form means sending the request to the * server and reloading the current page). * * @element form * @param {expression} expression {@link guide/dev_guide.expressions Expression} to eval. * * @example
Enter text and hit enter:
list={{list}}
it('should check ng:submit', function() { expect(binding('list')).toBe('list=[]'); element('.doc-example-live #submit').click(); expect(binding('list')).toBe('list=["hello"]'); });
*/ angularDirective("ng:submit", function(expression, element) { return function(element) { var self = this; element.bind('submit', function(event) { self.$apply(expression); event.preventDefault(); }); }; }); function ngClass(selector) { return function(expression, element) { return function(element) { this.$watch(expression, function(scope, newVal, oldVal) { if (selector(scope.$index)) { if (oldVal) element.removeClass(isArray(oldVal) ? oldVal.join(' ') : oldVal); if (newVal) element.addClass(isArray(newVal) ? newVal.join(' ') : newVal); } }); }; }; } /** * @ngdoc directive * @name angular.directive.ng:class * * @description * The `ng:class` allows you to set CSS class on HTML element dynamically by databinding an * expression that represents all classes to be added. * * The directive won't add duplicate classes if a particular class was already set. * * When the expression changes, the previously added classes are removed and only then the classes * new classes are added. * * @element ANY * @param {expression} expression {@link guide/dev_guide.expressions Expression} to eval. The result * of the evaluation can be a string representing space delimited class names or an array. * * @example
Sample Text     
it('should check ng:class', function() { expect(element('.doc-example-live span').prop('className')).not(). toMatch(/ng-input-indicator-wait/); using('.doc-example-live').element(':button:first').click(); expect(element('.doc-example-live span').prop('className')). toMatch(/ng-input-indicator-wait/); using('.doc-example-live').element(':button:last').click(); expect(element('.doc-example-live span').prop('className')).not(). toMatch(/ng-input-indicator-wait/); });
*/ angularDirective("ng:class", ngClass(function() {return true;})); /** * @ngdoc directive * @name angular.directive.ng:class-odd * * @description * The `ng:class-odd` and `ng:class-even` works exactly as * {@link angular.directive.ng:class ng:class}, except it works in conjunction with `ng:repeat` and * takes affect only on odd (even) rows. * * This directive can be applied only within a scope of an * {@link angular.widget.@ng:repeat ng:repeat}. * * @element ANY * @param {expression} expression {@link guide/dev_guide.expressions Expression} to eval. The result * of the evaluation can be a string representing space delimited class names or an array. * * @example
  1. {{name}}      
it('should check ng:class-odd and ng:class-even', function() { expect(element('.doc-example-live li:first span').prop('className')). toMatch(/ng-format-negative/); expect(element('.doc-example-live li:last span').prop('className')). toMatch(/ng-input-indicator-wait/); });
*/ angularDirective("ng:class-odd", ngClass(function(i){return i % 2 === 0;})); /** * @ngdoc directive * @name angular.directive.ng:class-even * * @description * The `ng:class-odd` and `ng:class-even` works exactly as * {@link angular.directive.ng:class ng:class}, except it works in conjunction with `ng:repeat` and * takes affect only on odd (even) rows. * * This directive can be applied only within a scope of an * {@link angular.widget.@ng:repeat ng:repeat}. * * @element ANY * @param {expression} expression {@link guide/dev_guide.expressions Expression} to eval. The result * of the evaluation can be a string representing space delimited class names or an array. * * @example
  1. {{name}}      
it('should check ng:class-odd and ng:class-even', function() { expect(element('.doc-example-live li:first span').prop('className')). toMatch(/ng-format-negative/); expect(element('.doc-example-live li:last span').prop('className')). toMatch(/ng-input-indicator-wait/); });
*/ angularDirective("ng:class-even", ngClass(function(i){return i % 2 === 1;})); /** * @ngdoc directive * @name angular.directive.ng:show * * @description * The `ng:show` and `ng:hide` directives show or hide a portion of the DOM tree (HTML) * conditionally. * * @element ANY * @param {expression} expression If the {@link guide/dev_guide.expressions expression} is truthy * then the element is shown or hidden respectively. * * @example Click me:
Show: I show up when your checkbox is checked.
Hide: I hide when your checkbox is checked.
it('should check ng:show / ng:hide', function() { expect(element('.doc-example-live span:first:hidden').count()).toEqual(1); expect(element('.doc-example-live span:last:visible').count()).toEqual(1); input('checked').check(); expect(element('.doc-example-live span:first:visible').count()).toEqual(1); expect(element('.doc-example-live span:last:hidden').count()).toEqual(1); });
*/ angularDirective("ng:show", function(expression, element){ return function(element){ this.$watch(expression, function(scope, value){ element.css('display', toBoolean(value) ? '' : 'none'); }); }; }); /** * @ngdoc directive * @name angular.directive.ng:hide * * @description * The `ng:hide` and `ng:show` directives hide or show a portion * of the HTML conditionally. * * @element ANY * @param {expression} expression If the {@link guide/dev_guide.expressions expression} truthy then * the element is shown or hidden respectively. * * @example Click me:
Show: I show up when you checkbox is checked?
Hide: I hide when you checkbox is checked?
it('should check ng:show / ng:hide', function() { expect(element('.doc-example-live span:first:hidden').count()).toEqual(1); expect(element('.doc-example-live span:last:visible').count()).toEqual(1); input('checked').check(); expect(element('.doc-example-live span:first:visible').count()).toEqual(1); expect(element('.doc-example-live span:last:hidden').count()).toEqual(1); });
*/ angularDirective("ng:hide", function(expression, element){ return function(element){ this.$watch(expression, function(scope, value){ element.css('display', toBoolean(value) ? 'none' : ''); }); }; }); /** * @ngdoc directive * @name angular.directive.ng:style * * @description * The ng:style allows you to set CSS style on an HTML element conditionally. * * @element ANY * @param {expression} expression {@link guide/dev_guide.expressions Expression} which evals to an * object whose keys are CSS style names and values are corresponding values for those CSS * keys. * * @example
Sample Text
myStyle={{myStyle}}
it('should check ng:style', function() { expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)'); element('.doc-example-live :button[value=set]').click(); expect(element('.doc-example-live span').css('color')).toBe('rgb(255, 0, 0)'); element('.doc-example-live :button[value=clear]').click(); expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)'); });
*/ angularDirective("ng:style", function(expression, element) { return function(element) { this.$watch(expression, function(scope, newStyles, oldStyles) { if (oldStyles) forEach(oldStyles, function(val, style) { element.css(style, '');}); if (newStyles) element.css(newStyles); }); }; }); /** * @ngdoc directive * @name angular.directive.ng:cloak * * @description * The `ng:cloak` directive is used to prevent the Angular html template from being briefly * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this * directive to avoid the undesirable flicker effect caused by the html template display. * * The directive can be applied to the `` element, but typically a fine-grained application is * prefered in order to benefit from progressive rendering of the browser view. * * `ng:cloak` works in cooperation with a css rule that is embedded within `angular.js` and * `angular.min.js` files. Following is the css rule: * *
 * [ng\:cloak], .ng-cloak {
 *   display: none;
 * }
 * 
* * When this css rule is loaded by the browser, all html elements (including their children) that * are tagged with the `ng:cloak` directive are hidden. When Angular comes across this directive * during the compilation of the template it deletes the `ng:cloak` element attribute, which * makes the compiled element visible. * * For the best result, `angular.js` script must be loaded in the head section of the html file; * alternatively, the css rule (above) must be included in the external stylesheet of the * application. * * Legacy browsers, like IE7, do not provide attribute selector support (added in CSS 2.1) so they * cannot match the `[ng\:cloak]` selector. To work around this limitation, you must add the css * class `ng-cloak` in addition to `ng:cloak` directive as shown in the example below. * * @element ANY * * @example
{{ 'hello' }}
{{ 'hello IE7' }}
it('should remove the template directive and css class', function() { expect(element('.doc-example-live #template1').attr('ng:cloak')). not().toBeDefined(); expect(element('.doc-example-live #template2').attr('ng:cloak')). not().toBeDefined(); });
* */ angularDirective("ng:cloak", function(expression, element) { element.removeAttr('ng:cloak'); element.removeClass('ng-cloak'); });