2016-03-16 12:01:33 -04:00
include ../../../../_includes/_util-fns
:marked
2016-09-19 23:24:40 -04:00
Everything that we can do in Angular in TypeScript, we can also do
2016-03-16 12:01:33 -04:00
in JavaScript. Translating from one language to the other is mostly a
matter of changing the way we organize our code and the way we access
2016-09-19 23:24:40 -04:00
Angular APIs.
2016-03-16 12:01:33 -04:00
2016-09-19 23:24:40 -04:00
Since TypeScript is a popular language option in Angular, many of the
2016-03-16 12:01:33 -04:00
code examples you see on the Internet as well as on this site are written
in TypeScript. This cookbook contains recipes for translating these kinds of
2016-09-19 23:24:40 -04:00
code examples to ES5, so that they can be applied to Angular JavaScript
2016-03-16 12:01:33 -04:00
applications.
<a id="toc"></a>
:marked
## Table of contents
[Modularity: imports and exports](#modularity)
[Classes and Class Metadata](#class-metadata)
[Input and Output Metadata](#property-metadata)
[Dependency Injection](#dependency-injection)
[Host and Query Metadata](#other-property-metadata)
2016-07-30 22:00:52 -04:00
**Run and compare the live <live-example name="cb-ts-to-js">TypeScript</live-example> and <live-example name="cb-ts-to-js" lang="js">JavaScript</live-example>
code shown in this cookbook.**
2016-03-16 12:01:33 -04:00
a(id="modularity")
.l-main-section
:marked
## Importing and Exporting
- var top="vertical-align:top"
table(width="100%")
col(width="50%")
col(width="50%")
tr
th TypeScript
th ES5 JavaScript
tr(style=top)
td
:marked
2016-09-19 23:24:40 -04:00
### Importing Angular Code
2016-03-16 12:01:33 -04:00
2016-09-19 23:24:40 -04:00
In TypeScript code, Angular classes, functions, and other members
2016-03-16 12:01:33 -04:00
are imported with TypeScript `import` statements:
+makeExample('cb-ts-to-js/ts/app/main.ts', 'ng2import')(format="." )
td
:marked
2016-09-19 23:24:40 -04:00
### Accessing Angular Code through the ng global
2016-03-16 12:01:33 -04:00
In JavaScript code, when using
2016-09-19 23:24:40 -04:00
[the Angular packages](../glossary.html#!#scoped-package),
2016-03-16 12:01:33 -04:00
we can access Angular code through the global `ng` object. In the
nested members of this object we'll find everything we would import
2016-09-19 23:18:20 -04:00
from `@angular` in TypeScript:
2016-03-16 12:01:33 -04:00
+makeExample('cb-ts-to-js/js/app/main.js', 'ng2import')(format="." )
tr(style=top)
td
:marked
### Importing and Exporting Application Code
2016-09-19 23:24:40 -04:00
Each file in an Angular TypeScript application constitutes a
2016-03-16 12:01:33 -04:00
TypeScript module. When we want to make something from a module available
to other modules, we `export` it.
+makeExample('cb-ts-to-js/ts/app/hero.component.ts', 'appexport')(format="." )
:marked
In other modules we can then `import` things that have been exported
elsewhere.
+makeExample('cb-ts-to-js/ts/app/main.ts', 'appimport')(format="." )
td
:marked
### Sharing Application Code
2016-09-19 23:24:40 -04:00
In an Angular JavaScript application, we load each file to the page
2016-03-16 12:01:33 -04:00
using a `<script>` tag. Each file can make things available to other
files via the shared global `window` scope.
We often introduce an application namespace
object (such as `"app"`) onto `window` and attach everything we need
to share to that namespace object.
We also wrap our code in an
[Immediately Invoked Function Expression (IIFE)](https://en.wikipedia.org/wiki/Immediately-invoked_function_expression).
These practices together prevent our code from
polluting the global scope.
+makeExample('cb-ts-to-js/js/app/hero.component.js', 'appexport')(format="." )
:marked
We can then access anything from this shared namespace in
other files.
+makeExample('cb-ts-to-js/js/app/main.js', 'appimport')(format="." )
:marked
Note that the order of `<script>` tags on the page is significant.
We must load a file that defines a shared member before
a file that uses that member.
.alert.is-helpful
:marked
Alternatively, we can use a module loader such as Webpack or
2016-09-19 23:24:40 -04:00
Browserify in an Angular JavaScript project. In such a project, we would
use CommonJS modules and the `require` function to load Angular framework code.
2016-03-16 12:01:33 -04:00
We would then use `module.exports` and `require` to export and import application
code.
a(id="class-metadata")
.l-main-section
:marked
## Classes and Class Metadata
- var top="vertical-align:top"
table(width="100%")
col(width="50%")
col(width="50%")
tr
th TypeScript
th ES5 JavaScript
tr(style=top)
td
:marked
### Classes
2016-09-19 23:24:40 -04:00
We put most of our Angular TypeScript code into TypeScript classes.
2016-03-16 12:01:33 -04:00
+makeExample('cb-ts-to-js/ts/app/hero.component.ts', 'class')(format="." )
td
:marked
### Constructors and Prototypes
ES5 JavaScript has no classes. We use the constructor
2016-09-19 23:24:40 -04:00
pattern instead which works with Angular as well as classes do.
2016-03-16 12:01:33 -04:00
+makeExample('cb-ts-to-js/js/app/hero.component.js', 'constructorproto')(format="." )
tr(style=top)
td
:marked
### Metadata with Decorators
2016-09-19 23:24:40 -04:00
Most Angular classes have one or more TypeScript *decorators*
2016-03-16 12:01:33 -04:00
attached to provide configuration and metadata. For example,
2016-06-21 10:22:38 -04:00
a component must have a [`@Component`](../api/core/index/Component-decorator.html) decorator.
2016-03-16 12:01:33 -04:00
+makeExample('cb-ts-to-js/ts/app/hero.component.ts', 'metadata')(format="." )
td
:marked
### Metadata with the Annotations Array
In JavaScript, we can attach an `annotations` array to a constructor
to provide metadata.
Each item in the array corresponds to a TypeScript decorator.
In the following example, we create a new instance of `Component` that corresponds
2016-06-21 10:22:38 -04:00
to the [`@Component`](../api/core/index/Component-decorator.html) TypeScript decorator.
2016-03-16 12:01:33 -04:00
+makeExample('cb-ts-to-js/js/app/hero.component.js', 'metadata')(format="." )
:marked
### Metadata with The Class Convenience API
The pattern of creating a constructor and decorating it with metadata
is so common that Angular provides an alternative convenience API for it.
This API lets us define everything in a single expression.
With this API we first call the `ng.core.Component` function,
followed by a chained `Class` method call. The argument to `Class`
is an object that defines the constructor and the instance methods
of the component:
+makeExample('cb-ts-to-js/js/app/hero-dsl.component.js', 'component')(format="." )
:marked
Similar APIs are also available for other decorators. You can define a
directive:
code-example.
var MyDirective = ng.core.Directive({
...
}).Class({
...
});
:marked
Or a pipe:
code-example.
var MyPipe = ng.core.Pipe({
name: 'myPipe'
}).Class({
...
});
tr(style=top)
td
:marked
### Interfaces
When defining classes that need to implement a certain method, it
is common to use TypeScript interfaces that enforce that the
method signature is correct. Component lifecycle methods like `ngOnInit`
are one example of this pattern. `ngOnInit` is defined in the `OnInit`
interface.
+makeExample('cb-ts-to-js/ts/app/hero-lifecycle.component.ts')(format="." )
td
:marked
### Implementing Methods without Interfaces
TypeScript interfaces are purely for developer convenience
2016-09-19 23:24:40 -04:00
and are not used by Angular at runtime. This means that in JavaScript
2016-03-16 12:01:33 -04:00
code we don't need to substitute anything for interfaces. We can just
implement the methods.
+makeExample('cb-ts-to-js/js/app/hero-lifecycle.component.js')(format="." )
a(id="property-metadata")
.l-main-section
:marked
## Input and Output Metadata
- var top="vertical-align:top"
table(width="100%")
col(width="50%")
col(width="50%")
tr
th TypeScript
th ES5 JavaScript
tr(style=top)
td
:marked
### Input and Output Decorators
In TypeScript, property decorators are often used to provide additional metadata
for components and directives.
For [inputs and outputs](../guide/template-syntax.html#inputs-outputs),
2016-06-21 10:22:38 -04:00
we use [`@Input`](../api/core/index/Input-var.html)
and [`@Output`](../api/core/index/Output-var.html) property decorators.
2016-03-16 12:01:33 -04:00
They may optionally specify input and output binding names if we want them to be
different from the class property names.
+makeExample('cb-ts-to-js/ts/app/hero-io.component.ts')(format="." )
.alert.is-helpful
:marked
In TypeScript we can also use the `inputs` and `outputs` array metadata
instead of the `@Input` and `@Output` property decorators.
td
:marked
### Inputs and Outputs in Component Metadata
There is no equivalent of a property decorator in ES5 JavaScript. Instead,
we add comparable information to the `Component` (or `Directive`) metadata.
In this example, we add `inputs` and `outputs` array attributes
containing the input and output property names.
If we need a binding name that is different from the
property itself, we use the `propertyName: bindingName` syntax.
+makeExample('cb-ts-to-js/js/app/hero-io.component.js')(format="." )
.l-main-section
:marked
## Dependency Injection
- var top="vertical-align:top"
table(width="100%")
col(width="50%")
col(width="50%")
tr
th TypeScript
th ES5 JavaScript
tr(style=top)
td
:marked
### Injection by Type
2016-09-19 23:24:40 -04:00
Angular can often use TypeScript type information to
2016-03-16 12:01:33 -04:00
determine what needs to be injected.
+makeExample('cb-ts-to-js/ts/app/hero-di.component.ts')(format="." )
td
:marked
### Injection with Parameter Tokens
Since no type information is available in ES5 JavaScript,
we must identify "injectables" in some other way.
We attach a `parameters` array to the constructor function.
Each array item is the dependency injection token that identifies the thing to be injected.
Often the token is the constructor function for the class-like dependency.
+makeExample('cb-ts-to-js/js/app/hero-di.component.js')(format="." )
:marked
When using the class convenience API, we can also supply the parameter
tokens by wrapping the constructor in an array.
+makeExample('cb-ts-to-js/js/app/hero-di-inline.component.js')(format="." )
tr(style=top)
td
:marked
### Injection with the @Inject decorator
When the thing being injected doesn't correspond directly to a type,
we use the `@Inject()` decorator to supply the injection token.
In this example, we're injecting a string identified by the "heroName" token.
+makeExample('cb-ts-to-js/ts/app/hero-di-inject.component.ts')(format="." )
td
:marked
### Injection with plain string tokens
In JavaScript we add the token string to the injection parameters array.
+makeExample('cb-ts-to-js/js/app/hero-di-inject.component.js','parameters')(format="." )
:marked
Alternatively, we can create a token with the `Inject` method and
add that to the constructor array in the annotations like this:
+makeExample('cb-ts-to-js/js/app/hero-di-inject.component.js','ctor')(format="." )
tr(style=top)
td
:marked
### Additional Injection Decorators
We can attach additional decorators to constructor parameters
to qualify the injection behavior. We can mark
2016-06-21 10:22:38 -04:00
optional dependencies with the [`@Optional`](../api/core/index/Optional-var.html),
inject host element attributes with [`@Attribute`](../api/core/index/Attribute-var.html),
inject content child queries with [`@Query`](../api/core/index/Query-var.html)
and inject view child queries with [`@ViewQuery`](../api/core/index/ViewQuery-var.html)).
2016-03-16 12:01:33 -04:00
+makeExample('cb-ts-to-js/ts/app/hero-di-inject-additional.component.ts')(format="." )
td
:marked
### Additional Injection Metadata with Nested Arrays
To achieve the same effect in JavaScript, use the constructor array notation
in which the injection information precedes the constructor function itself.
2016-08-31 21:08:57 -04:00
Use the injection support functions `Attribute`, `Host`, `Optional`, `Self`, `SkipSelf` to qualify dependency injection behavior.
2016-03-16 12:01:33 -04:00
Use a nested array to combine injection functions.
+makeExample('cb-ts-to-js/js/app/hero-di-inject-additional.component.js')(format="." )
:marked
We can apply other additional parameter decorators such as
2016-06-21 10:22:38 -04:00
[`@Host`](../api/core/index/Host-var.html) and
[`@SkipSelf`](../api/core/index/SkipSelf-var.html) in the same way -
2016-03-16 12:01:33 -04:00
by adding `new ng.core.Host()` or `ng.core.SkipSelf()` in the
parameters array.
a(id="other-property-metadata")
.l-main-section
:marked
## Host and Query Metadata
- var top="vertical-align:top"
table(width="100%")
col(width="50%")
col(width="50%")
tr
th TypeScript
th ES5 JavaScript
tr(style=top)
td
:marked
### Host Decorators
We can use host property decorators to bind a host element to a component or directive.
2016-06-21 10:22:38 -04:00
The [`@HostBinding`](../api/core/index/HostBinding-var.html) decorator
2016-03-16 12:01:33 -04:00
binds host element properties to component data properties.
2016-06-21 10:22:38 -04:00
The [`@HostListener`](../api/core/index/HostListener-var.html) decorator bimds
2016-03-16 12:01:33 -04:00
host element events to component event handlers.
+makeExample('cb-ts-to-js/ts/app/heroes-bindings.component.ts')(format="." )
.alert.is-helpful
:marked
In TypeScript we can also use `host` metadata
instead of the `@HostBinding` and `@HostListener` property decorators.
td
:marked
### Host Metadata
We add a `host` attribute to the component metadata to achieve the
same effect as `@HostBinding` and `@HostListener`.
The `host` value is an object whose properties are host property and listener bindings:
2016-09-19 23:24:40 -04:00
* Each key follows regular Angular binding syntax: `[property]` for host bindings
2016-03-16 12:01:33 -04:00
or `(event)` for host listeners.
* Each value identifies the corresponding component property or method.
+makeExample('cb-ts-to-js/js/app/heroes-bindings.component.js')(format="." )
tr(style=top)
td
:marked
### Query Decorators
There are several property decorators for querying the descendants of
a component or directive.
2016-06-21 10:22:38 -04:00
The [`@ViewChild`](../api/core/index/ViewChild-var.html) and
[`@ViewChildren`](../api/core/index/ViewChildren-var.html) property decorators
2016-03-16 12:01:33 -04:00
allow a component to query instances of other components that are used in
its view.
+makeExample('cb-ts-to-js/ts/app/heroes-queries.component.ts', 'view')(format="." )
:marked
2016-06-21 10:22:38 -04:00
The [`@ContentChild`](../api/core/index/ContentChild-var.html) and
[`@ContentChildren`](../api/core/index/ContentChildren-var.html) property decorators
2016-03-16 12:01:33 -04:00
allow a component to query instances of other components that have been projected
into its view from elsewhere.
+makeExample('cb-ts-to-js/ts/app/heroes-queries.component.ts', 'content')(format="." )
.alert.is-helpful
:marked
In TypeScript we can also use the `queries` metadata
instead of the `@ViewChild` and `@ContentChild` property decorators.
td
:marked
### Query Metadata
We access a component's view children by adding a `queries` attribute to
the component metadata. It should be an object where:
* Each key is the name of a component property that will hold the view children
* Each value is an instance of either `ViewChild` or `ViewChildren`.
+makeExample('cb-ts-to-js/js/app/heroes-queries.component.js', 'view')(format="." )
:marked
We add *content* child queries to the same `queries` attribute
in the same manner, using instances of `ContentChild` or `ContentChildren`:
+makeExample('cb-ts-to-js/js/app/heroes-queries.component.js', 'content')(format="." )