/** * @license * Copyright Google Inc. All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.io/license */ import {ChangeDetectionStrategy} from '../change_detection/constants'; import {Provider} from '../di'; import {Type} from '../interface/type'; import {compileComponent as render3CompileComponent, compileDirective as render3CompileDirective} from '../render3/jit/directive'; import {compilePipe as render3CompilePipe} from '../render3/jit/pipe'; import {TypeDecorator, makeDecorator, makePropDecorator} from '../util/decorators'; import {noop} from '../util/noop'; import {ViewEncapsulation} from './view'; /** * Type of the Directive decorator / constructor function. * @publicApi */ export interface DirectiveDecorator { /** * Marks a class as an Angular directive. You can define your own * directives to attach custom behavior to elements in the DOM. * The options provide configuration metadata that determines * how the directive should be processed, instantiated and used at * runtime. * * Directive classes, like component classes, can implement * [life-cycle hooks](guide/lifecycle-hooks) to influence their configuration and behavior. * * * @usageNotes * To define a directive, mark the class with the decorator and provide metadata. * * ``` * import {Directive} from '@angular/core'; * * @Directive({ * selector: 'my-directive', * }) * export class MyDirective { * ... * } * ``` * * ### Declaring directives * * Directives are [declarables](guide/glossary#declarable). * They must be declared by an NgModule * in order to be usable in an app. * * A directive must belong to exactly one NgModule. Do not re-declare * a directive imported from another module. * List the directive class in the `declarations` field of an NgModule. * * ``` * declarations: [ * AppComponent, * MyDirective * ], * ``` * * @Annotation */ (obj: Directive): TypeDecorator; /** * See the `Directive` decorator. */ new (obj: Directive): Directive; } /** * Directive decorator and metadata. * * @Annotation * @publicApi */ export interface Directive { /** * The CSS selector that identifies this directive in a template * and triggers instantiation of the directive. * * Declare as one of the following: * * - `element-name`: Select by element name. * - `.class`: Select by class name. * - `[attribute]`: Select by attribute name. * - `[attribute=value]`: Select by attribute name and value. * - `:not(sub_selector)`: Select only if the element does not match the `sub_selector`. * - `selector1, selector2`: Select if either `selector1` or `selector2` matches. * * Angular only allows directives to apply on CSS selectors that do not cross * element boundaries. * * For the following template HTML, a directive with an `input[type=text]` selector, * would be instantiated only on the `` element. * * ```html *
* * * * ``` * */ selector?: string; /** * Enumerates the set of data-bound input properties for a directive * * Angular automatically updates input properties during change detection. * The `inputs` property defines a set of `directiveProperty` to `bindingProperty` * configuration: * * - `directiveProperty` specifies the component property where the value is written. * - `bindingProperty` specifies the DOM property where the value is read from. * * When `bindingProperty` is not provided, it is assumed to be equal to `directiveProperty`. * @usageNotes * * ### Example * * The following example creates a component with two data-bound properties. * * ```typescript * @Component({ * selector: 'bank-account', * inputs: ['bankName', 'id: account-id'], * template: ` * Bank Name: {{bankName}} * Account Id: {{id}} * ` * }) * class BankAccount { * bankName: string; * id: string; * * ``` * */ inputs?: string[]; /** * Enumerates the set of event-bound output properties. * * When an output property emits an event, an event handler attached to that event * in the template is invoked. * * The `outputs` property defines a set of `directiveProperty` to `bindingProperty` * configuration: * * - `directiveProperty` specifies the component property that emits events. * - `bindingProperty` specifies the DOM property the event handler is attached to. * * @usageNotes * * ### Example * * ```typescript * @Directive({ * selector: 'child-dir', * exportAs: 'child' * }) * class ChildDir { * } * * @Component({ * selector: 'main', * template: `` * }) * class MainComponent { * } * ``` * */ outputs?: string[]; /** * Configures the [injector](guide/glossary#injector) of this * directive or component with a [token](guide/glossary#di-token) * that maps to a [provider](guide/glossary#provider) of a dependency. */ providers?: Provider[]; /** * Defines the name that can be used in the template to assign this directive to a variable. * * @usageNotes * * ### Simple Example * * ``` * @Directive({ * selector: 'child-dir', * exportAs: 'child' * }) * class ChildDir { * } * * @Component({ * selector: 'main', * template: `` * }) * class MainComponent { * } * ``` * */ exportAs?: string; /** * Configures the queries that will be injected into the directive. * * Content queries are set before the `ngAfterContentInit` callback is called. * View queries are set before the `ngAfterViewInit` callback is called. * * @usageNotes * * ### Example * * The following example shows how queries are defined * and when their results are available in lifecycle hooks: * * ``` * @Component({ * selector: 'someDir', * queries: { * contentChildren: new ContentChildren(ChildDirective), * viewChildren: new ViewChildren(ChildDirective) * }, * template: '' * }) * class SomeDir { * contentChildren: QueryList, * viewChildren: QueryList * * ngAfterContentInit() { * // contentChildren is set * } * * ngAfterViewInit() { * // viewChildren is set * } * } * ``` * * @Annotation */ queries?: {[key: string]: any}; /** * Maps class properties to host element bindings for properties, * attributes, and events, using a set of key-value pairs. * * Angular automatically checks host property bindings during change detection. * If a binding changes, Angular updates the directive's host element. * * When the key is a property of the host element, the property value is * the propagated to the specified DOM property. * * When the key is a static attribute in the DOM, the attribute value * is propagated to the specified property in the host element. * * For event handling: * - The key is the DOM event that the directive listens to. * To listen to global events, add the target to the event name. * The target can be `window`, `document` or `body`. * - The value is the statement to execute when the event occurs. If the * statement evaluates to `false`, then `preventDefault` is applied on the DOM * event. A handler method can refer to the `$event` local variable. * */ host?: {[key: string]: string}; /** * If true, this directive/component will be skipped by the AOT compiler and so will always be * compiled using JIT. * * This exists to support future Ivy work and has no effect currently. */ jit?: true; } /** * Type of the Directive metadata. * * @publicApi */ export const Directive: DirectiveDecorator = makeDecorator( 'Directive', (dir: Directive = {}) => dir, undefined, undefined, (type: Type, meta: Directive) => SWITCH_COMPILE_DIRECTIVE(type, meta)); /** * Component decorator interface * * @publicApi */ export interface ComponentDecorator { /** * Decorator that marks a class as an Angular component and provides configuration * metadata that determines how the component should be processed, * instantiated, and used at runtime. * * Components are the most basic UI building block of an Angular app. * An Angular app contains a tree of Angular components. * * Angular components are a subset of directives, always associated with a template. * Unlike other directives, only one component can be instantiated per an element in a template. * * A component must belong to an NgModule in order for it to be available * to another component or application. To make it a member of an NgModule, * list it in the `declarations` field of the `NgModule` metadata. * * Note that, in addition to these options for configuring a directive, * you can control a component's runtime behavior by implementing * life-cycle hooks. For more information, see the * [Lifecycle Hooks](guide/lifecycle-hooks) guide. * * @usageNotes * * ### Setting component inputs * * The following example creates a component with two data-bound properties, * specified by the `inputs` value. * * * * * * ### Setting component outputs * * The following example shows two event emitters that emit on an interval. One * emits an output every second, while the other emits every five seconds. * * {@example core/ts/metadata/directives.ts region='component-output-interval'} * * ### Injecting a class with a view provider * * The following simple example injects a class into a component * using the view provider specified in component metadata: * * ``` * class Greeter { * greet(name:string) { * return 'Hello ' + name + '!'; * } * } * * @Directive({ * selector: 'needs-greeter' * }) * class NeedsGreeter { * greeter:Greeter; * * constructor(greeter:Greeter) { * this.greeter = greeter; * } * } * * @Component({ * selector: 'greet', * viewProviders: [ * Greeter * ], * template: `` * }) * class HelloWorld { * } * * ``` * * ### Preserving whitespace * * Removing whitespace can greatly reduce AOT-generated code size and speed up view creation. * As of Angular 6, the default for `preserveWhitespaces` is false (whitespace is removed). * To change the default setting for all components in your application, set * the `preserveWhitespaces` option of the AOT compiler. * * By default, the AOT compiler removes whitespace characters as follows: * * Trims all whitespaces at the beginning and the end of a template. * * Removes whitespace-only text nodes. For example, * * ``` * * ``` * * becomes: * * ``` * * ``` * * * Replaces a series of whitespace characters in text nodes with a single space. * For example, `\n some text\n` becomes ` some text `. * * Does NOT alter text nodes inside HTML tags such as `
` or `