Compare commits
49 Commits
Author | SHA1 | Date | |
---|---|---|---|
dbbfab3ee8 | |||
b87ae8e5f9 | |||
8b1d28ff48 | |||
463e967abb | |||
71b8bbef95 | |||
a2cf677714 | |||
9e1ce318a8 | |||
a00c2a9210 | |||
a677d8b330 | |||
7fe89ba4ea | |||
a8af83bf36 | |||
c75e16aae8 | |||
1affcc63c0 | |||
34395aeea1 | |||
f64de2e9f3 | |||
86ad77c1b1 | |||
d5c815f1f2 | |||
32c6d5313a | |||
388c1a3638 | |||
334a3ba125 | |||
fd1d161844 | |||
280ea13342 | |||
3b1e539bab | |||
8e57965e3c | |||
761bb0aafd | |||
1b881b6ba2 | |||
f03d724fea | |||
cf8d934ba9 | |||
67f4852acb | |||
08f6a64893 | |||
ee49bbebc7 | |||
da78b02d71 | |||
d787925841 | |||
4e6efb361d | |||
aa371335dc | |||
090b6d92da | |||
a5cbfa2aab | |||
e8ed37a0e7 | |||
e5cbebef0d | |||
654ec1570a | |||
728d903a67 | |||
495f8e1bc6 | |||
d778a65447 | |||
e8dbba417d | |||
00c145f14c | |||
8c4c9858a2 | |||
caf3a53385 | |||
6ba1cd4365 | |||
bb18cba253 |
8
.bazelrc
@ -1,5 +1,3 @@
|
||||
# Load any settings specific to the current user
|
||||
try-import .bazelrc.user
|
||||
################################
|
||||
# Settings for Angular team members only
|
||||
################################
|
||||
@ -33,7 +31,7 @@ test:debug --test_arg=--node_options=--inspect-brk --test_output=streamed --test
|
||||
# eventually a surprising failure with auto-discovery of the C++ toolchain in
|
||||
# MacOS High Sierra.
|
||||
# See https://github.com/bazelbuild/bazel/issues/4603
|
||||
build --symlink_prefix=/
|
||||
build --symlink_prefix=dist/
|
||||
|
||||
# Performance: avoid stat'ing input files
|
||||
build --watchfs
|
||||
@ -117,3 +115,7 @@ build:remote --remote_instance_name=projects/internal-200822/instances/default_i
|
||||
# Do not accept remote cache.
|
||||
# We need to understand the security risks of using prior build artifacts.
|
||||
build:remote --remote_accept_cached=false
|
||||
|
||||
# Load any settings specific to the current user. Needs to be last statement in this
|
||||
# config, as the user configuration should be able to overwrite flags from this file.
|
||||
try-import .bazelrc.user
|
||||
|
5
.github/CODEOWNERS
vendored
@ -46,6 +46,7 @@
|
||||
# andrewseguin - Andrew Seguin
|
||||
# benlesh - Ben Lesh
|
||||
# brandonroberts - Brandon Roberts
|
||||
# devversion - Paul Gschwendtner
|
||||
# filipesilva - Filipe Silva
|
||||
# gkalpak - George Kalpakas
|
||||
# hansl - Hans Larsen
|
||||
@ -87,6 +88,7 @@
|
||||
# - IgorMinar
|
||||
# - kara
|
||||
# - mhevery
|
||||
# - alexeagle
|
||||
|
||||
|
||||
# ===========================================================
|
||||
@ -325,6 +327,7 @@
|
||||
# ===========================================================
|
||||
#
|
||||
# - alexeagle
|
||||
# - devversion
|
||||
# - filipesilva
|
||||
# - gkalpak
|
||||
# - IgorMinar
|
||||
@ -818,7 +821,9 @@ testing/** @angular/fw-test
|
||||
/* @angular/fw-dev-infra
|
||||
/.buildkite/** @angular/fw-dev-infra
|
||||
/.circleci/** @angular/fw-dev-infra
|
||||
/.codefresh/** @angular/fw-dev-infra
|
||||
/.github/** @angular/fw-dev-infra
|
||||
/.vscode/** @angular/fw-dev-infra
|
||||
/docs/BAZEL.md @angular/fw-dev-infra
|
||||
/packages/* @angular/fw-dev-infra
|
||||
/scripts/** @angular/fw-dev-infra
|
||||
|
1
.vscode/extensions.json
vendored
@ -4,6 +4,7 @@
|
||||
|
||||
// List of extensions which should be recommended for users of this workspace.
|
||||
"recommendations": [
|
||||
"devondcarew.bazel-code",
|
||||
"gkalpak.aio-docs-utils",
|
||||
"ms-vscode.vscode-typescript-tslint-plugin",
|
||||
"xaver.clang-format",
|
||||
|
2
.vscode/settings.json
vendored
@ -14,12 +14,14 @@
|
||||
"**/node_modules/**": true,
|
||||
"**/bazel-out/**": true,
|
||||
"**/dist/**": true,
|
||||
"**/aio/src/generated/**": true,
|
||||
},
|
||||
"search.exclude": {
|
||||
"**/node_modules": true,
|
||||
"**/bower_components": true,
|
||||
"**/bazel-out": true,
|
||||
"**/dist": true,
|
||||
"**/aio/src/generated": true,
|
||||
},
|
||||
"git.ignoreLimitWarning": true,
|
||||
}
|
||||
|
10
CHANGELOG.md
@ -1,3 +1,13 @@
|
||||
<a name="7.2.10"></a>
|
||||
## [7.2.10](https://github.com/angular/angular/compare/7.2.9...7.2.10) (2019-03-20)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **compiler-cli:** incorrect metadata bundle for multiple unnamed re-exports ([#29360](https://github.com/angular/angular/issues/29360)) ([cf8d934](https://github.com/angular/angular/commit/cf8d934)), closes [/github.com/angular/material2/blob/master/tools/package-tools/build-release.ts#L78-L85](https://github.com//github.com/angular/material2/blob/master/tools/package-tools/build-release.ts/issues/L78-L85)
|
||||
|
||||
|
||||
|
||||
<a name="7.2.9"></a>
|
||||
## [7.2.9](https://github.com/angular/angular/compare/7.2.8...7.2.9) (2019-03-12)
|
||||
|
||||
|
@ -26,8 +26,8 @@ ARG AIO_GITHUB_ORGANIZATION=angular
|
||||
ARG TEST_AIO_GITHUB_ORGANIZATION=test-org
|
||||
ARG AIO_GITHUB_REPO=angular
|
||||
ARG TEST_AIO_GITHUB_REPO=test-repo
|
||||
ARG AIO_GITHUB_TEAM_SLUGS=aio-contributors
|
||||
ARG TEST_AIO_GITHUB_TEAM_SLUGS=aio-contributors
|
||||
ARG AIO_GITHUB_TEAM_SLUGS=aio-auto-previews,aio-contributors
|
||||
ARG TEST_AIO_GITHUB_TEAM_SLUGS=test-team-1,test-team-2
|
||||
ARG AIO_NGINX_HOSTNAME=$AIO_DOMAIN_NAME
|
||||
ARG TEST_AIO_NGINX_HOSTNAME=$TEST_AIO_DOMAIN_NAME
|
||||
ARG AIO_NGINX_PORT_HTTP=80
|
||||
|
@ -0,0 +1,20 @@
|
||||
'use strict'; // necessary for es6 output in node
|
||||
|
||||
import { browser, element, by } from 'protractor';
|
||||
|
||||
describe('Built Template Functions Example', function () {
|
||||
beforeAll(function () {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
it('should have title Built-in Template Functions', function () {
|
||||
let title = element.all(by.css('h1')).get(0);
|
||||
expect(title.getText()).toEqual('Built-in Template Functions');
|
||||
});
|
||||
|
||||
it('should display $any( ) in h2', function () {
|
||||
let header = element(by.css('h2'));
|
||||
expect(header.getText()).toContain('$any( )');
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,15 @@
|
||||
<h1>{{title}}</h1>
|
||||
|
||||
<h2><code>$any( )</code> type cast function and an undeclared member</h2>
|
||||
|
||||
<p>There is no such member as <code>bestByDate</code> in the following two examples, so nothing renders:</p>
|
||||
<!-- #docregion any-type-cast-function-1 -->
|
||||
<p>The item's undeclared best by date is: {{$any(item).bestByDate}}</p>
|
||||
<!-- #enddocregion any-type-cast-function-1 -->
|
||||
|
||||
<h2>using <code>this</code></h2>
|
||||
<!-- #docregion any-type-cast-function-2 -->
|
||||
<p>The item's undeclared best by date is: {{$any(this).bestByDate}}</p>
|
||||
<!-- #enddocregion any-type-cast-function-2 -->
|
||||
|
||||
|
@ -0,0 +1,16 @@
|
||||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
}).compileComponents();
|
||||
}));
|
||||
it('should create the app', async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
}));
|
||||
});
|
@ -0,0 +1,16 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent {
|
||||
title = 'Built-in Template Functions';
|
||||
|
||||
item = {
|
||||
name : 'Telephone',
|
||||
origin : 'Sweden',
|
||||
price: 98
|
||||
};
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Built-in Template Functions Example</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root>Loading...</app-root>
|
||||
</body>
|
||||
</html>
|
11
aio/content/examples/built-in-template-functions/src/main.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description": "Built-in Template Functions",
|
||||
"files": [
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js",
|
||||
"!**/*.[1,2].*"
|
||||
],
|
||||
"file": "src/app/app.component.ts",
|
||||
"tags": ["Built-in Template Functions"]
|
||||
}
|
71
aio/content/examples/event-binding/e2e/src/app.e2e-spec.ts
Normal file
@ -0,0 +1,71 @@
|
||||
'use strict'; // necessary for es6 output in node
|
||||
|
||||
import { browser, element, by, protractor } from 'protractor';
|
||||
|
||||
describe('Event binding example', function () {
|
||||
|
||||
beforeEach(function () {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
let saveButton = element.all(by.css('button')).get(0);
|
||||
let onSaveButton = element.all(by.css('button')).get(1);
|
||||
let myClick = element.all(by.css('button')).get(2);
|
||||
let deleteButton = element.all(by.css('button')).get(3);
|
||||
let saveNoProp = element.all(by.css('button')).get(4);
|
||||
let saveProp = element.all(by.css('button')).get(5);
|
||||
|
||||
|
||||
it('should display Event Binding with Angular', function () {
|
||||
expect(element(by.css('h1')).getText()).toEqual('Event Binding');
|
||||
});
|
||||
|
||||
it('should display 6 buttons', function() {
|
||||
expect(saveButton.getText()).toBe('Save');
|
||||
expect(onSaveButton.getText()).toBe('on-click Save');
|
||||
expect(myClick.getText()).toBe('click with myClick');
|
||||
expect(deleteButton.getText()).toBe('Delete');
|
||||
expect(saveNoProp.getText()).toBe('Save, no propagation');
|
||||
expect(saveProp.getText()).toBe('Save with propagation');
|
||||
});
|
||||
|
||||
it('should support user input', function () {
|
||||
let input = element(by.css('input'));
|
||||
let bindingResult = element.all(by.css('h4')).get(1);
|
||||
expect(bindingResult.getText()).toEqual('Result: teapot');
|
||||
input.sendKeys('abc');
|
||||
expect(bindingResult.getText()).toEqual('Result: teapotabc');
|
||||
});
|
||||
|
||||
it('should hide the item img', async () => {
|
||||
let deleteButton = element.all(by.css('button')).get(3);
|
||||
await deleteButton.click();
|
||||
browser.switchTo().alert().accept();
|
||||
expect(element.all(by.css('img')).get(0).getCssValue('display')).toEqual('none');
|
||||
});
|
||||
|
||||
it('should show two alerts', async () => {
|
||||
let parentDiv = element.all(by.css('.parent-div'));
|
||||
let childDiv = element.all(by.css('div > div')).get(1);
|
||||
await parentDiv.click();
|
||||
browser.switchTo().alert().accept();
|
||||
expect(childDiv.getText()).toEqual('Click me too! (child)');
|
||||
await childDiv.click();
|
||||
expect(browser.switchTo().alert().getText()).toEqual('Click me. Event target class is child-div');
|
||||
browser.switchTo().alert().accept();
|
||||
});
|
||||
|
||||
it('should show 1 alert from Save, no prop, button', async () => {
|
||||
await saveNoProp.click();
|
||||
expect(browser.switchTo().alert().getText()).toEqual('Saved. Event target is Save, no propagation');
|
||||
browser.switchTo().alert().accept();
|
||||
});
|
||||
|
||||
it('should show 2 alerts from Save w/prop button', async () => {
|
||||
await saveProp.click();
|
||||
expect(browser.switchTo().alert().getText()).toEqual('Saved.');
|
||||
browser.switchTo().alert().accept();
|
||||
expect(browser.switchTo().alert().getText()).toEqual('Saved.');
|
||||
browser.switchTo().alert().accept();
|
||||
});
|
||||
});
|
25
aio/content/examples/event-binding/src/app/app.component.css
Normal file
@ -0,0 +1,25 @@
|
||||
.group {
|
||||
background-color: #dae8f9;
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
.parent-div {
|
||||
background-color: #bdd1f7;
|
||||
border: solid 1px rgb(25, 118, 210);
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.parent-div:hover {
|
||||
background-color: #8fb4f9;
|
||||
}
|
||||
|
||||
.child-div {
|
||||
margin-top: 1rem;
|
||||
background-color: #fff;
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.child-div:hover {
|
||||
background-color: #eee;
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
<h1 id="event-binding">Event Binding</h1>
|
||||
|
||||
<div class="group">
|
||||
<h3>Target event</h3>
|
||||
<!-- #docregion event-binding-1 -->
|
||||
<button (click)="onSave($event)">Save</button>
|
||||
<!-- #enddocregion event-binding-1 -->
|
||||
|
||||
<!-- #docregion event-binding-2 -->
|
||||
<button on-click="onSave($event)">on-click Save</button>
|
||||
<!-- #enddocregion event-binding-2 -->
|
||||
|
||||
<!-- #docregion custom-directive -->
|
||||
<h4>myClick is an event on the custom ClickDirective:</h4>
|
||||
<button (myClick)="clickMessage=$event" clickable>click with myClick</button>
|
||||
{{clickMessage}}
|
||||
<!-- #enddocregion custom-directive -->
|
||||
|
||||
</div>
|
||||
|
||||
<div class="group">
|
||||
<h3>$event and event handling statements</h3>
|
||||
<h4>Result: {{currentItem.name}}</h4>
|
||||
|
||||
<!-- #docregion event-binding-3-->
|
||||
<input [value]="currentItem.name"
|
||||
(input)="currentItem.name=$event.target.value" >
|
||||
without NgModel
|
||||
<!-- #enddocregion event-binding-3-->
|
||||
</div>
|
||||
|
||||
<div class="group">
|
||||
<h3>Binding to a nested component</h3>
|
||||
<h4>Custom events with EventEmitter</h4>
|
||||
<!-- #docregion event-binding-to-component -->
|
||||
<app-item-detail (deleteRequest)="deleteItem($event)" [item]="currentItem"></app-item-detail>
|
||||
<!-- #enddocregion event-binding-to-component -->
|
||||
|
||||
|
||||
<h4>Click to see event target class:</h4>
|
||||
<div class="parent-div" (click)="onClickMe($event)" clickable>Click me (parent)
|
||||
<div class="child-div">Click me too! (child) </div>
|
||||
</div>
|
||||
|
||||
<h3>Saves only once:</h3>
|
||||
<div (click)="onSave()" clickable>
|
||||
<button (click)="onSave($event)">Save, no propagation</button>
|
||||
</div>
|
||||
|
||||
<h3>Saves twice:</h3>
|
||||
<div (click)="onSave()" clickable>
|
||||
<button (click)="onSave()">Save with propagation</button>
|
||||
</div>
|
@ -0,0 +1,27 @@
|
||||
import { TestBed, async } from '@angular/core/testing';
|
||||
import { AppComponent } from './app.component';
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
}).compileComponents();
|
||||
}));
|
||||
it('should create the app', async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
}));
|
||||
it(`should have as title 'Featured product:'`, async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app.title).toEqual('Featured product:');
|
||||
}));
|
||||
it('should render title in a p tag', async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
expect(compiled.querySelector('p').textContent).toContain('Featured product:');
|
||||
}));
|
||||
});
|
29
aio/content/examples/event-binding/src/app/app.component.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import { Component } from '@angular/core';
|
||||
import { Item } from './item';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent {
|
||||
|
||||
currentItem = { name: 'teapot'} ;
|
||||
clickMessage = '';
|
||||
|
||||
onSave(event?: KeyboardEvent) {
|
||||
const evtMsg = event ? ' Event target is ' + (<HTMLElement>event.target).textContent : '';
|
||||
alert('Saved.' + evtMsg);
|
||||
if (event) { event.stopPropagation(); }
|
||||
}
|
||||
|
||||
deleteItem(item?: Item) {
|
||||
alert(`Delete the ${item}.`);
|
||||
}
|
||||
|
||||
onClickMe(event?: KeyboardEvent) {
|
||||
const evtMsg = event ? ' Event target class is ' + (<HTMLElement>event.target).className : '';
|
||||
alert('Click me.' + evtMsg);
|
||||
}
|
||||
|
||||
}
|
22
aio/content/examples/event-binding/src/app/app.module.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { ItemDetailComponent } from './item-detail/item-detail.component';
|
||||
import { ClickDirective } from './click.directive';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
ItemDetailComponent,
|
||||
ClickDirective
|
||||
],
|
||||
imports: [
|
||||
BrowserModule
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
@ -0,0 +1,18 @@
|
||||
/* tslint:disable use-output-property-decorator directive-class-suffix */
|
||||
import { Directive, ElementRef, EventEmitter, Output } from '@angular/core';
|
||||
|
||||
@Directive({selector: '[myClick]'})
|
||||
export class ClickDirective {
|
||||
@Output('myClick') clicks = new EventEmitter<string>(); // @Output(alias) propertyName = ...
|
||||
|
||||
toggle = false;
|
||||
|
||||
constructor(el: ElementRef) {
|
||||
el.nativeElement
|
||||
.addEventListener('click', (event: Event) => {
|
||||
this.toggle = !this.toggle;
|
||||
this.clicks.emit(this.toggle ? 'Click!' : '');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,11 @@
|
||||
.detail {
|
||||
border: 1px solid rgb(25, 118, 210);
|
||||
padding: 1rem;
|
||||
margin: 1rem 0;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100px;
|
||||
display: block;
|
||||
padding: 1rem 0;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
<div class="detail">
|
||||
<p>This is the ItemDetailComponent</p>
|
||||
<!-- #docregion line-through -->
|
||||
<img src="{{itemImageUrl}}" [style.display]="displayNone">
|
||||
<span [style.text-decoration]="lineThrough">{{ item.name }}
|
||||
</span>
|
||||
<button (click)="delete()">Delete</button>
|
||||
<!-- #enddocregion line-through -->
|
||||
</div>
|
@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ItemDetailComponent } from './item-detail.component';
|
||||
|
||||
describe('ItemDetailComponent', () => {
|
||||
let component: ItemDetailComponent;
|
||||
let fixture: ComponentFixture<ItemDetailComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ ItemDetailComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ItemDetailComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -0,0 +1,30 @@
|
||||
/* tslint:disable use-input-property-decorator use-output-property-decorator */
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
|
||||
import { Item } from '../item';
|
||||
|
||||
@Component({
|
||||
selector: 'app-item-detail',
|
||||
styleUrls: ['./item-detail.component.css'],
|
||||
templateUrl: './item-detail.component.html'
|
||||
})
|
||||
export class ItemDetailComponent {
|
||||
|
||||
@Input() item;
|
||||
itemImageUrl = 'assets/teapot.svg';
|
||||
lineThrough = '';
|
||||
displayNone = '';
|
||||
@Input() prefix = '';
|
||||
|
||||
// #docregion deleteRequest
|
||||
// This component makes a request but it can't actually delete a hero.
|
||||
@Output() deleteRequest = new EventEmitter<Item>();
|
||||
|
||||
delete() {
|
||||
this.deleteRequest.emit(this.item.name);
|
||||
this.displayNone = this.displayNone ? '' : 'none';
|
||||
this.lineThrough = this.lineThrough ? '' : 'line-through';
|
||||
}
|
||||
// #enddocregion deleteRequest
|
||||
|
||||
}
|
4
aio/content/examples/event-binding/src/app/item.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export class Item {
|
||||
name: '';
|
||||
}
|
||||
|
1
aio/content/examples/event-binding/src/assets/teapot.svg
Normal file
After Width: | Height: | Size: 23 KiB |
14
aio/content/examples/event-binding/src/index.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>EventBinding</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
12
aio/content/examples/event-binding/src/main.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.log(err));
|
10
aio/content/examples/event-binding/stackblitz.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"description": "Event Binding",
|
||||
"files": [
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js",
|
||||
"!**/*.[1,2].*"
|
||||
],
|
||||
"file": "src/app/app.component.ts",
|
||||
"tags": ["Event Binding"]
|
||||
}
|
@ -13,15 +13,4 @@ describe('AppComponent', () => {
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
}));
|
||||
it(`should have as title 'Featured product:'`, async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
const app = fixture.debugElement.componentInstance;
|
||||
expect(app.title).toEqual('Featured product:');
|
||||
}));
|
||||
it('should render title in a p tag', async(() => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const compiled = fixture.debugElement.nativeElement;
|
||||
expect(compiled.querySelector('p').textContent).toContain('Featured product:');
|
||||
}));
|
||||
});
|
||||
|
@ -31,6 +31,7 @@ describe('Router', () => {
|
||||
heroDetailTitle: heroDetail.element(by.xpath('*[2]')),
|
||||
|
||||
adminHref: hrefEles.get(2),
|
||||
adminPage: element(by.css('app-root > div > app-admin')),
|
||||
adminPreloadList: element.all(by.css('app-root > div > app-admin > app-admin-dashboard > ul > li')),
|
||||
|
||||
loginHref: hrefEles.get(3),
|
||||
@ -138,6 +139,31 @@ describe('Router', () => {
|
||||
expect(page.secondaryOutlet.count()).toBe(1, 'secondary outlet');
|
||||
});
|
||||
|
||||
it('should redirect with secondary route', async () => {
|
||||
const page = getPageStruct();
|
||||
|
||||
// go to login page and login
|
||||
await browser.get('');
|
||||
await page.loginHref.click();
|
||||
await page.loginButton.click();
|
||||
|
||||
// open secondary outlet
|
||||
await page.contactHref.click();
|
||||
|
||||
// go to login page and logout
|
||||
await page.loginHref.click();
|
||||
await page.loginButton.click();
|
||||
|
||||
// attempt to go to admin page, redirects to login with secondary outlet open
|
||||
await page.adminHref.click();
|
||||
|
||||
// login, get redirected back to admin with outlet still open
|
||||
await page.loginButton.click();
|
||||
|
||||
expect(await page.adminPage.isDisplayed()).toBeTruthy();
|
||||
expect(page.secondaryOutlet.count()).toBeTruthy();
|
||||
});
|
||||
|
||||
async function crisisCenterEdit(index: number, save: boolean) {
|
||||
const page = getPageStruct();
|
||||
await page.crisisHref.click();
|
||||
|
@ -27,10 +27,10 @@ export class LoginComponent {
|
||||
if (this.authService.isLoggedIn) {
|
||||
// Get the redirect URL from our auth service
|
||||
// If no redirect has been set, use the default
|
||||
let redirect = this.authService.redirectUrl ? this.authService.redirectUrl : '/crisis-center/admin';
|
||||
let redirect = this.authService.redirectUrl ? this.router.parseUrl(this.authService.redirectUrl) : '/admin';
|
||||
|
||||
// Redirect the user
|
||||
this.router.navigate([redirect]);
|
||||
this.router.navigateByUrl(redirect);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -28,7 +28,7 @@ export class LoginComponent {
|
||||
if (this.authService.isLoggedIn) {
|
||||
// Get the redirect URL from our auth service
|
||||
// If no redirect has been set, use the default
|
||||
let redirect = this.authService.redirectUrl ? this.authService.redirectUrl : '/admin';
|
||||
let redirect = this.authService.redirectUrl ? this.router.parseUrl(this.authService.redirectUrl) : '/admin';
|
||||
|
||||
// #docregion preserve
|
||||
// Set our navigation extras object
|
||||
@ -39,7 +39,7 @@ export class LoginComponent {
|
||||
};
|
||||
|
||||
// Redirect the user
|
||||
this.router.navigate([redirect], navigationExtras);
|
||||
this.router.navigateByUrl(redirect, navigationExtras);
|
||||
// #enddocregion preserve
|
||||
}
|
||||
});
|
||||
|
@ -42,7 +42,7 @@ export class HeroService {
|
||||
// #enddocregion getHeroes-2
|
||||
tap(_ => this.log('fetched heroes')),
|
||||
// #docregion getHeroes-2
|
||||
catchError(this.handleError('getHeroes', []))
|
||||
catchError(this.handleError<Hero[]>('getHeroes', []))
|
||||
);
|
||||
// #docregion getHeroes-1
|
||||
}
|
||||
|
@ -453,7 +453,7 @@ The compiler understands all syntax forms that the _collector_ supports, but it
|
||||
|
||||
The compiler can only reference _exported symbols_.
|
||||
|
||||
Decorated component class members must be public. You cannot make an `@Input()` property private or internal.
|
||||
Decorated component class members must be public. You cannot make an `@Input()` property private or protected.
|
||||
|
||||
Data bound properties must also be public.
|
||||
|
||||
|
59
aio/content/guide/app-shell.md
Normal file
@ -0,0 +1,59 @@
|
||||
# App shell
|
||||
|
||||
App shell is a way to render a portion of your application via a route at build time.
|
||||
It can improve the user experience by quickly launching a static rendered page (a skeleton common to all pages) while the browser downloads the full client version and switches to it automatically after the code loads.
|
||||
|
||||
This gives users a meaningful first paint of your application that appears quickly because the browser can simply render the HTML and CSS without the need to initialize any JavaScript.
|
||||
|
||||
Learn more in [The App Shell Model](https://developers.google.com/web/fundamentals/architecture/app-shell).
|
||||
|
||||
## Step 1: Prepare the application
|
||||
|
||||
You can do this with the following CLI command:
|
||||
<code-example format="." language="bash" linenums="false">
|
||||
ng new my-app --routing
|
||||
</code-example>
|
||||
|
||||
For an existing application, you have to manually add the `RouterModule` and defining a `<router-outlet>` within your application.
|
||||
|
||||
## Step 2: Create the app shell
|
||||
|
||||
Use the CLI to automatically create the app shell.
|
||||
|
||||
<code-example format="." language="bash" linenums="false">
|
||||
ng generate app-shell --client-project my-app --universal-project server-app
|
||||
</code-example>
|
||||
|
||||
* `my-app` takes the name of your client application.
|
||||
* `server-app` takes the name of the Universal (or server) application.
|
||||
|
||||
After running this command you will notice that the `angular.json` configuration file has been updated to add two new targets, with a few other changes.
|
||||
|
||||
<code-example format="." language="none" linenums="false">
|
||||
"server": {
|
||||
"builder": "@angular-devkit/build-angular:server",
|
||||
"options": {
|
||||
"outputPath": "dist/my-app-server",
|
||||
"main": "src/main.server.ts",
|
||||
"tsConfig": "tsconfig.server.json"
|
||||
}
|
||||
},
|
||||
"app-shell": {
|
||||
"builder": "@angular-devkit/build-angular:app-shell",
|
||||
"options": {
|
||||
"browserTarget": "my-app:build",
|
||||
"serverTarget": "my-app:server",
|
||||
"route": "shell"
|
||||
}
|
||||
}
|
||||
</code-example>
|
||||
|
||||
## Step 3: Verify the app is built with the shell content
|
||||
|
||||
Use the CLI to build the `app-shell` target.
|
||||
|
||||
<code-example format="." language="bash" linenums="false">
|
||||
ng run my-app:app-shell
|
||||
</code-example>
|
||||
|
||||
To verify the build output, open `dist/my-app/index.html`. Look for default text `app-shell works!` to show that the app shell route was rendered as part of the output.
|
@ -73,7 +73,7 @@ Angular provides predefined pipes for common transformations, and you can also d
|
||||
|
||||
## Services and dependency injection
|
||||
|
||||
For data or logic that isn't associated with a specific view, and that you want to share across components, you create a *service* class. A service class definition is immediately preceded by the `@Injectable()` decorator. The decorator provides the metadata that allows your service to be *injected* into client components as a dependency.
|
||||
For data or logic that isn't associated with a specific view, and that you want to share across components, you create a *service* class. A service class definition is immediately preceded by the `@Injectable()` decorator. The decorator provides the metadata that allows other providers to be **injected** as dependencies into your class.
|
||||
|
||||
*Dependency injection* (DI) lets you keep your component classes lean and efficient. They don't fetch data from the server, validate user input, or log directly to the console; they delegate such tasks to services.
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
You can create and publish new libraries to extend Angular functionality. If you find that you need to solve the same problem in more than one app (or want to share your solution with other developers), you have a candidate for a library.
|
||||
|
||||
An simple example might be a button that sends users to your company website, that would be included in all apps that your company builds.
|
||||
A simple example might be a button that sends users to your company website, that would be included in all apps that your company builds.
|
||||
|
||||
## Getting started
|
||||
|
||||
|
@ -49,18 +49,6 @@ locale id to find the correct corresponding locale data.
|
||||
|
||||
By default, Angular uses the locale `en-US`, which is English as spoken in the United States of America.
|
||||
|
||||
To set your app's locale to another value, use the CLI parameter `--configuration` with the value of the locale id that you want to use:
|
||||
|
||||
<code-example language="sh" class="code-shell">
|
||||
ng serve --configuration=fr
|
||||
</code-example>
|
||||
|
||||
If you use JIT, you also need to define the `LOCALE_ID` provider in your main module:
|
||||
|
||||
<code-example path="i18n/doc-files/app.module.ts" header="src/app/app.module.ts" linenums="false">
|
||||
</code-example>
|
||||
|
||||
|
||||
For more information about Unicode locale identifiers, see the
|
||||
[CLDR core spec](http://cldr.unicode.org/core-spec#Unicode_Language_and_Locale_Identifiers).
|
||||
|
||||
|
@ -158,7 +158,7 @@ You can <a href="generated/zips/cli-quickstart/cli-quickstart.zip" target="_blan
|
||||
</div>
|
||||
|
||||
|
||||
For more information about Angular project files and the file structure, see [Workspace and project file struture](guide/file-structure).
|
||||
For more information about Angular project files and the file structure, see [Workspace and project file structure](guide/file-structure).
|
||||
|
||||
|
||||
|
||||
|
@ -1055,7 +1055,7 @@ The default route should redirect to the `HeroListComponent` _only_ when the _en
|
||||
Remember to restore the redirect to `pathMatch = 'full'`.
|
||||
|
||||
Learn more in Victor Savkin's
|
||||
[post on redirects](http://victorsavkin.com/post/146722301646/angular-router-empty-paths-componentless-routes).
|
||||
[post on redirects](http://vsavkin.tumblr.com/post/146722301646/angular-router-empty-paths-componentless-routes).
|
||||
|
||||
|
||||
</div>
|
||||
@ -1280,8 +1280,9 @@ The **Routing Module** has several characteristics:
|
||||
### Integrate routing with your app
|
||||
|
||||
The sample routing application does not include routing by default.
|
||||
When you use the [Angular CLI](cli) to create a project that will use routing, set the `--routing` option for the project or app, and for each NgModule.
|
||||
When you create or initialize a new project (using the CLI [`ng new`](cli/new) command) or a new app (using the [`ng generate app`](cli/generate) command), specify the `--routing` option. This tells the CLI to include the `@angular/router` npm package and create a file named `app-routing.module.ts`.
|
||||
When you create a new workspace and initial application, the [Angular CLI](cli) [`ng new`](cli/new) command prompts you to add "Angular routing". Enter `Y`.
|
||||
When you generate a new application using the [`ng generate app`](cli/generate) command, specify the `--routing` option. These options tell the CLI to include the `@angular/router` npm package and create a file named `app-routing.module.ts`.
|
||||
|
||||
You can then use routing in any NgModule that you add to the project or app.
|
||||
|
||||
For example, the following command generates an NgModule that can use routing.
|
||||
@ -3849,7 +3850,7 @@ Update the `AuthGuard` to provide a `session_id` query that will remain after na
|
||||
|
||||
Add an `anchor` element so you can jump to a certain point on the page.
|
||||
|
||||
Add the `NavigationExtras` object to the `router.navigate` method that navigates you to the `/login` route.
|
||||
Add the `NavigationExtras` object to the `router.navigate()` method that navigates you to the `/login` route.
|
||||
|
||||
|
||||
<code-example path="router/src/app/auth/auth.guard.4.ts" linenums="false" header="src/app/auth/auth.guard.ts (v3)">
|
||||
@ -3860,7 +3861,7 @@ Add the `NavigationExtras` object to the `router.navigate` method that navigates
|
||||
|
||||
You can also preserve query parameters and fragments across navigations without having to provide them
|
||||
again when navigating. In the `LoginComponent`, you'll add an *object* as the
|
||||
second argument in the `router.navigate` function
|
||||
second argument in the `router.navigateUrl()` function
|
||||
and provide the `queryParamsHandling` and `preserveFragment` to pass along the current query parameters
|
||||
and fragment to the next route.
|
||||
|
||||
|
@ -1749,447 +1749,6 @@ A consistent class and file name convention make these modules easy to spot and
|
||||
</table>
|
||||
|
||||
|
||||
|
||||
<a href="#toc">Back to top</a>
|
||||
|
||||
|
||||
## Coding conventions
|
||||
|
||||
Have a consistent set of coding, naming, and whitespace conventions.
|
||||
|
||||
|
||||
|
||||
{@a 03-01}
|
||||
|
||||
### Classes
|
||||
|
||||
#### Style 03-01
|
||||
|
||||
<div class="s-rule do">
|
||||
|
||||
|
||||
|
||||
**Do** use upper camel case when naming classes.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why">
|
||||
|
||||
|
||||
|
||||
**Why?** Follows conventional thinking for class names.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why-last">
|
||||
|
||||
|
||||
|
||||
**Why?** Classes can be instantiated and construct an instance.
|
||||
By convention, upper camel case indicates a constructable asset.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<code-example path="styleguide/src/03-01/app/core/exception.service.avoid.ts" region="example" header="app/shared/exception.service.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<code-example path="styleguide/src/03-01/app/core/exception.service.ts" region="example" header="app/shared/exception.service.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
||||
|
||||
<a href="#toc">Back to top</a>
|
||||
|
||||
|
||||
{@a 03-02}
|
||||
|
||||
### Constants
|
||||
|
||||
#### Style 03-02
|
||||
|
||||
<div class="s-rule do">
|
||||
|
||||
|
||||
|
||||
**Do** declare variables with `const` if their values should not change during the application lifetime.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why">
|
||||
|
||||
|
||||
|
||||
**Why?** Conveys to readers that the value is invariant.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why-last">
|
||||
|
||||
|
||||
|
||||
**Why?** TypeScript helps enforce that intent by requiring immediate initialization and by
|
||||
preventing subsequent re-assignment.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-rule consider">
|
||||
|
||||
|
||||
|
||||
**Consider** spelling `const` variables in lower camel case.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why">
|
||||
|
||||
|
||||
|
||||
**Why?** Lower camel case variable names (`heroRoutes`) are easier to read and understand
|
||||
than the traditional UPPER_SNAKE_CASE names (`HERO_ROUTES`).
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why-last">
|
||||
|
||||
|
||||
|
||||
**Why?** The tradition of naming constants in UPPER_SNAKE_CASE reflects
|
||||
an era before the modern IDEs that quickly reveal the `const` declaration.
|
||||
TypeScript prevents accidental reassignment.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-rule do">
|
||||
|
||||
|
||||
|
||||
**Do** tolerate _existing_ `const` variables that are spelled in UPPER_SNAKE_CASE.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why-last">
|
||||
|
||||
|
||||
|
||||
**Why?** The tradition of UPPER_SNAKE_CASE remains popular and pervasive,
|
||||
especially in third party modules.
|
||||
It is rarely worth the effort to change them at the risk of breaking existing code and documentation.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<code-example path="styleguide/src/03-02/app/core/data.service.ts" header="app/shared/data.service.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
||||
|
||||
<a href="#toc">Back to top</a>
|
||||
|
||||
|
||||
{@a 03-03}
|
||||
|
||||
### Interfaces
|
||||
|
||||
#### Style 03-03
|
||||
|
||||
<div class="s-rule do">
|
||||
|
||||
|
||||
|
||||
**Do** name an interface using upper camel case.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-rule consider">
|
||||
|
||||
|
||||
|
||||
**Consider** naming an interface without an `I` prefix.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-rule consider">
|
||||
|
||||
|
||||
|
||||
**Consider** using a class instead of an interface for services and declarables (components, directives, and pipes).
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-rule consider">
|
||||
|
||||
|
||||
|
||||
**Consider** using an interface for data models.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why">
|
||||
|
||||
|
||||
|
||||
**Why?** <a href="https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines">TypeScript guidelines</a>
|
||||
discourage the `I` prefix.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why">
|
||||
|
||||
|
||||
|
||||
**Why?** A class alone is less code than a _class-plus-interface_.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why">
|
||||
|
||||
|
||||
|
||||
**Why?** A class can act as an interface (use `implements` instead of `extends`).
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why-last">
|
||||
|
||||
|
||||
|
||||
**Why?** An interface-class can be a provider lookup token in Angular dependency injection.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<code-example path="styleguide/src/03-03/app/core/hero-collector.service.avoid.ts" region="example" header="app/shared/hero-collector.service.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<code-example path="styleguide/src/03-03/app/core/hero-collector.service.ts" region="example" header="app/shared/hero-collector.service.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
||||
|
||||
<a href="#toc">Back to top</a>
|
||||
|
||||
{@a 03-04}
|
||||
|
||||
### Properties and methods
|
||||
|
||||
#### Style 03-04
|
||||
|
||||
|
||||
<div class="s-rule do">
|
||||
|
||||
|
||||
|
||||
**Do** use lower camel case to name properties and methods.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-rule avoid">
|
||||
|
||||
|
||||
|
||||
**Avoid** prefixing private properties and methods with an underscore.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why">
|
||||
|
||||
|
||||
|
||||
**Why?** Follows conventional thinking for properties and methods.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why">
|
||||
|
||||
|
||||
|
||||
**Why?** JavaScript lacks a true private property or method.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why-last">
|
||||
|
||||
|
||||
|
||||
**Why?** TypeScript tooling makes it easy to identify private vs. public properties and methods.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<code-example path="styleguide/src/03-04/app/core/toast.service.avoid.ts" region="example" header="app/shared/toast.service.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<code-example path="styleguide/src/03-04/app/core/toast.service.ts" region="example" header="app/shared/toast.service.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
||||
|
||||
<a href="#toc">Back to top</a>
|
||||
|
||||
{@a 03-06}
|
||||
|
||||
### Import line spacing
|
||||
|
||||
#### Style 03-06
|
||||
|
||||
|
||||
<div class="s-rule consider">
|
||||
|
||||
|
||||
|
||||
**Consider** leaving one empty line between third party imports and application imports.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-rule consider">
|
||||
|
||||
|
||||
|
||||
**Consider** listing import lines alphabetized by the module.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-rule consider">
|
||||
|
||||
|
||||
|
||||
**Consider** listing destructured imported symbols alphabetically.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why">
|
||||
|
||||
|
||||
|
||||
**Why?** The empty line separates _your_ stuff from _their_ stuff.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="s-why-last">
|
||||
|
||||
|
||||
|
||||
**Why?** Alphabetizing makes it easier to read and locate symbols.
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<code-example path="styleguide/src/03-06/app/heroes/shared/hero.service.avoid.ts" region="example" header="app/heroes/shared/hero.service.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<code-example path="styleguide/src/03-06/app/heroes/shared/hero.service.ts" region="example" header="app/heroes/shared/hero.service.ts">
|
||||
|
||||
</code-example>
|
||||
|
||||
|
||||
|
||||
<a href="#toc">Back to top</a>
|
||||
|
||||
|
||||
|
@ -797,7 +797,6 @@ content harmlessly.
|
||||
|
||||
|
||||
<hr/>
|
||||
|
||||
{@a other-bindings}
|
||||
|
||||
## Attribute, class, and style bindings
|
||||
@ -944,56 +943,44 @@ Note that a _style property_ name can be written in either
|
||||
|
||||
{@a event-binding}
|
||||
|
||||
## Event binding ( <span class="syntax">(event)</span> )
|
||||
## Event binding `(event)`
|
||||
|
||||
The bindings directives you've met so far flow data in one direction: **from a component to an element**.
|
||||
Event binding allows you to listen for certain events such as
|
||||
keystrokes, mouse movements, clicks, and touches. For an example
|
||||
demonstrating all of the points in this section, see the <live-example name="event-binding">event binding example</live-example>.
|
||||
|
||||
Users don't just stare at the screen. They enter text into input boxes. They pick items from lists.
|
||||
They click buttons. Such user actions may result in a flow of data in the opposite direction:
|
||||
**from an element to a component**.
|
||||
|
||||
The only way to know about a user action is to listen for certain events such as
|
||||
keystrokes, mouse movements, clicks, and touches.
|
||||
You declare your interest in user actions through Angular event binding.
|
||||
|
||||
Event binding syntax consists of a **target event** name
|
||||
Angular event binding syntax consists of a **target event** name
|
||||
within parentheses on the left of an equal sign, and a quoted
|
||||
[template statement](guide/template-syntax#template-statements) on the right.
|
||||
template statement on the right.
|
||||
The following event binding listens for the button's click events, calling
|
||||
the component's `onSave()` method whenever a click occurs:
|
||||
|
||||
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-1" header="src/app/app.component.html" linenums="false">
|
||||
</code-example>
|
||||
<figure>
|
||||
<img src='generated/images/guide/event-binding/syntax-diagram.svg' alt="Syntax diagram">
|
||||
</figure>
|
||||
|
||||
### Target event
|
||||
|
||||
A **name between parentheses** — for example, `(click)` —
|
||||
identifies the target event. In the following example, the target is the button's click event.
|
||||
As above, the target is the button's click event.
|
||||
|
||||
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-1" header="src/app/app.component.html" linenums="false">
|
||||
<code-example path="event-binding/src/app/app.component.html" region="event-binding-1" header="src/app/app.component.html" linenums="false">
|
||||
</code-example>
|
||||
|
||||
Some people prefer the `on-` prefix alternative, known as the **canonical form**:
|
||||
Alternatively, use the `on-` prefix, known as the canonical form:
|
||||
|
||||
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-2" header="src/app/app.component.html" linenums="false">
|
||||
<code-example path="event-binding/src/app/app.component.html" region="event-binding-2" header="src/app/app.component.html" linenums="false">
|
||||
</code-example>
|
||||
|
||||
Element events may be the more common targets, but Angular looks first to see if the name matches an event property
|
||||
of a known directive, as it does in the following example:
|
||||
|
||||
<code-example path="template-syntax/src/app/app.component.html" region="event-binding-3" header="src/app/app.component.html" linenums="false">
|
||||
<code-example path="event-binding/src/app/app.component.html" region="custom-directive" header="src/app/app.component.html" linenums="false">
|
||||
</code-example>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
The `myClick` directive is further described in the section
|
||||
on [aliasing input/output properties](guide/template-syntax#aliasing-io).
|
||||
|
||||
</div>
|
||||
|
||||
If the name fails to match an element event or an output property of a known directive,
|
||||
Angular reports an “unknown directive” error.
|
||||
|
||||
|
||||
### *$event* and event handling statements
|
||||
|
||||
In an event binding, Angular sets up an event handler for the target event.
|
||||
@ -1003,72 +990,73 @@ The template statement typically involves a receiver, which performs an action
|
||||
in response to the event, such as storing a value from the HTML control
|
||||
into a model.
|
||||
|
||||
The binding conveys information about the event, including data values, through
|
||||
an **event object named `$event`**.
|
||||
The binding conveys information about the event. This information can include data values such as an event object, string, or number named `$event`.
|
||||
|
||||
The shape of the event object is determined by the target event.
|
||||
The target event determines the shape of the `$event` object.
|
||||
If the target event is a native DOM element event, then `$event` is a
|
||||
[DOM event object](https://developer.mozilla.org/en-US/docs/Web/Events),
|
||||
with properties such as `target` and `target.value`.
|
||||
|
||||
Consider this example:
|
||||
|
||||
<code-example path="template-syntax/src/app/app.component.html" region="without-NgModel" header="src/app/app.component.html" linenums="false">
|
||||
<code-example path="event-binding/src/app/app.component.html" region="event-binding-3" header="src/app/app.component.html" linenums="false">
|
||||
</code-example>
|
||||
|
||||
This code sets the input box `value` property by binding to the `name` property.
|
||||
To listen for changes to the value, the code binds to the input box's `input` event.
|
||||
This code sets the `<input>` `value` property by binding to the `name` property.
|
||||
To listen for changes to the value, the code binds to the `input`
|
||||
event of the `<input>` element.
|
||||
When the user makes changes, the `input` event is raised, and the binding executes
|
||||
the statement within a context that includes the DOM event object, `$event`.
|
||||
|
||||
To update the `name` property, the changed text is retrieved by following the path `$event.target.value`.
|
||||
|
||||
If the event belongs to a directive (recall that components are directives),
|
||||
`$event` has whatever shape the directive decides to produce.
|
||||
If the event belongs to a directive—recall that components
|
||||
are directives—`$event` has whatever shape the directive produces.
|
||||
|
||||
{@a eventemitter}
|
||||
|
||||
{@a custom-event}
|
||||
|
||||
### Custom events with <span class="syntax">EventEmitter</span>
|
||||
### Custom events with `EventEmitter`
|
||||
|
||||
Directives typically raise custom events with an Angular [EventEmitter](api/core/EventEmitter).
|
||||
The directive creates an `EventEmitter` and exposes it as a property.
|
||||
The directive calls `EventEmitter.emit(payload)` to fire an event, passing in a message payload, which can be anything.
|
||||
Parent directives listen for the event by binding to this property and accessing the payload through the `$event` object.
|
||||
|
||||
Consider a `HeroDetailComponent` that presents hero information and responds to user actions.
|
||||
Although the `HeroDetailComponent` has a delete button it doesn't know how to delete the hero itself.
|
||||
The best it can do is raise an event reporting the user's delete request.
|
||||
Consider an `ItemDetailComponent` that presents item information and responds to user actions.
|
||||
Although the `ItemDetailComponent` has a delete button, it doesn't know how to delete the hero. It can only raise an event reporting the user's delete request.
|
||||
|
||||
Here are the pertinent excerpts from that `HeroDetailComponent`:
|
||||
Here are the pertinent excerpts from that `ItemDetailComponent`:
|
||||
|
||||
<code-example path="template-syntax/src/app/hero-detail.component.ts" linenums="false" header="src/app/hero-detail.component.ts (template)" region="template-1">
|
||||
|
||||
<code-example path="event-binding/src/app/item-detail/item-detail.component.html" linenums="false" header="src/app/item-detail/item-detail.component.ts (template)" region="line-through">
|
||||
</code-example>
|
||||
|
||||
<code-example path="template-syntax/src/app/hero-detail.component.ts" linenums="false" header="src/app/hero-detail.component.ts (deleteRequest)" region="deleteRequest">
|
||||
<code-example path="event-binding/src/app/item-detail/item-detail.component.ts" linenums="false" header="src/app/item-detail/item-detail.component.ts (deleteRequest)" region="deleteRequest">
|
||||
</code-example>
|
||||
|
||||
|
||||
The component defines a `deleteRequest` property that returns an `EventEmitter`.
|
||||
When the user clicks *delete*, the component invokes the `delete()` method,
|
||||
telling the `EventEmitter` to emit a `Hero` object.
|
||||
telling the `EventEmitter` to emit an `Item` object.
|
||||
|
||||
Now imagine a hosting parent component that binds to the `HeroDetailComponent`'s `deleteRequest` event.
|
||||
Now imagine a hosting parent component that binds to the `deleteRequest` event
|
||||
of the `ItemDetailComponent`.
|
||||
|
||||
<code-example path="template-syntax/src/app/app.component.html" linenums="false" header="src/app/app.component.html (event-binding-to-component)" region="event-binding-to-component">
|
||||
<code-example path="event-binding/src/app/app.component.html" linenums="false" header="src/app/app.component.html (event-binding-to-component)" region="event-binding-to-component">
|
||||
</code-example>
|
||||
|
||||
When the `deleteRequest` event fires, Angular calls the parent component's `deleteHero` method,
|
||||
passing the *hero-to-delete* (emitted by `HeroDetail`) in the `$event` variable.
|
||||
When the `deleteRequest` event fires, Angular calls the parent component's
|
||||
`deleteItem()` method, passing the *item-to-delete* (emitted by `ItemDetail`)
|
||||
in the `$event` variable.
|
||||
|
||||
### Template statements have side effects
|
||||
|
||||
The `deleteHero` method has a side effect: it deletes a hero.
|
||||
Template statement side effects are not just OK, but expected.
|
||||
Though [template expressions](guide/template-syntax#template-expressions) shouldn't have [side effects](guide/template-syntax#avoid-side-effects), template
|
||||
statements usually do. The `deleteItem()` method does have
|
||||
a side effect: it deletes an item.
|
||||
|
||||
Deleting the hero updates the model, perhaps triggering other changes
|
||||
including queries and saves to a remote server.
|
||||
These changes percolate through the system and are ultimately displayed in this and other views.
|
||||
Deleting an item updates the model, and depending on your code, triggers
|
||||
other changes including queries and saving to a remote server.
|
||||
These changes propagate through the system and ultimately display in this and other views.
|
||||
|
||||
|
||||
<hr/>
|
||||
@ -2009,29 +1997,29 @@ You'll need this template operator when you turn on strict null checks. It's opt
|
||||
|
||||
<hr/>
|
||||
|
||||
{@a built-in-template-functions}
|
||||
|
||||
## Built-in template functions
|
||||
|
||||
{@a any-type-cast-function}
|
||||
|
||||
## The `$any` type cast function (`$any( <expression> )`)
|
||||
### The `$any()` type cast function
|
||||
|
||||
Sometimes a binding expression will be reported as a type error and it is not possible or difficult
|
||||
to fully specify the type. To silence the error, you can use the `$any` cast function to cast
|
||||
the expression to [the `any` type](http://www.typescriptlang.org/docs/handbook/basic-types.html#any).
|
||||
Sometimes a binding expression triggers a type error during [AOT compilation](guide/aot-compiler) and it is not possible or difficult
|
||||
to fully specify the type. To silence the error, you can use the `$any()` cast function to cast
|
||||
the expression to [the `any` type](http://www.typescriptlang.org/docs/handbook/basic-types.html#any) as in the following example:
|
||||
|
||||
<code-example path="template-syntax/src/app/app.component.html" region="any-type-cast-function-1" header="src/app/app.component.html" linenums="false">
|
||||
<code-example path="built-in-template-functions/src/app/app.component.html" region="any-type-cast-function-1" header="src/app/app.component.html" linenums="false">
|
||||
</code-example>
|
||||
|
||||
In this example, when the Angular compiler turns your template into TypeScript code,
|
||||
it prevents TypeScript from reporting that `marker` is not a member of the `Hero`
|
||||
interface.
|
||||
When the Angular compiler turns this template into TypeScript code,
|
||||
it prevents TypeScript from reporting that `bestByDate` is not a member of the `item`
|
||||
object when it runs type checking on the template.
|
||||
|
||||
The `$any` cast function can be used in conjunction with `this` to allow access to undeclared members of
|
||||
The `$any()` cast function also works with `this` to allow access to undeclared members of
|
||||
the component.
|
||||
|
||||
<code-example path="template-syntax/src/app/app.component.html" region="any-type-cast-function-2" header="src/app/app.component.html" linenums="false">
|
||||
<code-example path="built-in-template-functions/src/app/app.component.html" region="any-type-cast-function-2" header="src/app/app.component.html" linenums="false">
|
||||
</code-example>
|
||||
|
||||
The `$any` cast function can be used anywhere in a binding expression where a method call is valid.
|
||||
|
||||
## Summary
|
||||
You've completed this survey of template syntax.
|
||||
Now it's time to put that knowledge to work on your own components and directives.
|
||||
The `$any()` cast function works anywhere in a binding expression where a method call is valid.
|
||||
|
@ -289,7 +289,7 @@ written without assistance from Angular testing utilities.
|
||||
#### Services with dependencies
|
||||
|
||||
Services often depend on other services that Angular injects into the constructor.
|
||||
In many cases, it easy to create and _inject_ these dependencies by hand while
|
||||
In many cases, it's easy to create and _inject_ these dependencies by hand while
|
||||
calling the service's constructor.
|
||||
|
||||
The `MasterService` is a simple example:
|
||||
@ -318,7 +318,7 @@ Prefer spies as they are usually the easiest way to mock services.
|
||||
|
||||
These standard testing techniques are great for unit testing services in isolation.
|
||||
|
||||
However, you almost always inject service into application classes using Angular
|
||||
However, you almost always inject services into application classes using Angular
|
||||
dependency injection and you should have tests that reflect that usage pattern.
|
||||
Angular testing utilities make it easy to investigate how injected services behave.
|
||||
|
||||
@ -2398,7 +2398,7 @@ So when you call `createComponent()`, the `TestBed` compiles implicitly.
|
||||
|
||||
That's not a problem when the source code is in memory.
|
||||
But the `BannerComponent` requires external files
|
||||
that the compile must read from the file system,
|
||||
that the compiler must read from the file system,
|
||||
an inherently _asynchronous_ operation.
|
||||
|
||||
If the `TestBed` were allowed to continue, the tests would run and fail mysteriously
|
||||
|
BIN
aio/content/images/bios/CaerusKaru.jpg
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
aio/content/images/bios/JiaLiPassion.jpg
Normal file
After Width: | Height: | Size: 38 KiB |
BIN
aio/content/images/bios/alan-agius4.jpg
Normal file
After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 14 KiB |
BIN
aio/content/images/bios/cexbrayat.jpg
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
aio/content/images/bios/clydin.jpg
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
aio/content/images/bios/denny.jpg
Normal file
After Width: | Height: | Size: 44 KiB |
BIN
aio/content/images/bios/gregmagolan.jpg
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
aio/content/images/bios/jennifer.jpg
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
aio/content/images/bios/judy.png
Normal file
After Width: | Height: | Size: 127 KiB |
BIN
aio/content/images/bios/justinschwartzenberger.jpg
Normal file
After Width: | Height: | Size: 24 KiB |
BIN
aio/content/images/bios/kapunahele.jpg
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
aio/content/images/bios/luixaviles.jpg
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
aio/content/images/bios/sidd-ajmera.jpg
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
aio/content/images/bios/sreevani.jpg
Normal file
After Width: | Height: | Size: 24 KiB |
@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 600 125" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;"><g transform="matrix(0.469484,0,0,0.469925,-158.685,-184.211)"><text x="374px" y="472px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:64px;"><button</text><text x="607.094px" y="472px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:64px;fill:#df002d;">(click)</text><text x="774.156px" y="472px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:64px;">="</text><text x="834.25px" y="472px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:64px;fill:#0022be;">onSave()</text><text x="1093.94px" y="472px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:64px;">">Save</button></text></g><path d="M142.827,95.824l-6.663,-3.032l17.828,-39.26l-6.187,-2.815l13.842,-5.191l5.195,13.852l-6.187,-2.815l-17.828,39.261Z" style="fill:#df002d;"/><path d="M337.08,93.548l-6.915,2.399l-13.342,-38.531l-6.422,2.228l6.458,-13.308l13.3,6.453l-6.421,2.228l13.342,38.531Z" style="fill:#3345cc;"/><g><rect x="23.005" y="76.128" width="197.653" height="31.485" style="fill:#fff;stroke:#000;stroke-width:0.7px;"/><text x="31.989px" y="98.214px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:22.556px;fill:#df002d;">target even<tspan x="144.743px " y="98.214px ">t</tspan> name</text></g><g><rect x="275.117" y="76.128" width="228.169" height="31.955" style="fill:#fff;stroke:#000;stroke-width:0.7px;"/><text x="293.078px" y="98.214px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:22.556px;fill:#3345cc;">template st<tspan x="403.3px " y="98.214px ">a</tspan>tement</text></g></svg>
|
After Width: | Height: | Size: 2.0 KiB |
@ -1,29 +1,23 @@
|
||||
{
|
||||
"misko": {
|
||||
"mhevery": {
|
||||
"name": "Miško Hevery",
|
||||
"picture": "misko.jpg",
|
||||
"twitter": "mhevery",
|
||||
"website": "http://misko.hevery.com",
|
||||
"bio": "Miško Hevery is the creator of AngularJS framework. He has passion for making complex things simple. He currently works at Google, but has previously worked at Adobe, Sun Microsystems, Intel, and Xerox, where he became an expert in building web applications in web related technologies such as Java, JavaScript, Flex and ActionScript.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "kara"
|
||||
},
|
||||
"igor": {
|
||||
"igorminar": {
|
||||
"name": "Igor Minar",
|
||||
"picture": "igor-minar.jpg",
|
||||
"twitter": "IgorMinar",
|
||||
"website": "https://google.com/+IgorMinar",
|
||||
"bio": "Igor is a software engineer at Google. He is a lead on the Angular project, practitioner of test driven development, open source enthusiast, hacker. In his free time, Igor enjoys spending time with his wife and two kids, doing outdoor activities (including but not limited to sports, gardening and building retaining walls).",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "bradlygreen"
|
||||
},
|
||||
"naomi": {
|
||||
"name": "Naomi Black",
|
||||
"picture": "naomi.jpg",
|
||||
"twitter": "naomitraveller",
|
||||
"website": "http://google.com/+NaomiBlack",
|
||||
"bio": "Naomi is Angular's TPM generalist and jack-of-all-trades. She supports Angular's internal Google users and solves hard-to-define problems. She's been at Google since 2006, as a technical program manager on projects ranging from Accessibility to Google Transit. She fights daleks in her spare time.",
|
||||
"group": "Angular"
|
||||
},
|
||||
"brad": {
|
||||
"bradlygreen": {
|
||||
"name": "Brad Green",
|
||||
"picture": "brad-green.jpg",
|
||||
"twitter": "bradlygreen",
|
||||
@ -31,29 +25,23 @@
|
||||
"bio": "Brad Green works at Google as an engineering director. Brad manages the Google Sales Platform suite of projects as well as the AngularJS framework. Prior to Google, Brad worked on the early mobile web at AvantGo, founded and sold startups, and spent a few hard years toiling as a caterer. Brad's first job out of school was as lackey to Steve Jobs at NeXT Computer writing demo software and designing his slide presentations. Brad enjoys throwing dinner parties with his wife Heather and putting on plays with his children.",
|
||||
"group": "Angular"
|
||||
},
|
||||
"juleskremer": {
|
||||
"name": "Jules Kremer",
|
||||
"picture": "juleskremer.jpg",
|
||||
"twitter": "jules_kremer",
|
||||
"website": "https://plus.google.com/+JulesKremer",
|
||||
"bio": "Jules is Head of Angular Developer Relations at Google. When not working with developers, Jules is often bending into pretzel-like shapes, creating paths through thick jungle with a machete or drinking really awesome beer.",
|
||||
"group": "Angular"
|
||||
},
|
||||
"jelbourn": {
|
||||
"name": "Jeremy Elbourn",
|
||||
"picture": "jelbourn.jpg",
|
||||
"twitter": "jelbourn",
|
||||
"website": "https://plus.google.com/+JeremyElbourn/",
|
||||
"bio": "Angular Material Team Lead. FE Engineer @ Google specializing in AngularJS, component design, and the cleanest of code.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "igorminar"
|
||||
},
|
||||
"pete": {
|
||||
"petebacondarwin": {
|
||||
"name": "Pete Bacon Darwin",
|
||||
"picture": "pete.jpg",
|
||||
"twitter": "petebd",
|
||||
"website": "http://www.bacondarwin.com",
|
||||
"bio": "AngularJS for JS Team Lead. Pete has been working on the core team since 2012 and became the team lead for the AngularJS for JS branch in November 2014. He has co-authored a book on AngularJS and regularly talks about and teaches Angular.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "igorminar"
|
||||
},
|
||||
"stephenfluin": {
|
||||
"name": "Stephen Fluin",
|
||||
@ -61,7 +49,8 @@
|
||||
"twitter": "stephenfluin",
|
||||
"website": "https://plus.google.com/+stephenfluin",
|
||||
"bio": "Stephen is a Developer Advocate working on the Angular team. Before joining Google, he was a Google Expert. Stephen loves to help enterprises use technology more effectively.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "bradlygreen"
|
||||
},
|
||||
"robwormald": {
|
||||
"name": "Rob Wormald",
|
||||
@ -69,23 +58,17 @@
|
||||
"twitter": "robwormald",
|
||||
"website": "http://github.com/robwormald",
|
||||
"bio": "Rob is a Developer Advocate on the Angular team at Google. He's the Angular team's resident reactive programming geek and founded the Reactive Extensions for Angular project, ngrx.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "stephenfluin"
|
||||
},
|
||||
"tobias": {
|
||||
"name": "Tobias Bosch",
|
||||
"picture": "tobias.jpg",
|
||||
"twitter": "tbosch1009",
|
||||
"website": "https://plus.google.com/+TobiasBosch",
|
||||
"bio": "Tobias Bosch is a software engineer at Google. He is part of the Angular core team and works on Angular.",
|
||||
"group": "Angular"
|
||||
},
|
||||
"rado": {
|
||||
"rkirov": {
|
||||
"name": "Rado Kirov",
|
||||
"picture": "rado.jpg",
|
||||
"twitter": "radokirov",
|
||||
"website": "https://plus.sandbox.google.com/+RadoslavKirov",
|
||||
"bio": "Rado has been on the Angular Core team since Summer 2014. Before Angular, he worked on the Adsense serving stack, responsible for serving billions of ads daily. Being passionate about open source, he made contributions to Angular as a Google-20% project, before making the fulltime jump. He is a recovering academic; ask him about error-correcting codes from algebraic curves (or don't).",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "mprobst"
|
||||
},
|
||||
"alexeagle": {
|
||||
"name": "Alex Eagle",
|
||||
@ -93,39 +76,61 @@
|
||||
"twitter": "jakeherringbone",
|
||||
"website": "http://google.com/+alexeagle",
|
||||
"bio": "Alex works on language tooling for JavaScript and TypeScript. Previously Alex spent five years in Google's developer testing tools. He has developed systems including Google's continuous integration service, capturing build&test failures, and explaining them to developers. Before Google, Alex worked at startups including Opower, and consulted for large government IT. In his 20% time, he created the Error-Prone static analysis tool, which detects common Java programming mistakes and reports them as compile errors.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "igorminar"
|
||||
},
|
||||
"martinprobst": {
|
||||
"kyliau": {
|
||||
"name": "Keen Yee Liau",
|
||||
"group": "Angular",
|
||||
"lead": "alexeagle",
|
||||
"picture": "kyliau.jpg"
|
||||
},
|
||||
"clydin": {
|
||||
"name": "Charles Lyding",
|
||||
"group": "Angular",
|
||||
"lead": "alexeagle",
|
||||
"picture": "clydin.jpg"
|
||||
},
|
||||
"alan-agius4": {
|
||||
"name": "Alan Agius",
|
||||
"group": "Angular",
|
||||
"lead": "alexeagle",
|
||||
"picture": "alan-agius4.jpg",
|
||||
"bio": "Angular CLI Member, Loves TypeScript, Build Tools, Food, Beer & Coffee :)"
|
||||
},
|
||||
"gregmagolan": {
|
||||
"name": "Greg Magolan",
|
||||
"group": "Angular",
|
||||
"lead": "alexeagle",
|
||||
"picture": "gregmagolan.jpg",
|
||||
"bio": "Building great software with Angular and Node.js."
|
||||
},
|
||||
"mprobst": {
|
||||
"name": "Martin Probst",
|
||||
"picture": "martin-probst.jpg",
|
||||
"twitter": "martin_probst",
|
||||
"website": "http://probst.io",
|
||||
"bio": "Martin is a software engineer at Google in the AngularJS team. He holds a MSc in Software Engineering from HPI in Potsdam, Germany. Before joining the AngularJS team at Google, he worked at a database startup in the Netherlands, at EMC, at SAP, and as a freelancer. In his free time, he likes to cook and sail, not necessarily at the same time.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "bradlygreen"
|
||||
},
|
||||
"julieralph": {
|
||||
"name": "Julie Ralph",
|
||||
"picture": "julie-ralph.jpg",
|
||||
"twitter": "SomeJulie",
|
||||
"website": "https://plus.google.com/+JulieRalph",
|
||||
"bio": "Julie Ralph works as a Software Engineer in Test at Google in Seattle and is the lead developer on the Angular end-to-end testing framework Protractor.",
|
||||
"group": "Angular"
|
||||
},
|
||||
"alexrickabaugh": {
|
||||
"alxhub": {
|
||||
"name": "Alex Rickabaugh",
|
||||
"picture": "alex-rickabaugh.jpg",
|
||||
"twitter": "synalx",
|
||||
"website": "https://plus.google.com/+AlexRickabaugh/about",
|
||||
"bio": "Core team member working to optimize the Angular platform for the next generation of applications, including mobile. Before joining the Angular team, Alex worked in the Google sales organization where he helped build the first large Angular application within Google.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "kara"
|
||||
},
|
||||
"matias": {
|
||||
"matsko": {
|
||||
"name": "Matias Niemela",
|
||||
"picture": "matias.jpg",
|
||||
"twitter": "yearofmoo",
|
||||
"website": "http://yearofmoo.com",
|
||||
"bio": "Matias Niemela is a fullstack web developer who has been programming & building websites for over 10 years, and a core team member of AngularJS for two years. In the spring of 2015 Matias joined Angular full time at Google. In his free time Matias loves to build complex things and is always up for public speaking, travelling and tweaking his current Vim setup.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "kara"
|
||||
},
|
||||
"hansl": {
|
||||
"name": "Hans Larsen",
|
||||
@ -133,7 +138,8 @@
|
||||
"twitter": "hanslatwork",
|
||||
"website": "http://www.codingatwork.com/",
|
||||
"bio": "Hans is a software engineer at Google on the Angular team and was previously at Slack. He works everyday to help make it easier for everyone to create beautiful, consistent web applications using Angular, using Material Design components and the CLI tool.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "alexeagle"
|
||||
},
|
||||
"kara": {
|
||||
"name": "Kara Erickson",
|
||||
@ -141,52 +147,40 @@
|
||||
"twitter": "karaforthewin",
|
||||
"website": "https://github.com/kara",
|
||||
"bio": "Kara is a software engineer on the Angular team at Google and a co-organizer of the Angular-SF Meetup. Prior to Google, she helped build UI components in Angular for guest management systems at OpenTable. She enjoys snacking indiscriminately and probably other things too.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "igorminar"
|
||||
},
|
||||
"chuckj": {
|
||||
"name": "Chuck Jazdzewski",
|
||||
"picture": "chuckj.jpg",
|
||||
"twitter": "chuckjaz",
|
||||
"website": "http://removingalldoubt.com",
|
||||
"bio": "Chuck is a Software Engineer on the Angular team at Google. He is a programming language geek, UI framework and component library veteran, and has a passion for simplifying the task of programming. Before Google, he worked at Microsoft and Borland.",
|
||||
"group": "Angular"
|
||||
},
|
||||
"vikram": {
|
||||
"vikerman": {
|
||||
"name": "Vikram Subramanian",
|
||||
"picture": "vikram.jpg",
|
||||
"twitter": "vikerman",
|
||||
"bio": "Vikram is a Software Engineer on the Angular team focused on Engineering Productivity. That means he makes sure people on the team can move fast and not break things. Vikram enjoys doing Yoga and going on walks with his daughter.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "alexeagle"
|
||||
},
|
||||
"maxsills": {
|
||||
"name": "Max Sills",
|
||||
"picture": "max-sills.jpg",
|
||||
"twitter": "angularjs",
|
||||
"website": "http://google-opensource.blogspot.com/",
|
||||
"bio": "Max Sills is Angular's Open Source lawyer.",
|
||||
"group": "Angular"
|
||||
},
|
||||
"pawel": {
|
||||
"pkozlowski-opensource": {
|
||||
"name": "Pawel Kozlowski",
|
||||
"picture": "pawel.jpg",
|
||||
"twitter": "pkozlowski_os",
|
||||
"bio": "Open source hacker, AngularJS book author, AngularUI lead developer. Pawel is an software-development addict who believes in free, open source software. He is a core contributor to the AngularJS framework, AngularUI, Karma-runner and several other projects. He is the co-author of the \"Mastering Web Application Development with AngularJS\" book. When not coding, Pawel can be spotted speaking at various software development conferences.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "kara"
|
||||
},
|
||||
"paulgschwendtner": {
|
||||
"devversion": {
|
||||
"name": "Paul Gschwendtner",
|
||||
"picture": "devversion.jpg",
|
||||
"twitter": "DevVersion",
|
||||
"website": "https://github.com/DevVersion",
|
||||
"bio": "Paul is a 17-year-old developer living in Germany. While he attends school, Paul works as a core team member on Angular Material. Paul focuses on tooling and building components for Angular.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "kara"
|
||||
},
|
||||
"elad": {
|
||||
"EladBezalel": {
|
||||
"name": "Elad Bezalel",
|
||||
"picture": "eladbezalel.jpg",
|
||||
"website": "https://github.com/EladBezalel",
|
||||
"bio": "Elad is a fullstack developer with a very strong love for design. Since 8 years old, he's been designing in Photoshop and later on fell in love with programing. This strong bond between design and computer programming gave birth to a new kind of love. And he is currently doing the combination of both, as a core member of the ngMaterial project.",
|
||||
"group": "Angular"
|
||||
"group": "GDE"
|
||||
},
|
||||
"marclaval": {
|
||||
"name": "Marc Laval",
|
||||
@ -194,7 +188,8 @@
|
||||
"twitter": "marclaval",
|
||||
"website": "https://github.com/mlaval",
|
||||
"bio": "Marc is a manager at Amadeus where he leads the team in charge of developing and recommending UI frameworks for the company. He is also an open source developer and a contributor to Angular.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "kara"
|
||||
},
|
||||
"wardbell": {
|
||||
"name": "Ward Bell",
|
||||
@ -202,14 +197,15 @@
|
||||
"website": "https://github.com/wardbell",
|
||||
"twitter": "wardbell",
|
||||
"bio": "Ward is an all-around developer with JavaScript, Node.js®, and .net chops. He's a frequent conference speaker and podcaster, trainer, Google Developer Expert for Angular, Microsoft MVP, and PluralSight author. He is also president of IdeaBlade, an enterprise software consulting firm and the makers of breeze.js. He would like to get more sleep and spend more time in the mountains.",
|
||||
"group": "Angular"
|
||||
"group": "GDE"
|
||||
},
|
||||
"martinstaffa": {
|
||||
"Narretz": {
|
||||
"name": "Martin Staffa",
|
||||
"picture": "martinstaffa.jpg",
|
||||
"twitter": "Narretz",
|
||||
"bio": "Martin is an English major turned web developer who loves frontend stuff. He's been part of the AngularJS team since 2014. If you can't find him roaming the Github issue queues, he's probably out with his camera somewhere.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "petebacondarwin"
|
||||
},
|
||||
"filipesilva": {
|
||||
"name": "Filipe Silva",
|
||||
@ -217,29 +213,24 @@
|
||||
"twitter": "filipematossilv",
|
||||
"website": "http://github.com/filipesilva",
|
||||
"bio": "Filipe is a passion-driven developer that always strives for the most elegant solution for each problem. He is currently an author for Angular.io, a core contributor for Angular-CLI and senior front end engineer at KonnectAgain. When not busy going through PRs, you can find him scouring reddit for new dinner recipes to cook or enjoying a craft beer in Dublin.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "alexeagle"
|
||||
},
|
||||
"andrewseguin": {
|
||||
"name": "Andrew Seguin",
|
||||
"picture": "andrewseguin.jpg",
|
||||
"website": "http://github.com/andrewseguin",
|
||||
"bio": "Andrew is an engineer on the Angular Material team working on bringing material components to the world. When he’s not obsessing over pixels and design, he is probably off somewhere having adventures with his wife and daughters.",
|
||||
"group": "Angular"
|
||||
},
|
||||
"jesusrodriguez": {
|
||||
"name": "Jesús Rodríguez",
|
||||
"picture": "jesus-rodriguez.jpg",
|
||||
"twitter": "foxandxss",
|
||||
"website": "http://angular-tips.com",
|
||||
"bio": "Jesus is an open source lover, a book author and editor, and AngularUI lead developer. He is currently a core contributor to the UI Bootstrap project.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "jelbourn"
|
||||
},
|
||||
"crisbeto": {
|
||||
"name": "Kristiyan Kostadinov",
|
||||
"picture": "crisbeto.jpg",
|
||||
"website": "http://crisbeto.com/",
|
||||
"bio": "Kristiyan is a front-end developer, passionate open-source contributor and a core team member on Angular Material.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "jelbourn"
|
||||
},
|
||||
"gkalpak": {
|
||||
"name": "Georgios Kalpakas",
|
||||
@ -247,19 +238,22 @@
|
||||
"twitter": "gkalpakas",
|
||||
"website": "https://github.com/gkalpak",
|
||||
"bio": "George is a Software Engineer with a passion for chess, robotics and automating stuff. He has a strong need to know how things work (so if you already know, he'd love to have a talk with you). He has been a member of the AngularJS team since 2014. When not doing geeky stuff, he is probably trying to convince his wife and kids to apply programming principles in real life. (Or is it the other way around?)",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "igorminar"
|
||||
},
|
||||
"mmalerba": {
|
||||
"name": "Miles Malerba",
|
||||
"picture": "mmalerba.jpg",
|
||||
"bio": "Miles is a software engineer on the Angular Material team at Google. In addition to Javascripting he enjoys eating food and ogling cute puppies.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "jelbourn"
|
||||
},
|
||||
"jasonaden": {
|
||||
"name": "Jason Aden",
|
||||
"picture": "jasonaden.jpg",
|
||||
"bio": "Jason is a software engineer at Google on the Angular Core team. He is enthusiastic about Angular and application development in the modern age. In his free time Jason enjoys spending time with his wife and four children and doing outdoor activities (hiking, fishing, snowboarding, etc.).",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "igorminar"
|
||||
},
|
||||
"jeffwhelpley": {
|
||||
"name": "Jeff Whelpley",
|
||||
@ -299,13 +293,14 @@
|
||||
"bio": "Ralph(Zhicheng Wang) is a senior consultant at ThoughtWorks and also a GDE. He is a technology enthusiast and he is a passionate advocate of 'Simplicity, Professionalism and Sharing'. In his eighteen years of R&D career, he worked as tester, R&D engineer, project manager, product manager and CTO. He is immersed in the excitement of the arrival of the baby.",
|
||||
"group": "GDE"
|
||||
},
|
||||
"wassim": {
|
||||
"manekinekko": {
|
||||
"name": "Wassim Chegham",
|
||||
"picture": "wassim.jpg",
|
||||
"twitter": "manekinekko",
|
||||
"website": "https://medium.com/@wassimchegham",
|
||||
"bio": "Wassim (aka manekinekko on Twitter/Github) is a Developer Advocate at SFEIR, in Web technologies (Angular, Polymer, PWA, Web Components...). He is also a Developer Expert in Web technologies nominated by Google. He enjoys writing technical articles, meeting developers at events, speaking at conferences and contributing to open source projects. Wassim loves the Web Platform and works hard to move it forward.",
|
||||
"group": "GDE"
|
||||
"group": "Angular",
|
||||
"mentor": "filipesilva"
|
||||
},
|
||||
"chrisnoring": {
|
||||
"name": "Christoffer Noring",
|
||||
@ -337,14 +332,8 @@
|
||||
"twitter": "splaktar",
|
||||
"website": "https://www.DevIntent.com",
|
||||
"bio": "Lead for AngularJS Material. Owner and consultant at DevIntent. Ex-Angular GDE. Founder of the Google Developers Group (GDG) community on the Space Coast of Florida, USA.",
|
||||
"group": "Angular"
|
||||
},
|
||||
"mikebrocchi": {
|
||||
"name": "Mike Brocchi",
|
||||
"picture": "mike-brocchi.jpg",
|
||||
"twitter": "brocco",
|
||||
"bio": "Mike is a core team member of the Angular CLI team, a GDE and is also an instructor at egghead. Mike is passionate about helping others by writing code as well as teaching.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "jelbourn"
|
||||
},
|
||||
"manfredsteyer": {
|
||||
"name": "Manfred Steyer",
|
||||
@ -370,15 +359,16 @@
|
||||
"bio": "Based in Austin Texas, Jeremy is an application architect and homebrewer. He is a Google Developer Expert in Web Technologies and Angular, with a focus on speaking and training and author of Angular in Action and Ionic in Action.",
|
||||
"group": "GDE"
|
||||
},
|
||||
"minko": {
|
||||
"mgechev": {
|
||||
"name": "Minko Gechev",
|
||||
"picture": "minko.jpg",
|
||||
"twitter": "mgechev",
|
||||
"website": "http://blog.mgechev.com",
|
||||
"bio": "Software engineer who enjoys theoretical computer science and its practical applications. Speaker, author of the book 'Switching to Angular', codelyzer, Guess.js, and the Go linter revive. Working for faster and more reliable software.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "alexeagle"
|
||||
},
|
||||
"uri": {
|
||||
"urish": {
|
||||
"name": "Uri Shaked",
|
||||
"picture": "urish.jpg",
|
||||
"twitter": "UriShaked",
|
||||
@ -415,7 +405,8 @@
|
||||
"picture": "ocombe.jpg",
|
||||
"twitter": "ocombe",
|
||||
"bio": "Olivier is a passionate front-end engineer who loves interacting with the community by doing open source projects (ocLazyLoad, ngx-translate…), being a panelist at Angular-Air, giving talks or just chatting on Twitter and Slack. He’s a member of the Angular Core team and works on i18n.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "kara"
|
||||
},
|
||||
"cironunes": {
|
||||
"name": "Ciro Nunes",
|
||||
@ -446,7 +437,7 @@
|
||||
"bio": "Co-founder and CTO of Thinktecture AG, as well as Google GDE and Microsoft MVP. Since two decades active as an engaged and passionate speaker on several software conferences and events all over the world. Some people call him 'Mr. Cross-Platform'.",
|
||||
"group": "GDE"
|
||||
},
|
||||
"shaireznik": {
|
||||
"shairez": {
|
||||
"name": "Shai Reznik",
|
||||
"picture": "shaireznik.jpg",
|
||||
"twitter": "shai_reznik",
|
||||
@ -486,7 +477,7 @@
|
||||
"bio": "GDE (Google Developer Expert) Angular and Web Technologies, Women Who Code KL Director, Jecelyn specializes in professional application development with technologies, including Angular, HTML5, Typescript, JavaScript, CSS, C#, NodeJs, Cloud and ASP.NET.",
|
||||
"group": "GDE"
|
||||
},
|
||||
"vincirufus": {
|
||||
"areai51": {
|
||||
"name": "Vinci Rufus",
|
||||
"picture": "vincirufus.jpg",
|
||||
"twitter": "areai51",
|
||||
@ -494,7 +485,7 @@
|
||||
"bio": "Director of Experience Technology at SapientRazorfish. Consults various brands on their frontend and mobile web architecture. A speaker at various forums and mentor at Launchpad Accelerator and ngGirls India. Spends free time playing with Angular, Preact, web-components ",
|
||||
"group": "GDE"
|
||||
},
|
||||
"thierrychatel": {
|
||||
"tchatel": {
|
||||
"name": "Thierry Chatel",
|
||||
"picture": "thierrychatel.jpg",
|
||||
"twitter": "ThierryChatel",
|
||||
@ -510,14 +501,6 @@
|
||||
"bio": "Gerard is very excited about the future of the Web and JavaScript. Always happy Computer Science Engineer and humble Google Developer Expert. He loves to share his learnings by giving talks, trainings and writing about cool technologies. He loves running AngularZone and GraphQL London, mentoring students and giving back to the community.",
|
||||
"group": "GDE"
|
||||
},
|
||||
"amcdnl": {
|
||||
"name": "Austin McDaniel",
|
||||
"picture": "amcdnl.jpeg",
|
||||
"twitter": "amcdnl",
|
||||
"website": "https://amcdnl.com",
|
||||
"bio": "Austin is an software architect with a passion for JavaScript and Angular. Austin loves to share his experiences with other like-minded developers by giving talks, blogging, podcasting and open-sourcing.",
|
||||
"group": "Angular"
|
||||
},
|
||||
"nirkaufman": {
|
||||
"name": "Nir Kaufman",
|
||||
"picture": "nirkaufman.jpg",
|
||||
@ -579,7 +562,8 @@
|
||||
"picture": "elanaolson.jpg",
|
||||
"twitter": "elanathellama",
|
||||
"bio": "Elana is a Developer Relations intern on the Angular team at Google. She is working on migration paths from AngularJS to Angular and would love to chat about your experience with upgrading.",
|
||||
"group": "Angular"
|
||||
"group": "Angular",
|
||||
"lead": "stephenfluin"
|
||||
},
|
||||
"kevinyang": {
|
||||
"name": "Kevin Yang",
|
||||
@ -675,5 +659,100 @@
|
||||
"website": "http://www.samjulien.com/",
|
||||
"bio": "Sam Julien builds software, articles, video courses, and campfires. A developer, speaker, writer, and GDE in the Pacific Northwest, Sam's favorite thing in the world is changing someone's life by teaching them to code.",
|
||||
"group": "GDE"
|
||||
},
|
||||
"JiaLiPassion": {
|
||||
"name": "JiaLi Passion",
|
||||
"group": "Collaborator",
|
||||
"mentor": "mhevery",
|
||||
"picture": "JiaLiPassion.jpg",
|
||||
"bio": "A programmer with passion, angular/zone.js guy! Web frontend engineer @sylabs"
|
||||
},
|
||||
"cexbrayat": {
|
||||
"name": "Cédric Exbrayat",
|
||||
"mentor": "petebacondarwin",
|
||||
"group": "Collaborator",
|
||||
"picture": "cexbrayat.jpg",
|
||||
"bio": "Author of `Become a ninja with Angular (2+)` https://books.ninja-squad.com/angular - Angular trainer and @Ninja-Squad co-founder"
|
||||
},
|
||||
"CaerusKaru": {
|
||||
"name": "Adam Plumer",
|
||||
"group": "Collaborator",
|
||||
"mentor": "vikerman",
|
||||
"picture": "CaerusKaru.jpg"
|
||||
},
|
||||
"jbedard": {
|
||||
"name": "Jason Bedard",
|
||||
"group": "Collaborator",
|
||||
"mentor": "kyliau",
|
||||
"picture": "jbedard.png"
|
||||
},
|
||||
"jschwarty": {
|
||||
"name": "Justin Schwartzenberger",
|
||||
"picture": "justinschwartzenberger.jpg",
|
||||
"twitter": "schwarty",
|
||||
"website": "https://schwarty.com",
|
||||
"bio": "Justin (aka Schwarty) is a Google Developer Expert in Web Technologies and Angular, the host and maintainer of the weekly AngularAir live video broadcast, educator, writer and content creator. He has Angular courses available on LinkedIn Learning and Pluralsight and loves passing on years of full stack development knowledge to help empower others to find their inner awesomeness!",
|
||||
"group": "GDE"
|
||||
},
|
||||
"brandonroberts": {
|
||||
"name": "Brandon Roberts",
|
||||
"picture": "brandonroberts.jpg",
|
||||
"twitter": "brandontroberts",
|
||||
"website": "https://brandonroberts.dev",
|
||||
"bio": "Brandon is a developer and technical writer working on guides, tutorials, application development, and infrastructure for the Angular docs. He is also a maintainer of the NgRx project, building reactive libraries for Angular.",
|
||||
"group": "Angular",
|
||||
"lead": "dennispbrown"
|
||||
},
|
||||
"chembu": {
|
||||
"name": "Sreevani Sreejith",
|
||||
"picture": "sreevani.jpg",
|
||||
"bio": "Sreevani is a tech writer with prior programming experience. She writes documentation for the Angular framework team. Outside of work, she likes practicing yoga, honing her skills on classical dance forms, and baking cakes.",
|
||||
"group": "Angular",
|
||||
"lead": "dennispbrown"
|
||||
},
|
||||
"dennispbrown": {
|
||||
"name": "Denny Brown",
|
||||
"picture": "denny.jpg",
|
||||
"bio": "Denny is founder of Expert Support, a professional services firm specializing in technical communication, and leads the Angular technical writing team. His lifelong passion has been to reduce the time and effort required to understand complex technical information. Early on, he was Associate Chairman of the Computer Science Department at Stanford, where he taught introductory courses in programming. He also plays old-timers baseball in local leagues and national tournaments.",
|
||||
"group": "Angular",
|
||||
"lead": "bradlygreen"
|
||||
},
|
||||
"jbogarthyde": {
|
||||
"name": "Judy Bogart",
|
||||
"picture": "judy.png",
|
||||
"group": "Angular",
|
||||
"lead": "dennispbrown"
|
||||
},
|
||||
"jenniferfell": {
|
||||
"name": "Jennifer Fell",
|
||||
"picture": "jennifer.jpg",
|
||||
"website": "http://silverpath.org",
|
||||
"bio": "Jennifer is a technical content strategist, architect, designer, and writer. As lead of the Angular docs team, she's always interested in learning more about how developers learn and use Angular. Her offline persona is a horsewoman in Idaho.",
|
||||
"group": "Angular",
|
||||
"lead": "dennispbrown"
|
||||
},
|
||||
"kapunahelewong": {
|
||||
"name": "Kapunahele Wong",
|
||||
"picture": "kapunahele.jpg",
|
||||
"twitter": "kapunahele",
|
||||
"bio": "Kapunahele is a developer and Angular fan who works on the Angular docs writing guides and developing example apps. She also enjoys Native Hawaiian practices, textile arts, and marveling at little, inconspicuous plants growing in forgotten places outdoors.",
|
||||
"group": "Angular",
|
||||
"lead": "dennispbrown"
|
||||
},
|
||||
"luixaviles": {
|
||||
"name": "Luis Aviles",
|
||||
"picture": "luixaviles.jpg",
|
||||
"twitter": "luixaviles",
|
||||
"website": "https://luixaviles.com",
|
||||
"bio": "Luis is an enthusiast of Open Source software and communities, as well as being a public speaker, a technology trainer and an author of courses and technical articles. He is the organizer of the Angular Bolivia community and NG Bolivia conference. When he's not coding, Luis is reading about Astronomy or nerding about outer space, photography or even doing Astrophotography.",
|
||||
"group": "GDE"
|
||||
},
|
||||
"siddajmera": {
|
||||
"name": "Siddharth Ajmera",
|
||||
"picture": "sidd-ajmera.jpg",
|
||||
"twitter": "SiddAjmera",
|
||||
"website": "https://webstackup.com/",
|
||||
"bio": "Siddharth is a Full Stack JavaScript Developer and a GDE in Angular. He's passionate about sharing his knowledge on Angular, Firebase and the Web in general. He's the organizer of WebStack, a local community of developers focused on Web, Mobile, Voice and Server related technologies in general. WebStack hosts free monthly meetups every 2nd or 3rd Saturday of the month. Siddharth is also an avid photographer and loves traveling. Find him anywhere on the Web with `SiddAjmera`.",
|
||||
"group": "GDE"
|
||||
}
|
||||
}
|
||||
}
|
@ -31,6 +31,12 @@
|
||||
<td>London, UK</td>
|
||||
<td>September 19-20, 2019</td>
|
||||
</tr>
|
||||
<!-- NG-DE 2019-->
|
||||
<tr>
|
||||
<th><a href="https://ng-de.org/" title="NG-DE">NG-DE</a></th>
|
||||
<td>Berlin, Germany</td>
|
||||
<td>August 29th workshops, 30-31 conference, 2019</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -452,6 +452,11 @@
|
||||
"title": "Getting Started",
|
||||
"tooltip": "Enabling the service worker in a CLI project and observing behavior in the browser."
|
||||
},
|
||||
{
|
||||
"url": "guide/app-shell",
|
||||
"title": "App Shell",
|
||||
"tooltip": "Enabling the App Shell in a CLI project."
|
||||
},
|
||||
{
|
||||
"url": "guide/service-worker-communications",
|
||||
"title": "Service Worker Communication",
|
||||
@ -768,4 +773,4 @@
|
||||
{ "title": "v4", "url": "https://v4.angular.io" },
|
||||
{ "title": "v2", "url": "https://v2.angular.io" }
|
||||
]
|
||||
}
|
||||
}
|
@ -116,7 +116,7 @@ Most apps strive for a consistent look across the application.
|
||||
The CLI generated an empty `styles.css` for this purpose.
|
||||
Put your application-wide styles there.
|
||||
|
||||
Here's an excerpt from the `styles.css` for the _Tour of Heroes_ sample app.
|
||||
Open `src/styles.css` and add the code below to the file.
|
||||
|
||||
<code-example path="toh-pt0/src/styles.1.css" header="src/styles.css (excerpt)">
|
||||
</code-example>
|
||||
|
@ -267,7 +267,7 @@ Use the CLI to create the `MessagesComponent`.
|
||||
ng generate component messages
|
||||
</code-example>
|
||||
|
||||
The CLI creates the component files in the `src/app/messages` folder and declare `MessagesComponent` in `AppModule`.
|
||||
The CLI creates the component files in the `src/app/messages` folder and declares the `MessagesComponent` in `AppModule`.
|
||||
|
||||
Modify the `AppComponent` template to display the generated `MessagesComponent`
|
||||
|
||||
|
@ -169,4 +169,4 @@
|
||||
"xregexp": "^4.0.0",
|
||||
"yargs": "^7.0.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
"master": {
|
||||
"uncompressed": {
|
||||
"runtime": 3713,
|
||||
"main": 500343,
|
||||
"main": 509261,
|
||||
"polyfills": 53926
|
||||
}
|
||||
}
|
||||
|
3778
aio/yarn.lock
@ -1,7 +1,7 @@
|
||||
# Building and Testing Angular
|
||||
|
||||
This document describes how to set up your development environment to build and test Angular.
|
||||
It also explains the basic mechanics of using `git`, `node`, and `npm`.
|
||||
It also explains the basic mechanics of using `git`, `node`, and `yarn`.
|
||||
|
||||
* [Prerequisite Software](#prerequisite-software)
|
||||
* [Getting the Sources](#getting-the-sources)
|
||||
@ -59,12 +59,6 @@ Next, install the JavaScript modules needed to build and test Angular:
|
||||
yarn install
|
||||
```
|
||||
|
||||
**Optional**: In this document, we make use of installed npm package scripts and binaries
|
||||
(stored under `./node_modules/.bin`) by prefixing these command invocations with `$(yarn bin)`; in
|
||||
particular `gulp` and `protractor` commands.
|
||||
|
||||
|
||||
|
||||
## Windows only
|
||||
|
||||
In order to create the right symlinks, run **as administrator**:
|
||||
@ -91,40 +85,46 @@ To build Angular run:
|
||||
|
||||
Bazel is used as the primary tool for building and testing Angular. Building and testing is
|
||||
incremental with Bazel, and it's possible to only run tests for an individual package instead
|
||||
of for all packages.
|
||||
of for all packages. Read more about this in the [BAZEL.md](./BAZEL.md) document.
|
||||
|
||||
Read more about this in the [BAZEL.md](./BAZEL.md) document. You should execute all test suites
|
||||
before submitting a PR to Github.
|
||||
You should execute all test suites before submitting a PR to GitHub:
|
||||
- `yarn bazel test packages/...`
|
||||
|
||||
All the tests are executed on our Continuous Integration infrastructure and a PR could only be
|
||||
**Note**: The first test run will be much slower than future runs. This is because future runs will
|
||||
benefit from Bazel's capability to do incremental builds.
|
||||
|
||||
All the tests are executed on our Continuous Integration infrastructure. PRs can only be
|
||||
merged if the code is formatted properly and all tests are passing.
|
||||
|
||||
## <a name="clang-format"></a> Formatting your source code
|
||||
|
||||
Angular uses [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to format the source code.
|
||||
If the source code is not properly formatted, the CI will fail and the PR can not be merged.
|
||||
If the source code is not properly formatted, the CI will fail and the PR cannot be merged.
|
||||
|
||||
You can automatically format your code by running:
|
||||
- `gulp format`: re-format only edited source code.
|
||||
- `gulp format:all`: format _all_ source code
|
||||
- `yarn gulp format`: re-format only edited source code.
|
||||
- `yarn gulp format:all`: format _all_ source code
|
||||
|
||||
A better way is to set up your IDE to format the changed file on each file save.
|
||||
|
||||
### VS Code
|
||||
1. Install [Clang-Format](https://marketplace.visualstudio.com/items?itemName=xaver.clang-format) extension for VS Code.
|
||||
2. Open `settings.json` in your workspace and add these lines:
|
||||
```json
|
||||
"files.autoSave": "onFocusChange",
|
||||
"editor.formatOnSave": true,
|
||||
"clang-format.executable": "PATH_TO_YOUR_WORKSPACE/angular/node_modules/.bin/clang-format",
|
||||
```
|
||||
|
||||
It will automatically pick up the settings from Angular's [settings.json](../.vscode/settings.json).
|
||||
|
||||
### WebStorm / IntelliJ
|
||||
1. Install the [ClangFormatIJ](https://plugins.jetbrains.com/plugin/8396-clangformatij) plugin
|
||||
1. Open `Preferences->Tools->clang-format`
|
||||
1. Find the field named "PATH"
|
||||
1. Add `<PATH_TO_YOUR_WORKSPACE>/angular/node_modules/clang-format/bin/<OS>/`
|
||||
where the OS options are: `darwin_x64`, `linux_x64`, and `win32`.
|
||||
|
||||
## Linting/verifying your source code
|
||||
|
||||
You can check that your code is properly formatted and adheres to coding style by running:
|
||||
|
||||
``` shell
|
||||
$ gulp lint
|
||||
$ yarn gulp lint
|
||||
```
|
||||
|
||||
## Publishing snapshot builds
|
||||
@ -138,17 +138,17 @@ You may find that your un-merged change needs some validation from external part
|
||||
Rather than requiring them to pull your Pull Request and build Angular locally, you can
|
||||
publish the `*-builds` snapshots just like our CircleCI build does.
|
||||
|
||||
First time, you need to create the github repositories:
|
||||
First time, you need to create the GitHub repositories:
|
||||
|
||||
``` shell
|
||||
$ export TOKEN=[get one from https://github.com/settings/tokens]
|
||||
$ CREATE_REPOS=1 ./scripts/ci/publish-build-artifacts.sh [github username]
|
||||
$ CREATE_REPOS=1 ./scripts/ci/publish-build-artifacts.sh [GitHub username]
|
||||
```
|
||||
|
||||
For subsequent snapshots, just run
|
||||
|
||||
``` shell
|
||||
$ ./scripts/publish/publish-build-artifacts.sh [github username]
|
||||
$ ./scripts/ci/publish-build-artifacts.sh [GitHub username]
|
||||
```
|
||||
|
||||
The script will publish the build snapshot to a branch with the same name as your current branch,
|
||||
@ -158,27 +158,9 @@ and create it if it doesn't exist.
|
||||
### VS Code
|
||||
|
||||
1. Install [Bazel](https://marketplace.visualstudio.com/items?itemName=DevonDCarew.bazel-code) extension for VS Code.
|
||||
2. Open `settings.json` in your workspace and add these lines:
|
||||
```json
|
||||
"files.associations": {
|
||||
"*.bazel": "bazel"
|
||||
},
|
||||
```
|
||||
|
||||
## General IDE settings
|
||||
### VS Code
|
||||
### WebStorm / IntelliJ
|
||||
1. Install the [Bazel](https://plugins.jetbrains.com/plugin/8609-bazel) plugin
|
||||
1. You can find the settings under `Preferences->Other Settings->Bazel Settings`
|
||||
|
||||
1. Open `settings.json` in your workspace and add these lines:
|
||||
```json
|
||||
"editor.tabSize": 2,
|
||||
"files.exclude": {
|
||||
"bazel-out": true,
|
||||
".idea": true,
|
||||
".circleci": true,
|
||||
".github": true,
|
||||
"dist/**": true,
|
||||
"node_modules/**": true,
|
||||
".rpt2_cache": true,
|
||||
".vscode": true
|
||||
},
|
||||
```
|
||||
It will automatically recognize `*.bazel` and `*.bzl` files.
|
||||
|
@ -31,8 +31,7 @@ The components have a clear piece of source code associated with it within the `
|
||||
* `comp: server`
|
||||
* `comp: service-worker`
|
||||
* `comp: testing`
|
||||
* `comp: upgrade/dynamic`
|
||||
* `comp: upgrade/static`
|
||||
* `comp: upgrade`
|
||||
* `comp: web-worker`
|
||||
* `comp: zones`
|
||||
|
||||
@ -112,10 +111,9 @@ Triaging PRs is the same as triaging issues, except that PRs have additional lab
|
||||
|
||||
Every triaged PR must have a `pr_action` label assigned to it:
|
||||
|
||||
* `PR action: review` - work is complete and comment is needed from the reviewers.
|
||||
* `PR action: cleanup` - more work is needed from the author.
|
||||
* `PR action: discuss` - discussion is needed, to be led by the author.
|
||||
* `PR action: merge` - the PR author is ready for the changes to be merged by the caretaker as soon as the PR is green (or merge-assistance label is applied and caretaker has deemed it acceptable manually). In other words, this label indicates to "auto submit when ready".
|
||||
* `PR action: merge` - the PR author is ready for the changes to be merged by the caretaker as soon as the PR is green (or merge-assistance label is applied and caretaker has deemed it acceptable manually). In other words, this label indicates to "auto submit when ready".
|
||||
|
||||
|
||||
In addition, PRs can have the following states:
|
||||
@ -123,6 +121,8 @@ In addition, PRs can have the following states:
|
||||
* `PR state: WIP` - PR is experimental or rapidly changing. Not ready for review or triage.
|
||||
* `PR state: blocked` - PR is blocked on an issue or other PR. Not ready for review or triage or merge.
|
||||
|
||||
When a PR is ready for review, a review should be requested using the Reviewers interface in Github.
|
||||
|
||||
|
||||
## PR Target
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "angular-srcs",
|
||||
"version": "7.2.9",
|
||||
"version": "7.2.10",
|
||||
"private": true,
|
||||
"branchPattern": "2.0.*",
|
||||
"description": "Angular - a web framework for modern web apps",
|
||||
|
@ -1,8 +1,14 @@
|
||||
load("//packages/bazel:index.bzl", "protractor_web_test_suite")
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_devserver")
|
||||
load("@npm_bazel_typescript//:index.bzl", "ts_config", "ts_devserver")
|
||||
load("@build_bazel_rules_nodejs//:defs.bzl", "http_server", "rollup_bundle")
|
||||
load("//tools:defaults.bzl", "ts_library")
|
||||
|
||||
ts_config(
|
||||
name = "tsconfig-test",
|
||||
src = "tsconfig-test.json",
|
||||
deps = [":tsconfig.json"],
|
||||
)
|
||||
|
||||
ts_library(
|
||||
name = "app",
|
||||
srcs = ["app.ts"],
|
||||
@ -34,7 +40,7 @@ ts_library(
|
||||
name = "ts_spec",
|
||||
testonly = True,
|
||||
srcs = ["test.spec.ts"],
|
||||
tsconfig = ":tsconfig.test.json",
|
||||
tsconfig = ":tsconfig-test",
|
||||
deps = [
|
||||
"@npm//@types/selenium-webdriver",
|
||||
"@npm//protractor",
|
||||
|
@ -180,6 +180,7 @@ export class MetadataBundler {
|
||||
|
||||
// Export all the re-exports from this module
|
||||
if (module && module.exports) {
|
||||
let unnamedModuleExportsIdx = 0;
|
||||
for (const exportDeclaration of module.exports) {
|
||||
const exportFrom = resolveModule(exportDeclaration.from, moduleName);
|
||||
// Record all the exports from the module even if we don't use it directly.
|
||||
@ -202,7 +203,12 @@ export class MetadataBundler {
|
||||
// Re-export all the symbols from the module
|
||||
const exportedSymbols = this.exportAll(exportFrom);
|
||||
for (const exportedSymbol of exportedSymbols) {
|
||||
const name = exportedSymbol.name;
|
||||
// In case the exported symbol does not have a name, we need to give it an unique
|
||||
// name for the current module. This is necessary because there can be multiple
|
||||
// unnamed re-exports in a given module.
|
||||
const name = exportedSymbol.name === '*' ?
|
||||
`unnamed_reexport_${unnamedModuleExportsIdx++}` :
|
||||
exportedSymbol.name;
|
||||
exportSymbol(exportedSymbol, name);
|
||||
}
|
||||
}
|
||||
|
@ -422,6 +422,21 @@ describe('metadata bundler', () => {
|
||||
expect(result.metadata.origins !['E']).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should be able to bundle a library with multiple unnamed re-exports', () => {
|
||||
const host = new MockStringBundlerHost('/', {
|
||||
'public-api.ts': `
|
||||
export * from '@mypkg/secondary1';
|
||||
export * from '@mypkg/secondary2';
|
||||
`,
|
||||
});
|
||||
|
||||
const bundler = new MetadataBundler('/public-api', undefined, host);
|
||||
const result = bundler.getMetadataBundle();
|
||||
expect(result.metadata.exports).toEqual([
|
||||
{from: '@mypkg/secondary1'}, {from: '@mypkg/secondary2'}
|
||||
]);
|
||||
});
|
||||
|
||||
it('should be able to de-duplicate symbols of re-exported modules', () => {
|
||||
const host = new MockStringBundlerHost('/', {
|
||||
'public-api.ts': `
|
||||
|
@ -18,6 +18,7 @@ export enum ChangeDetectionStrategy {
|
||||
* Use the `CheckOnce` strategy, meaning that automatic change detection is deactivated
|
||||
* until reactivated by setting the strategy to `Default` (`CheckAlways`).
|
||||
* Change detection can still be explicitly invoked.
|
||||
* This strategy applies to all child directives and cannot be overridden.
|
||||
*/
|
||||
OnPush = 0,
|
||||
|
||||
|
@ -517,12 +517,12 @@ export interface Component extends Directive {
|
||||
|
||||
/**
|
||||
* An encapsulation policy for the template and CSS styles. One of:
|
||||
* - `ViewEncapsulation.Native`: Use shadow roots. This works
|
||||
* only if natively available on the platform.
|
||||
* - `ViewEncapsulation.Native`: Deprecated. Use `ViewEncapsulation.ShadowDom` instead.
|
||||
* - `ViewEncapsulation.Emulated`: Use shimmed CSS that
|
||||
* emulates the native behavior.
|
||||
* - `ViewEncapsulation.None`: Use global CSS without any
|
||||
* encapsulation.
|
||||
* - `ViewEncapsulation.ShadowDom`: Use Shadow DOM v1 to encapsulate styles.
|
||||
*
|
||||
* If not supplied, the value is taken from `CompilerOptions`. The default compiler option is
|
||||
* `ViewEncapsulation.Emulated`.
|
||||
|
@ -226,7 +226,7 @@ export interface NgModule {
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* The following example allows MainModule to use anthing exported by
|
||||
* The following example allows MainModule to use anything exported by
|
||||
* `CommonModule`:
|
||||
*
|
||||
* ```javascript
|
||||
|
@ -52,7 +52,7 @@ class GiantList {
|
||||
selector: 'app',
|
||||
providers: [DataListProvider],
|
||||
template: `
|
||||
<giant-list><giant-list>
|
||||
<giant-list></giant-list>
|
||||
`,
|
||||
})
|
||||
class App {
|
||||
@ -86,7 +86,7 @@ class LiveData {
|
||||
providers: [DataProvider],
|
||||
template: `
|
||||
Live Update: <input type="checkbox" [(ngModel)]="live">
|
||||
<live-data [live]="live"><live-data>
|
||||
<live-data [live]="live"></live-data>
|
||||
`,
|
||||
})
|
||||
|
||||
|
@ -981,7 +981,7 @@ export class FormControl extends AbstractControl {
|
||||
* Sets a new value for the form control.
|
||||
*
|
||||
* @param value The new value for the control.
|
||||
* @param options Configuration options that determine how the control proopagates changes
|
||||
* @param options Configuration options that determine how the control propagates changes
|
||||
* and emits events when the value changes.
|
||||
* The configuration options are passed to the {@link AbstractControl#updateValueAndValidity
|
||||
* updateValueAndValidity} method.
|
||||
|
@ -61,7 +61,7 @@ export class HttpModule {
|
||||
/**
|
||||
* The module that includes jsonp's providers
|
||||
*
|
||||
* @deprecated see https://angular.io/guide/http
|
||||
* @deprecated see https://angular.io/api/common/http/HttpClient#jsonp
|
||||
* @publicApi
|
||||
*/
|
||||
@NgModule({
|
||||
|
@ -4,8 +4,12 @@ set -x -u -e -o pipefail
|
||||
|
||||
readonly currentDir=$(cd $(dirname $0); pwd)
|
||||
|
||||
# Command arguments that will be passed to sauce-connect.
|
||||
sauceArgs=""
|
||||
# Command arguments that will be passed to sauce-connect. By default we disable SSL bumping for
|
||||
# all requests. This is because SSL bumping is not needed for our test setup and in order
|
||||
# to perform the SSL bumping, Saucelabs intercepts all HTTP requests in the tunnel VM and modifies
|
||||
# them. This can cause flakiness as it makes all requests dependent on the SSL bumping middleware.
|
||||
# See: https://wiki.saucelabs.com/display/DOCS/Troubleshooting+Sauce+Connect#TroubleshootingSauceConnect-DisablingSSLBumping
|
||||
sauceArgs="--no-ssl-bump-domains all"
|
||||
|
||||
if [[ ! -z "${SAUCE_LOG_FILE:-}" ]]; then
|
||||
mkdir -p $(dirname ${SAUCE_LOG_FILE})
|
||||
|