'use strict'; /** * @ngdoc overview * @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:change ng:change} - Executes an expression when the value of an * input widget changes. * * {@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. */ /** * @workInProgress * @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); }; }); /** * @workInProgress * @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[ng\\:repeat-index="0"] input').val()) .toBe('408 555 1212'); expect(element('.doc-example-live li[ng\\:repeat-index="1"] 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[ng\\:repeat-index="2"] 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); 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 the given expression, and to update the text * content whenever the expression's value changes. Usually, you would * just write `{{ expression }}` and let Angular compile it into * `` at bootstrap time. * * @element ANY * @param {expression} expression {@link guide/dev_guide.expressions Expression} to evaluate. * * @example * Enter a name in the Live Preview text box and watch the greeting below it change 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'); var exprFn = parser(expression).statements(); return function(element) { var lastValue = noop, lastError = noop; this.$watch(function(scope) { // TODO(misko): remove error handling https://github.com/angular/angular.js/issues/347 var error, 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); } catch (e) { scope.$service('$exceptionHandler')(e); error = formatError(e); } finally { if (hadOwnElement) { scope.$element = oldElement; } else { delete scope.$element; } } // If we are HTML, then save the raw HTML data so that we don't // recompute sanitization since that is expensive. // TODO: turn this into a more generic way to compute this if ((isHtml = (value instanceof HTML))) value = (html = value).html; if (lastValue === value && lastError == error) return; isDomElement = isElement(value); if (!isHtml && !isDomElement && isObject(value)) { value = toJson(value, true); } if (value != lastValue || error != lastError) { lastValue = value; lastError = error; elementError(element, NG_EXCEPTION, error); if (error) value = error; if (isHtml) { element.html(html.get()); } else if (isDomElement) { element.html(''); element.append(value); } else { element.text(value == undefined ? '' : value); } } }); }; }); 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) { var error, value; try { value = scope.$eval(exp); } catch(e) { scope.$service('$exceptionHandler')(e); error = toJson(e); } elementError(element, NG_EXCEPTION, error); return error ? error : value; } : 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; } /** * @workInProgress * @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; } }); }; }); var REMOVE_ATTRIBUTES = { 'disabled':'disabled', 'readonly':'readOnly', 'checked':'checked', 'selected':'selected', 'multiple':'multiple' }; /** * @workInProgress * @ngdoc directive * @name angular.directive.ng:bind-attr * * @description * The `ng:bind-attr` attribute specifies that * {@link guide/dev_guide.templates.databinding databindings} should be created between element * attributes and given expressions. Unlike `ng:bind` the `ng:bind-attr` contains a JSON key value * pairs representing which attributes need to be mapped to which * {@link guide/dev_guide.expressions expressions}. * * You don't usually write the `ng:bind-attr` in the HTML since embedding * {{expression}} into the attribute directly as the attribute value is * preferred. The attributes get translated into `` at * compile time. * * This HTML snippet is preferred way of working with `ng:bind-attr` *
 *   Google
 * 
* * The above gets translated to bellow during bootstrap time. *
 *   Google
 * 
* * @element ANY * @param {string} attribute_json a JSON key-value pairs representing * the attributes to replace. Each key matches the attribute * which needs to be replaced. Each value is a text template of * the attribute with embedded * {{expression}}s. Any number of * key-value pairs can be specified. * * @example * Try it here: enter text in text box and click Google. Google for: Google 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), specialName = REMOVE_ATTRIBUTES[lowercase(key)]; if (lastValue[key] !== value) { lastValue[key] = value; if (specialName) { if (toBoolean(value)) { element.attr(specialName, specialName); element.attr('ng-' + specialName, value); } else { element.removeAttr(specialName); element.removeAttr('ng-' + specialName); } (element.data($$validate)||noop)(); } else { element.attr(key, value); } } } }); }; }); /** * @workInProgress * @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(); }); }; }); /** * @workInProgress * @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) { var existing = element[0].className + ' '; return function(element) { this.$watch(function(scope) { if (selector(scope.$index)) { var ngClassVal = scope.$eval(element.attr('ng:class')); if (isArray(ngClassVal)) ngClassVal = ngClassVal.join(' '); var value = scope.$eval(expression); if (isArray(value)) value = value.join(' '); if (ngClassVal && ngClassVal !== value) value = value + ' ' + ngClassVal; element[0].className = trim(existing + value); } }); }; }; } /** * @workInProgress * @ngdoc directive * @name angular.directive.ng:class * * @description * The `ng:class` allows you to set CSS class on HTML element * conditionally. * * @element ANY * @param {expression} expression {@link guide/dev_guide.expressions Expression} to eval. * * @example
Sample Text     
it('should check ng:class', function(){ expect(element('.doc-example-live span').attr('className')).not(). toMatch(/ng-input-indicator-wait/); using('.doc-example-live').element(':button:first').click(); expect(element('.doc-example-live span').attr('className')). toMatch(/ng-input-indicator-wait/); using('.doc-example-live').element(':button:last').click(); expect(element('.doc-example-live span').attr('className')).not(). toMatch(/ng-input-indicator-wait/); });
*/ angularDirective("ng:class", ngClass(function(){return true;})); /** * @workInProgress * @ngdoc directive * @name angular.directive.ng:class-odd * * @description * The `ng:class-odd` and `ng:class-even` works exactly as * `ng:class`, except it works in conjunction with `ng:repeat` * and takes affect only on odd (even) rows. * * @element ANY * @param {expression} expression {@link guide/dev_guide.expressions Expression} to eval. Must be * inside `ng:repeat`. * * @example
  1. {{name}}      
it('should check ng:class-odd and ng:class-even', function(){ expect(element('.doc-example-live li:first span').attr('className')). toMatch(/ng-format-negative/); expect(element('.doc-example-live li:last span').attr('className')). toMatch(/ng-input-indicator-wait/); });
*/ angularDirective("ng:class-odd", ngClass(function(i){return i % 2 === 0;})); /** * @workInProgress * @ngdoc directive * @name angular.directive.ng:class-even * * @description * The `ng:class-odd` and `ng:class-even` works exactly as * `ng:class`, except it works in conjunction with `ng:repeat` * and takes affect only on odd (even) rows. * * @element ANY * @param {expression} expression {@link guide/dev_guide.expressions Expression} to eval. Must be * inside `ng:repeat`. * * @example
  1. {{name}}      
it('should check ng:class-odd and ng:class-even', function(){ expect(element('.doc-example-live li:first span').attr('className')). toMatch(/ng-format-negative/); expect(element('.doc-example-live li:last span').attr('className')). toMatch(/ng-input-indicator-wait/); });
*/ angularDirective("ng:class-even", ngClass(function(i){return i % 2 === 1;})); /** * @workInProgress * @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'); }); }; }); /** * @workInProgress * @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' : ''); }); }; }); /** * @workInProgress * @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('red'); 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){ var resetStyle = getStyle(element); this.$watch(function(scope){ var style = scope.$eval(expression) || {}, key, mergedStyle = {}; for(key in style) { if (resetStyle[key] === undefined) resetStyle[key] = ''; mergedStyle[key] = style[key]; } for(key in resetStyle) { mergedStyle[key] = mergedStyle[key] || resetStyle[key]; } element.css(mergedStyle); }); }; }); /** * @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'); });