refactor: move angular source to /packages rather than modules/@angular
This commit is contained in:
34
packages/examples/README.md
Normal file
34
packages/examples/README.md
Normal file
@ -0,0 +1,34 @@
|
||||
# API Examples
|
||||
|
||||
This folder contains small example apps that get in-lined into our API docs.
|
||||
Each example contains tests for application behavior (as opposed to testing Angular's
|
||||
behavior) just like an Angular application developer would write.
|
||||
|
||||
# Running the examples
|
||||
|
||||
```
|
||||
# # execute the following command only when framework code changes
|
||||
./build.sh
|
||||
|
||||
# run when test change
|
||||
./modules/@angular/examples/build.sh
|
||||
|
||||
# start server
|
||||
$(npm bin)/gulp serve-examples
|
||||
```
|
||||
|
||||
navigate to [http://localhost:8001](http://localhost:8001)
|
||||
|
||||
# Running the tests
|
||||
|
||||
```
|
||||
# run only when framework code changes
|
||||
./build.sh
|
||||
|
||||
# run to compile tests and run them
|
||||
./modules/@angular/examples/test.sh
|
||||
```
|
||||
|
||||
NOTE: sometimes the http server does not exit properly and it retains the `8001` port.
|
||||
in such a case you can use `lsof -i:8001` to see which process it is and then use `kill`
|
||||
to remove it. (Or in single command: `lsof -i:8001 -t | xargs kill`)
|
20
packages/examples/_common/bootstrap.ts
Normal file
20
packages/examples/_common/bootstrap.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
(function(global: any) {
|
||||
writeScriptTag('/vendor/zone.js');
|
||||
writeScriptTag('/vendor/system.js');
|
||||
writeScriptTag('/vendor/Reflect.js');
|
||||
writeScriptTag('/_common/system-config.js');
|
||||
if (location.pathname.indexOf('/upgrade/') != -1) {
|
||||
writeScriptTag('/vendor/angular.js');
|
||||
}
|
||||
|
||||
function writeScriptTag(scriptUrl: string, onload: string = '') {
|
||||
document.write('<script src="' + scriptUrl + '" onload="' + onload + '"></script>');
|
||||
}
|
||||
}(window));
|
26
packages/examples/_common/e2e_util.ts
Normal file
26
packages/examples/_common/e2e_util.ts
Normal file
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
/* tslint:disable:no-console */
|
||||
import * as webdriver from 'selenium-webdriver';
|
||||
declare var browser: any;
|
||||
declare var expect: any;
|
||||
|
||||
// TODO (juliemr): remove this method once this becomes a protractor plugin
|
||||
export function verifyNoBrowserErrors() {
|
||||
browser.manage().logs().get('browser').then(function(browserLog: any[]) {
|
||||
const errors: any[] = [];
|
||||
browserLog.filter(logEntry => {
|
||||
const msg = logEntry.message;
|
||||
console.log('>> ' + msg);
|
||||
if (logEntry.level.value >= webdriver.logging.Level.INFO.value) {
|
||||
errors.push(msg);
|
||||
}
|
||||
});
|
||||
expect(errors).toEqual([]);
|
||||
});
|
||||
}
|
16
packages/examples/_common/index.html
Normal file
16
packages/examples/_common/index.html
Normal file
@ -0,0 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="shortcut icon" href="data:image/x-icon;," type="image/x-icon" />
|
||||
<script type="text/javascript" src="bootstrap.js"></script>
|
||||
<script type="text/javascript">
|
||||
System.import('main-dynamic').catch(console.error.bind(console));
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<example-app>
|
||||
loading...
|
||||
</example-app>
|
||||
</body>
|
||||
</html>
|
13
packages/examples/_common/main-dynamic.ts
Normal file
13
packages/examples/_common/main-dynamic.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
import * as mod from './module';
|
||||
|
||||
if (mod.AppModule) {
|
||||
platformBrowserDynamic().bootstrapModule(mod.AppModule);
|
||||
}
|
19
packages/examples/_common/module.d.ts
vendored
Normal file
19
packages/examples/_common/module.d.ts
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
DO NOT DELETE THIS FILE
|
||||
=======================
|
||||
|
||||
The purpose of this file is to allow `main-dynamic.ts` to be tsc-compiled
|
||||
BEFORE it is copied over to each of the associated example directories
|
||||
within `dist/examples`.
|
||||
|
||||
*/
|
||||
export class AppModule {};
|
32
packages/examples/_common/system-config.ts
Normal file
32
packages/examples/_common/system-config.ts
Normal file
@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
System.config({
|
||||
defaultJSExtensions: true,
|
||||
map: {
|
||||
'@angular/common': '/vendor/@angular/common/bundles/common.umd.js',
|
||||
'@angular/compiler': '/vendor/@angular/compiler/bundles/compiler.umd.js',
|
||||
'@angular/animations': '/vendor/@angular/animations/bundles/animations.umd.js',
|
||||
'@angular/platform-browser/animations':
|
||||
'/vendor/@angular/platform-browser/bundles/platform-browser-animations.umd.js',
|
||||
'@angular/core': '/vendor/@angular/core/bundles/core.umd.js',
|
||||
'@angular/forms': '/vendor/@angular/forms/bundles/forms.umd.js',
|
||||
'@angular/http': '/vendor/@angular/forms/bundles/http.umd.js',
|
||||
'@angular/platform-browser':
|
||||
'/vendor/@angular/platform-browser/bundles/platform-browser.umd.js',
|
||||
'@angular/platform-browser-dynamic':
|
||||
'/vendor/@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
|
||||
'@angular/router': '/vendor/@angular/router/bundles/router.umd.js',
|
||||
'@angular/upgrade': '/vendor/@angular/upgrade/bundles/upgrade.umd.js',
|
||||
'@angular/upgrade/static': '/vendor/@angular/upgrade/bundles/upgrade-static.umd.js',
|
||||
'rxjs': '/vendor/rxjs',
|
||||
},
|
||||
packages: {
|
||||
// rxjs: {format: 'cjs', exports: 'Rx' }
|
||||
rxjs: {defaultExtension: 'js'}
|
||||
}
|
||||
});
|
41
packages/examples/build.sh
Executable file
41
packages/examples/build.sh
Executable file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -u -e -o pipefail
|
||||
|
||||
#
|
||||
# This script is used to compile and copy the contents for each of
|
||||
# example directories over to the dist/examples directory so that they
|
||||
# can be tested with karma and protractor. The `gulp serve-examples` command
|
||||
# can be used to run each of the examples in isolation via http as well.
|
||||
#
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
DIST="../../../dist/examples";
|
||||
rm -rf -- $DIST
|
||||
$(npm bin)/tsc -p ./tsconfig-build.json
|
||||
|
||||
mkdir $DIST/vendor/
|
||||
|
||||
ln -s ../../../dist/packages-dist/ $DIST/vendor/@angular
|
||||
|
||||
for FILE in \
|
||||
../../../node_modules/angular/angular.js \
|
||||
../../../node_modules/zone.js/dist/zone.js \
|
||||
../../../node_modules/systemjs/dist/system.js \
|
||||
../../../node_modules/reflect-metadata/Reflect.js \
|
||||
../../../node_modules/rxjs
|
||||
do
|
||||
ln -s $FILE $DIST/vendor/`basename $FILE`
|
||||
done
|
||||
|
||||
for MODULE in `find . -name module.ts`; do
|
||||
FINAL_DIR_PATH=$DIST/`dirname $MODULE`
|
||||
|
||||
echo "==== $MODULE"
|
||||
cp _common/*.html $FINAL_DIR_PATH
|
||||
cp $DIST/_common/*.js $FINAL_DIR_PATH
|
||||
cp $DIST/_common/*.js.map $FINAL_DIR_PATH
|
||||
|
||||
find `dirname $MODULE` -name \*.css -exec cp {} $FINAL_DIR_PATH \;
|
||||
done
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {browser, by, element, protractor} from 'protractor';
|
||||
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
|
||||
function waitForElement(selector: string) {
|
||||
const EC = (<any>protractor).ExpectedConditions;
|
||||
// Waits for the element with id 'abc' to be present on the dom.
|
||||
browser.wait(EC.presenceOf($(selector)), 20000);
|
||||
}
|
||||
|
||||
describe('Location', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
|
||||
it('should verify paths', () => {
|
||||
browser.get('/common/location/ts/#/bar/baz');
|
||||
waitForElement('hash-location');
|
||||
expect(element.all(by.css('path-location code')).get(0).getText())
|
||||
.toEqual('/common/location/ts');
|
||||
expect(element.all(by.css('hash-location code')).get(0).getText()).toEqual('/bar/baz');
|
||||
});
|
||||
});
|
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion LocationComponent
|
||||
import {HashLocationStrategy, Location, LocationStrategy} from '@angular/common';
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'hash-location',
|
||||
providers: [Location, {provide: LocationStrategy, useClass: HashLocationStrategy}],
|
||||
template: `
|
||||
<h1>HashLocationStrategy</h1>
|
||||
Current URL is: <code>{{location.path()}}</code><br>
|
||||
Normalize: <code>/foo/bar/</code> is: <code>{{location.normalize('foo/bar')}}</code><br>
|
||||
`
|
||||
})
|
||||
export class HashLocationComponent {
|
||||
location: Location;
|
||||
constructor(location: Location) { this.location = location; }
|
||||
}
|
||||
// #enddocregion
|
30
packages/examples/common/location/ts/module.ts
Normal file
30
packages/examples/common/location/ts/module.ts
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {APP_BASE_HREF} from '@angular/common';
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
|
||||
import {HashLocationComponent} from './hash_location_component';
|
||||
import {PathLocationComponent} from './path_location_component';
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `<hash-location></hash-location><path-location></path-location>`
|
||||
})
|
||||
export class ExampleAppComponent {
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [ExampleAppComponent, PathLocationComponent, HashLocationComponent],
|
||||
providers: [{provide: APP_BASE_HREF, useValue: '/'}],
|
||||
imports: [BrowserModule],
|
||||
bootstrap: [ExampleAppComponent]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion LocationComponent
|
||||
import {Location, LocationStrategy, PathLocationStrategy} from '@angular/common';
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'path-location',
|
||||
providers: [Location, {provide: LocationStrategy, useClass: PathLocationStrategy}],
|
||||
template: `
|
||||
<h1>PathLocationStrategy</h1>
|
||||
Current URL is: <code>{{location.path()}}</code><br>
|
||||
Normalize: <code>/foo/bar/</code> is: <code>{{location.normalize('foo/bar')}}</code><br>
|
||||
`
|
||||
})
|
||||
export class PathLocationComponent {
|
||||
location: Location;
|
||||
constructor(location: Location) { this.location = location; }
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {$, ExpectedConditions, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
function waitForElement(selector: string) {
|
||||
const EC = ExpectedConditions;
|
||||
// Waits for the element with id 'abc' to be present on the dom.
|
||||
browser.wait(EC.presenceOf($(selector)), 20000);
|
||||
}
|
||||
|
||||
describe('ngComponentOutlet', () => {
|
||||
const URL = 'common/ngComponentOutlet/ts/';
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
|
||||
describe('ng-component-outlet-example', () => {
|
||||
it('should render simple', () => {
|
||||
browser.get(URL);
|
||||
waitForElement('ng-component-outlet-simple-example');
|
||||
expect(element.all(by.css('hello-world')).getText()).toEqual(['Hello World!']);
|
||||
});
|
||||
|
||||
it('should render complete', () => {
|
||||
browser.get(URL);
|
||||
waitForElement('ng-component-outlet-complete-example');
|
||||
expect(element.all(by.css('complete-component')).getText()).toEqual(['Complete: Ahoj Svet!']);
|
||||
});
|
||||
|
||||
it('should render other module', () => {
|
||||
browser.get(URL);
|
||||
waitForElement('ng-component-outlet-other-module-example');
|
||||
expect(element.all(by.css('other-module-component')).getText()).toEqual([
|
||||
'Other Module Component!'
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
114
packages/examples/common/ngComponentOutlet/ts/module.ts
Normal file
114
packages/examples/common/ngComponentOutlet/ts/module.ts
Normal file
@ -0,0 +1,114 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {Compiler, Component, Injectable, Injector, NgModule, NgModuleFactory, ReflectiveInjector} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
|
||||
|
||||
|
||||
// #docregion SimpleExample
|
||||
@Component({selector: 'hello-world', template: 'Hello World!'})
|
||||
class HelloWorld {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'ng-component-outlet-simple-example',
|
||||
template: `<ng-container *ngComponentOutlet="HelloWorld"></ng-container>`
|
||||
})
|
||||
class NgTemplateOutletSimpleExample {
|
||||
// This field is necessary to expose HelloWorld to the template.
|
||||
HelloWorld = HelloWorld;
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// #docregion CompleteExample
|
||||
@Injectable()
|
||||
class Greeter {
|
||||
suffix = '!';
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'complete-component',
|
||||
template: `Complete: <ng-content></ng-content> <ng-content></ng-content>{{ greeter.suffix }}`
|
||||
})
|
||||
class CompleteComponent {
|
||||
constructor(public greeter: Greeter) {}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'ng-component-outlet-complete-example',
|
||||
template: `
|
||||
<ng-container *ngComponentOutlet="CompleteComponent;
|
||||
injector: myInjector;
|
||||
content: myContent"></ng-container>`
|
||||
})
|
||||
class NgTemplateOutletCompleteExample {
|
||||
// This field is necessary to expose CompleteComponent to the template.
|
||||
CompleteComponent = CompleteComponent;
|
||||
myInjector: Injector;
|
||||
|
||||
myContent = [[document.createTextNode('Ahoj')], [document.createTextNode('Svet')]];
|
||||
|
||||
constructor(injector: Injector) {
|
||||
this.myInjector = ReflectiveInjector.resolveAndCreate([Greeter], injector);
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// #docregion NgModuleFactoryExample
|
||||
@Component({selector: 'other-module-component', template: `Other Module Component!`})
|
||||
class OtherModuleComponent {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'ng-component-outlet-other-module-example',
|
||||
template: `
|
||||
<ng-container *ngComponentOutlet="OtherModuleComponent;
|
||||
ngModuleFactory: myModule;"></ng-container>`
|
||||
})
|
||||
class NgTemplateOutletOtherModuleExample {
|
||||
// This field is necessary to expose OtherModuleComponent to the template.
|
||||
OtherModuleComponent = OtherModuleComponent;
|
||||
myModule: NgModuleFactory<any>;
|
||||
|
||||
constructor(compiler: Compiler) { this.myModule = compiler.compileModuleSync(OtherModule); }
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `<ng-component-outlet-simple-example></ng-component-outlet-simple-example>
|
||||
<hr/>
|
||||
<ng-component-outlet-complete-example></ng-component-outlet-complete-example>
|
||||
<hr/>
|
||||
<ng-component-outlet-other-module-example></ng-component-outlet-other-module-example>`
|
||||
})
|
||||
class ExampleApp {
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule],
|
||||
declarations: [
|
||||
ExampleApp, NgTemplateOutletSimpleExample, NgTemplateOutletCompleteExample,
|
||||
NgTemplateOutletOtherModuleExample, HelloWorld, CompleteComponent
|
||||
],
|
||||
entryComponents: [HelloWorld, CompleteComponent],
|
||||
bootstrap: [ExampleApp]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule],
|
||||
declarations: [OtherModuleComponent],
|
||||
entryComponents: [OtherModuleComponent]
|
||||
})
|
||||
export class OtherModule {
|
||||
}
|
72
packages/examples/common/ngIf/ts/e2e_test/ngIf_spec.ts
Normal file
72
packages/examples/common/ngIf/ts/e2e_test/ngIf_spec.ts
Normal file
@ -0,0 +1,72 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {$, ExpectedConditions, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
function waitForElement(selector: string) {
|
||||
const EC = ExpectedConditions;
|
||||
// Waits for the element with id 'abc' to be present on the dom.
|
||||
browser.wait(EC.presenceOf($(selector)), 20000);
|
||||
}
|
||||
|
||||
describe('ngIf', () => {
|
||||
const URL = 'common/ngIf/ts/';
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
|
||||
describe('ng-if-simple', () => {
|
||||
let comp = 'ng-if-simple';
|
||||
it('should hide/show content', () => {
|
||||
browser.get(URL);
|
||||
waitForElement(comp);
|
||||
expect(element.all(by.css(comp)).get(0).getText()).toEqual('hide show = true\nText to show');
|
||||
element(by.css(comp + ' button')).click();
|
||||
expect(element.all(by.css(comp)).get(0).getText()).toEqual('show show = false');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ng-if-else', () => {
|
||||
let comp = 'ng-if-else';
|
||||
it('should hide/show content', () => {
|
||||
browser.get(URL);
|
||||
waitForElement(comp);
|
||||
expect(element.all(by.css(comp)).get(0).getText()).toEqual('hide show = true\nText to show');
|
||||
element(by.css(comp + ' button')).click();
|
||||
expect(element.all(by.css(comp)).get(0).getText())
|
||||
.toEqual('show show = false\nAlternate text while primary text is hidden');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ng-if-then-else', () => {
|
||||
let comp = 'ng-if-then-else';
|
||||
it('should hide/show content', () => {
|
||||
browser.get(URL);
|
||||
waitForElement(comp);
|
||||
expect(element.all(by.css(comp)).get(0).getText())
|
||||
.toEqual('hide Switch Primary show = true\nPrimary text to show');
|
||||
element.all(by.css(comp + ' button')).get(1).click();
|
||||
expect(element.all(by.css(comp)).get(0).getText())
|
||||
.toEqual('hide Switch Primary show = true\nSecondary text to show');
|
||||
element.all(by.css(comp + ' button')).get(0).click();
|
||||
expect(element.all(by.css(comp)).get(0).getText())
|
||||
.toEqual('show Switch Primary show = false\nAlternate text while primary text is hidden');
|
||||
});
|
||||
});
|
||||
|
||||
describe('ng-if-let', () => {
|
||||
let comp = 'ng-if-let';
|
||||
it('should hide/show content', () => {
|
||||
browser.get(URL);
|
||||
waitForElement(comp);
|
||||
expect(element.all(by.css(comp)).get(0).getText())
|
||||
.toEqual('Next User\nWaiting... (user is null)');
|
||||
element(by.css(comp + ' button')).click();
|
||||
expect(element.all(by.css(comp)).get(0).getText()).toEqual('Next User\nHello Smith, John!');
|
||||
});
|
||||
});
|
||||
});
|
128
packages/examples/common/ngIf/ts/module.ts
Normal file
128
packages/examples/common/ngIf/ts/module.ts
Normal file
@ -0,0 +1,128 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, NgModule, OnInit, TemplateRef, ViewChild} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {Subject} from 'rxjs/Subject';
|
||||
|
||||
|
||||
// #docregion NgIfSimple
|
||||
@Component({
|
||||
selector: 'ng-if-simple',
|
||||
template: `
|
||||
<button (click)="show = !show">{{show ? 'hide' : 'show'}}</button>
|
||||
show = {{show}}
|
||||
<br>
|
||||
<div *ngIf="show">Text to show</div>
|
||||
`
|
||||
})
|
||||
class NgIfSimple {
|
||||
show: boolean = true;
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// #docregion NgIfElse
|
||||
@Component({
|
||||
selector: 'ng-if-else',
|
||||
template: `
|
||||
<button (click)="show = !show">{{show ? 'hide' : 'show'}}</button>
|
||||
show = {{show}}
|
||||
<br>
|
||||
<div *ngIf="show; else elseBlock">Text to show</div>
|
||||
<ng-template #elseBlock>Alternate text while primary text is hidden</ng-template>
|
||||
`
|
||||
})
|
||||
class NgIfElse {
|
||||
show: boolean = true;
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// #docregion NgIfThenElse
|
||||
@Component({
|
||||
selector: 'ng-if-then-else',
|
||||
template: `
|
||||
<button (click)="show = !show">{{show ? 'hide' : 'show'}}</button>
|
||||
<button (click)="switchPrimary()">Switch Primary</button>
|
||||
show = {{show}}
|
||||
<br>
|
||||
<div *ngIf="show; then thenBlock; else elseBlock">this is ignored</div>
|
||||
<ng-template #primaryBlock>Primary text to show</ng-template>
|
||||
<ng-template #secondaryBlock>Secondary text to show</ng-template>
|
||||
<ng-template #elseBlock>Alternate text while primary text is hidden</ng-template>
|
||||
`
|
||||
})
|
||||
class NgIfThenElse implements OnInit {
|
||||
thenBlock: TemplateRef<any> = null;
|
||||
show: boolean = true;
|
||||
|
||||
@ViewChild('primaryBlock')
|
||||
primaryBlock: TemplateRef<any> = null;
|
||||
@ViewChild('secondaryBlock')
|
||||
secondaryBlock: TemplateRef<any> = null;
|
||||
|
||||
switchPrimary() {
|
||||
this.thenBlock = this.thenBlock === this.primaryBlock ? this.secondaryBlock : this.primaryBlock;
|
||||
}
|
||||
|
||||
ngOnInit() { this.thenBlock = this.primaryBlock; }
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// #docregion NgIfLet
|
||||
@Component({
|
||||
selector: 'ng-if-let',
|
||||
template: `
|
||||
<button (click)="nextUser()">Next User</button>
|
||||
<br>
|
||||
<div *ngIf="userObservable | async; else loading; let user">
|
||||
Hello {{user.last}}, {{user.first}}!
|
||||
</div>
|
||||
<ng-template #loading let-user>Waiting... (user is {{user|json}})</ng-template>
|
||||
`
|
||||
})
|
||||
class NgIfLet {
|
||||
userObservable = new Subject<{first: string, last: string}>();
|
||||
first = ['John', 'Mike', 'Mary', 'Bob'];
|
||||
firstIndex = 0;
|
||||
last = ['Smith', 'Novotny', 'Angular'];
|
||||
lastIndex = 0;
|
||||
|
||||
nextUser() {
|
||||
let first = this.first[this.firstIndex++];
|
||||
if (this.firstIndex >= this.first.length) this.firstIndex = 0;
|
||||
let last = this.last[this.lastIndex++];
|
||||
if (this.lastIndex >= this.last.length) this.lastIndex = 0;
|
||||
this.userObservable.next({first, last});
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<ng-if-simple></ng-if-simple>
|
||||
<hr>
|
||||
<ng-if-else></ng-if-else>
|
||||
<hr>
|
||||
<ng-if-then-else></ng-if-then-else>
|
||||
<hr>
|
||||
<ng-if-let></ng-if-let>
|
||||
<hr>
|
||||
`
|
||||
})
|
||||
class ExampleApp {
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule],
|
||||
declarations: [ExampleApp, NgIfSimple, NgIfElse, NgIfThenElse, NgIfLet],
|
||||
bootstrap: [ExampleApp]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {$, ExpectedConditions, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
function waitForElement(selector: string) {
|
||||
const EC = ExpectedConditions;
|
||||
// Waits for the element with id 'abc' to be present on the dom.
|
||||
browser.wait(EC.presenceOf($(selector)), 20000);
|
||||
}
|
||||
|
||||
describe('ngTemplateOutlet', () => {
|
||||
const URL = 'common/ngTemplateOutlet/ts/';
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
|
||||
describe('ng-template-outlet-example', () => {
|
||||
it('should render', () => {
|
||||
browser.get(URL);
|
||||
waitForElement('ng-template-outlet-example');
|
||||
expect(element.all(by.css('ng-template-outlet-example span')).getText()).toEqual([
|
||||
'Hello', 'Hello World!', 'Ahoj Svet!'
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
49
packages/examples/common/ngTemplateOutlet/ts/module.ts
Normal file
49
packages/examples/common/ngTemplateOutlet/ts/module.ts
Normal file
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, NgModule, OnInit, TemplateRef, ViewChild} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {Subject} from 'rxjs/Subject';
|
||||
|
||||
|
||||
// #docregion NgTemplateOutlet
|
||||
@Component({
|
||||
selector: 'ng-template-outlet-example',
|
||||
template: `
|
||||
<ng-container *ngTemplateOutlet="greet"></ng-container>
|
||||
<hr>
|
||||
<ng-container *ngTemplateOutlet="eng; context: myContext"></ng-container>
|
||||
<hr>
|
||||
<ng-container *ngTemplateOutlet="svk; context: myContext"></ng-container>
|
||||
<hr>
|
||||
|
||||
<ng-template #greet><span>Hello</span></ng-template>
|
||||
<ng-template #eng let-name><span>Hello {{name}}!</span></ng-template>
|
||||
<ng-template #svk let-person="localSk"><span>Ahoj {{person}}!</span></ng-template>
|
||||
`
|
||||
})
|
||||
class NgTemplateOutletExample {
|
||||
myContext = {$implicit: 'World', localSk: 'Svet'};
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `<ng-template-outlet-example></ng-template-outlet-example>`
|
||||
})
|
||||
class ExampleApp {
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule],
|
||||
declarations: [ExampleApp, NgTemplateOutletExample],
|
||||
bootstrap: [ExampleApp]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
69
packages/examples/common/pipes/ts/async_pipe.ts
Normal file
69
packages/examples/common/pipes/ts/async_pipe.ts
Normal file
@ -0,0 +1,69 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
import {Observable} from 'rxjs/Observable';
|
||||
import {Subscriber} from 'rxjs/Subscriber';
|
||||
|
||||
// #docregion AsyncPipePromise
|
||||
@Component({
|
||||
selector: 'async-promise-pipe',
|
||||
template: `<div>
|
||||
<code>promise|async</code>:
|
||||
<button (click)="clicked()">{{ arrived ? 'Reset' : 'Resolve' }}</button>
|
||||
<span>Wait for it... {{ greeting | async }}</span>
|
||||
</div>`
|
||||
})
|
||||
export class AsyncPromisePipeComponent {
|
||||
greeting: Promise<string> = null;
|
||||
arrived: boolean = false;
|
||||
|
||||
private resolve: Function = null;
|
||||
|
||||
constructor() { this.reset(); }
|
||||
|
||||
reset() {
|
||||
this.arrived = false;
|
||||
this.greeting = new Promise<string>((resolve, reject) => { this.resolve = resolve; });
|
||||
}
|
||||
|
||||
clicked() {
|
||||
if (this.arrived) {
|
||||
this.reset();
|
||||
} else {
|
||||
this.resolve('hi there!');
|
||||
this.arrived = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// #docregion AsyncPipeObservable
|
||||
@Component({
|
||||
selector: 'async-observable-pipe',
|
||||
template: '<div><code>observable|async</code>: Time: {{ time | async }}</div>'
|
||||
})
|
||||
export class AsyncObservablePipeComponent {
|
||||
time = new Observable<string>((observer: Subscriber<string>) => {
|
||||
setInterval(() => observer.next(new Date().toString()), 1000);
|
||||
});
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// For some reason protractor hangs on setInterval. So we will run outside of angular zone so that
|
||||
// protractor will not see us. Also we want to have this outside the docregion so as not to confuse
|
||||
// the reader.
|
||||
function setInterval(fn: Function, delay: number) {
|
||||
const zone = Zone.current;
|
||||
let rootZone = zone;
|
||||
while (rootZone.parent) {
|
||||
rootZone = rootZone.parent;
|
||||
}
|
||||
rootZone.run(
|
||||
() => { window.setInterval(function() { zone.run(fn, this, arguments as any); }, delay); });
|
||||
}
|
23
packages/examples/common/pipes/ts/date_pipe.ts
Normal file
23
packages/examples/common/pipes/ts/date_pipe.ts
Normal file
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
// #docregion DatePipe
|
||||
@Component({
|
||||
selector: 'date-pipe',
|
||||
template: `<div>
|
||||
<p>Today is {{today | date}}</p>
|
||||
<p>Or if you prefer, {{today | date:'fullDate'}}</p>
|
||||
<p>The time is {{today | date:'jmZ'}}</p>
|
||||
</div>`
|
||||
})
|
||||
export class DatePipeComponent {
|
||||
today: number = Date.now();
|
||||
}
|
||||
// #enddocregion
|
44
packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts
Normal file
44
packages/examples/common/pipes/ts/e2e_test/pipe_spec.ts
Normal file
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {$, ExpectedConditions, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
function waitForElement(selector: string) {
|
||||
const EC = ExpectedConditions;
|
||||
// Waits for the element with id 'abc' to be present on the dom.
|
||||
browser.wait(EC.presenceOf($(selector)), 20000);
|
||||
}
|
||||
|
||||
describe('pipe', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
|
||||
describe('async', () => {
|
||||
const URL = '/common/pipes/ts/';
|
||||
|
||||
it('should resolve and display promise', () => {
|
||||
browser.get(URL);
|
||||
waitForElement('async-promise-pipe');
|
||||
expect(element.all(by.css('async-promise-pipe span')).get(0).getText())
|
||||
.toEqual('Wait for it...');
|
||||
element(by.css('async-promise-pipe button')).click();
|
||||
expect(element.all(by.css('async-promise-pipe span')).get(0).getText())
|
||||
.toEqual('Wait for it... hi there!');
|
||||
});
|
||||
|
||||
it('should update lowercase/uppercase', () => {
|
||||
browser.get(URL);
|
||||
waitForElement('lowerupper-pipe');
|
||||
element(by.css('lowerupper-pipe input')).sendKeys('Hello World!');
|
||||
expect(element.all(by.css('lowerupper-pipe pre')).get(0).getText())
|
||||
.toEqual('\'hello world!\'');
|
||||
expect(element.all(by.css('lowerupper-pipe pre')).get(1).getText())
|
||||
.toEqual('\'HELLO WORLD!\'');
|
||||
});
|
||||
});
|
||||
});
|
30
packages/examples/common/pipes/ts/i18n_pipe.ts
Normal file
30
packages/examples/common/pipes/ts/i18n_pipe.ts
Normal file
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
// #docregion I18nPluralPipeComponent
|
||||
@Component({
|
||||
selector: 'i18n-plural-pipe',
|
||||
template: `<div>{{ messages.length | i18nPlural: messageMapping }}</div>`
|
||||
})
|
||||
export class I18nPluralPipeComponent {
|
||||
messages: any[] = ['Message 1'];
|
||||
messageMapping:
|
||||
{[k: string]: string} = {'=0': 'No messages.', '=1': 'One message.', 'other': '# messages.'};
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// #docregion I18nSelectPipeComponent
|
||||
@Component(
|
||||
{selector: 'i18n-select-pipe', template: `<div>{{gender | i18nSelect: inviteMap}} </div>`})
|
||||
export class I18nSelectPipeComponent {
|
||||
gender: string = 'male';
|
||||
inviteMap: any = {'male': 'Invite him.', 'female': 'Invite her.', 'other': 'Invite them.'};
|
||||
}
|
||||
//#enddocregion
|
24
packages/examples/common/pipes/ts/json_pipe.ts
Normal file
24
packages/examples/common/pipes/ts/json_pipe.ts
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
// #docregion JsonPipe
|
||||
@Component({
|
||||
selector: 'json-pipe',
|
||||
template: `<div>
|
||||
<p>Without JSON pipe:</p>
|
||||
<pre>{{object}}</pre>
|
||||
<p>With JSON pipe:</p>
|
||||
<pre>{{object | json}}</pre>
|
||||
</div>`
|
||||
})
|
||||
export class JsonPipeComponent {
|
||||
object: Object = {foo: 'bar', baz: 'qux', nested: {xyz: 3, numbers: [1, 2, 3, 4, 5]}};
|
||||
}
|
||||
// #enddocregion
|
24
packages/examples/common/pipes/ts/lowerupper_pipe.ts
Normal file
24
packages/examples/common/pipes/ts/lowerupper_pipe.ts
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
// #docregion LowerUpperPipe
|
||||
@Component({
|
||||
selector: 'lowerupper-pipe',
|
||||
template: `<div>
|
||||
<label>Name: </label><input #name (keyup)="change(name.value)" type="text">
|
||||
<p>In lowercase: <pre>'{{value | lowercase}}'</pre>
|
||||
<p>In uppercase: <pre>'{{value | uppercase}}'</pre>
|
||||
</div>`
|
||||
})
|
||||
export class LowerUpperPipeComponent {
|
||||
value: string;
|
||||
change(value: string) { this.value = value; }
|
||||
}
|
||||
// #enddocregion
|
66
packages/examples/common/pipes/ts/module.ts
Normal file
66
packages/examples/common/pipes/ts/module.ts
Normal file
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
|
||||
import {AsyncObservablePipeComponent, AsyncPromisePipeComponent} from './async_pipe';
|
||||
import {DatePipeComponent} from './date_pipe';
|
||||
import {I18nPluralPipeComponent, I18nSelectPipeComponent} from './i18n_pipe';
|
||||
import {JsonPipeComponent} from './json_pipe';
|
||||
import {LowerUpperPipeComponent} from './lowerupper_pipe';
|
||||
import {CurrencyPipeComponent, NumberPipeComponent, PercentPipeComponent} from './number_pipe';
|
||||
import {SlicePipeListComponent, SlicePipeStringComponent} from './slice_pipe';
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<h1>Pipe Example</h1>
|
||||
|
||||
<h2><code>async</code></h2>
|
||||
<async-promise-pipe></async-promise-pipe>
|
||||
<async-observable-pipe></async-observable-pipe>
|
||||
|
||||
<h2><code>date</code></h2>
|
||||
<date-pipe></date-pipe>
|
||||
|
||||
<h2><code>json</code></h2>
|
||||
<json-pipe></json-pipe>
|
||||
|
||||
<h2><code>lower</code>, <code>upper</code></h2>
|
||||
<lowerupper-pipe></lowerupper-pipe>
|
||||
|
||||
<h2><code>number</code></h2>
|
||||
<number-pipe></number-pipe>
|
||||
<percent-pipe></percent-pipe>
|
||||
<currency-pipe></currency-pipe>
|
||||
|
||||
<h2><code>slice</code></h2>
|
||||
<slice-string-pipe></slice-string-pipe>
|
||||
<slice-list-pipe></slice-list-pipe>
|
||||
|
||||
<h2><code>i18n</code></h2>
|
||||
<i18n-plural-pipe></i18n-plural-pipe>
|
||||
<i18n-select-pipe></i18n-select-pipe>
|
||||
`
|
||||
})
|
||||
export class ExampleAppComponent {
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AsyncPromisePipeComponent, AsyncObservablePipeComponent, ExampleAppComponent, JsonPipeComponent,
|
||||
DatePipeComponent, LowerUpperPipeComponent, NumberPipeComponent, PercentPipeComponent,
|
||||
CurrencyPipeComponent, SlicePipeStringComponent, SlicePipeListComponent,
|
||||
I18nPluralPipeComponent, I18nSelectPipeComponent
|
||||
],
|
||||
imports: [BrowserModule],
|
||||
bootstrap: [ExampleAppComponent]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
53
packages/examples/common/pipes/ts/number_pipe.ts
Normal file
53
packages/examples/common/pipes/ts/number_pipe.ts
Normal file
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
// #docregion NumberPipe
|
||||
@Component({
|
||||
selector: 'number-pipe',
|
||||
template: `<div>
|
||||
<p>e (no formatting): {{e}}</p>
|
||||
<p>e (3.1-5): {{e | number:'3.1-5'}}</p>
|
||||
<p>pi (no formatting): {{pi}}</p>
|
||||
<p>pi (3.5-5): {{pi | number:'3.5-5'}}</p>
|
||||
</div>`
|
||||
})
|
||||
export class NumberPipeComponent {
|
||||
pi: number = 3.141592;
|
||||
e: number = 2.718281828459045;
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// #docregion PercentPipe
|
||||
@Component({
|
||||
selector: 'percent-pipe',
|
||||
template: `<div>
|
||||
<p>A: {{a | percent}}</p>
|
||||
<p>B: {{b | percent:'4.3-5'}}</p>
|
||||
</div>`
|
||||
})
|
||||
export class PercentPipeComponent {
|
||||
a: number = 0.259;
|
||||
b: number = 1.3495;
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// #docregion CurrencyPipe
|
||||
@Component({
|
||||
selector: 'currency-pipe',
|
||||
template: `<div>
|
||||
<p>A: {{a | currency:'USD':false}}</p>
|
||||
<p>B: {{b | currency:'USD':true:'4.2-2'}}</p>
|
||||
</div>`
|
||||
})
|
||||
export class CurrencyPipeComponent {
|
||||
a: number = 0.259;
|
||||
b: number = 1.3495;
|
||||
}
|
||||
// #enddocregion
|
38
packages/examples/common/pipes/ts/slice_pipe.ts
Normal file
38
packages/examples/common/pipes/ts/slice_pipe.ts
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
// #docregion SlicePipe_string
|
||||
@Component({
|
||||
selector: 'slice-string-pipe',
|
||||
template: `<div>
|
||||
<p>{{str}}[0:4]: '{{str | slice:0:4}}' - output is expected to be 'abcd'</p>
|
||||
<p>{{str}}[4:0]: '{{str | slice:4:0}}' - output is expected to be ''</p>
|
||||
<p>{{str}}[-4]: '{{str | slice:-4}}' - output is expected to be 'ghij'</p>
|
||||
<p>{{str}}[-4:-2]: '{{str | slice:-4:-2}}' - output is expected to be 'gh'</p>
|
||||
<p>{{str}}[-100]: '{{str | slice:-100}}' - output is expected to be 'abcdefghij'</p>
|
||||
<p>{{str}}[100]: '{{str | slice:100}}' - output is expected to be ''</p>
|
||||
</div>`
|
||||
})
|
||||
export class SlicePipeStringComponent {
|
||||
str: string = 'abcdefghij';
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// #docregion SlicePipe_list
|
||||
@Component({
|
||||
selector: 'slice-list-pipe',
|
||||
template: `<ul>
|
||||
<li *ngFor="let i of collection | slice:1:3">{{i}}</li>
|
||||
</ul>`
|
||||
})
|
||||
export class SlicePipeListComponent {
|
||||
collection: string[] = ['a', 'b', 'c', 'd'];
|
||||
}
|
||||
// #enddocregion
|
38
packages/examples/compiler/ts/url_resolver/url_resolver.ts
Normal file
38
packages/examples/compiler/ts/url_resolver/url_resolver.ts
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {UrlResolver} from '@angular/compiler';
|
||||
import {NgModule} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
|
||||
let MyApp: any;
|
||||
|
||||
// #docregion url_resolver
|
||||
class MyUrlResolver extends UrlResolver {
|
||||
resolve(baseUrl: string, url: string): string {
|
||||
// Serve CSS files from a special CDN.
|
||||
if (url.substr(-4) === '.css') {
|
||||
return super.resolve('http://cdn.myapp.com/css/', url);
|
||||
}
|
||||
return super.resolve(baseUrl, url);
|
||||
}
|
||||
}
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule],
|
||||
providers: [{provide: UrlResolver, useClass: MyUrlResolver}],
|
||||
bootstrap: [MyApp]
|
||||
})
|
||||
class AppModule {
|
||||
}
|
||||
|
||||
export function main() {
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
}
|
||||
// #enddocregion
|
56
packages/examples/core/animation/ts/dsl/animation_example.ts
Normal file
56
packages/examples/core/animation/ts/dsl/animation_example.ts
Normal file
@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion Component
|
||||
import {Component, NgModule, animate, state, style, transition, trigger} from '@angular/core';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
styles: [`
|
||||
.toggle-container {
|
||||
background-color:white;
|
||||
border:10px solid black;
|
||||
width:200px;
|
||||
text-align:center;
|
||||
line-height:100px;
|
||||
font-size:50px;
|
||||
box-sizing:border-box;
|
||||
overflow:hidden;
|
||||
}
|
||||
`],
|
||||
animations: [trigger(
|
||||
'openClose',
|
||||
[
|
||||
state('collapsed, void', style({height: '0px', color: 'maroon', borderColor: 'maroon'})),
|
||||
state('expanded', style({height: '*', borderColor: 'green', color: 'green'})),
|
||||
transition(
|
||||
'collapsed <=> expanded', [animate(500, style({height: '250px'})), animate(500)])
|
||||
])],
|
||||
template: `
|
||||
<button (click)="expand()">Open</button>
|
||||
<button (click)="collapse()">Closed</button>
|
||||
<hr />
|
||||
<div class="toggle-container" [@openClose]="stateExpression">
|
||||
Look at this box
|
||||
</div>
|
||||
`
|
||||
})
|
||||
export class MyExpandoCmp {
|
||||
stateExpression: string;
|
||||
constructor() { this.collapse(); }
|
||||
expand() { this.stateExpression = 'expanded'; }
|
||||
collapse() { this.stateExpression = 'collapsed'; }
|
||||
}
|
||||
|
||||
@NgModule(
|
||||
{imports: [BrowserAnimationsModule], declarations: [MyExpandoCmp], bootstrap: [MyExpandoCmp]})
|
||||
export class AppModule {
|
||||
}
|
||||
|
||||
// #enddocregion
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {$, ExpectedConditions, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../../_common/e2e_util';
|
||||
|
||||
function waitForElement(selector: string) {
|
||||
const EC = ExpectedConditions;
|
||||
// Waits for the element with id 'abc' to be present on the dom.
|
||||
browser.wait(EC.presenceOf($(selector)), 20000);
|
||||
}
|
||||
|
||||
describe('animation example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
|
||||
describe('index view', () => {
|
||||
const URL = '/core/animation/ts/dsl/';
|
||||
|
||||
it('should list out the current collection of items', () => {
|
||||
browser.get(URL);
|
||||
waitForElement('.toggle-container');
|
||||
expect(element.all(by.css('.toggle-container')).get(0).getText()).toEqual('Look at this box');
|
||||
});
|
||||
});
|
||||
});
|
8
packages/examples/core/animation/ts/dsl/module.ts
Normal file
8
packages/examples/core/animation/ts/dsl/module.ts
Normal file
@ -0,0 +1,8 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
export {AppModule} from './animation_example';
|
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {DebugElement} from '@angular/core';
|
||||
|
||||
let debugElement: DebugElement;
|
||||
let predicate: any;
|
||||
|
||||
// #docregion scope_all
|
||||
debugElement.query(predicate);
|
||||
// #enddocregion
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion Component
|
||||
import {Component, ContentChild, Directive, Input} from '@angular/core';
|
||||
|
||||
@Directive({selector: 'pane'})
|
||||
export class Pane {
|
||||
@Input() id: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'tab',
|
||||
template: `
|
||||
<div>pane: {{pane?.id}}</div>
|
||||
`
|
||||
})
|
||||
export class Tab {
|
||||
@ContentChild(Pane) pane: Pane;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<tab>
|
||||
<pane id="1" *ngIf="shouldShow"></pane>
|
||||
<pane id="2" *ngIf="!shouldShow"></pane>
|
||||
</tab>
|
||||
|
||||
<button (click)="toggle()">Toggle</button>
|
||||
`,
|
||||
})
|
||||
export class ContentChildComp {
|
||||
shouldShow = true;
|
||||
|
||||
toggle() { this.shouldShow = !this.shouldShow; }
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion HowTo
|
||||
import {AfterContentInit, ContentChild, Directive} from '@angular/core';
|
||||
|
||||
@Directive({selector: 'child-directive'})
|
||||
class ChildDirective {
|
||||
}
|
||||
|
||||
@Directive({selector: 'someDir'})
|
||||
class SomeDir implements AfterContentInit {
|
||||
@ContentChild(ChildDirective) contentChild: ChildDirective;
|
||||
|
||||
ngAfterContentInit() {
|
||||
// contentChild is set
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../../_common/e2e_util';
|
||||
|
||||
describe('contentChild example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
let button: ElementFinder;
|
||||
let result: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/core/di/ts/contentChild/index.html');
|
||||
button = element(by.css('button'));
|
||||
result = element(by.css('div'));
|
||||
});
|
||||
|
||||
it('should query content child', () => {
|
||||
expect(result.getText()).toEqual('pane: 1');
|
||||
|
||||
button.click();
|
||||
|
||||
expect(result.getText()).toEqual('pane: 2');
|
||||
});
|
||||
});
|
19
packages/examples/core/di/ts/contentChild/module.ts
Normal file
19
packages/examples/core/di/ts/contentChild/module.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {ContentChildComp, Pane, Tab} from './content_child_example';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule],
|
||||
declarations: [ContentChildComp, Pane, Tab],
|
||||
bootstrap: [ContentChildComp]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion Component
|
||||
import {Component, ContentChildren, Directive, Input, QueryList} from '@angular/core';
|
||||
|
||||
@Directive({selector: 'pane'})
|
||||
export class Pane {
|
||||
@Input() id: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'tab',
|
||||
template: `
|
||||
<div>panes: {{serializedPanes}}</div>
|
||||
`
|
||||
})
|
||||
export class Tab {
|
||||
@ContentChildren(Pane) panes: QueryList<Pane>;
|
||||
|
||||
get serializedPanes(): string { return this.panes ? this.panes.map(p => p.id).join(', ') : ''; }
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<tab>
|
||||
<pane id="1"></pane>
|
||||
<pane id="2"></pane>
|
||||
<pane id="3" *ngIf="shouldShow"></pane>
|
||||
</tab>
|
||||
|
||||
<button (click)="show()">Show 3</button>
|
||||
`,
|
||||
})
|
||||
export class ContentChildrenComp {
|
||||
shouldShow = false;
|
||||
|
||||
show() { this.shouldShow = true; }
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion HowTo
|
||||
import {AfterContentInit, ContentChildren, Directive, QueryList} from '@angular/core';
|
||||
|
||||
@Directive({selector: 'child-directive'})
|
||||
class ChildDirective {
|
||||
}
|
||||
|
||||
@Directive({selector: 'someDir'})
|
||||
class SomeDir implements AfterContentInit {
|
||||
@ContentChildren(ChildDirective) contentChildren: QueryList<ChildDirective>;
|
||||
|
||||
ngAfterContentInit() {
|
||||
// contentChildren is set
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../../_common/e2e_util';
|
||||
|
||||
describe('contentChildren example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
let button: ElementFinder;
|
||||
let result: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/core/di/ts/contentChildren/index.html');
|
||||
button = element(by.css('button'));
|
||||
result = element(by.css('div'));
|
||||
});
|
||||
|
||||
it('should query content children', () => {
|
||||
expect(result.getText()).toEqual('panes: 1, 2');
|
||||
|
||||
button.click();
|
||||
|
||||
expect(result.getText()).toEqual('panes: 1, 2, 3');
|
||||
});
|
||||
});
|
19
packages/examples/core/di/ts/contentChildren/module.ts
Normal file
19
packages/examples/core/di/ts/contentChildren/module.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {ContentChildrenComp, Pane, Tab} from './content_children_example';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule],
|
||||
declarations: [ContentChildrenComp, Pane, Tab],
|
||||
bootstrap: [ContentChildrenComp]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
50
packages/examples/core/di/ts/forward_ref/forward_ref_spec.ts
Normal file
50
packages/examples/core/di/ts/forward_ref/forward_ref_spec.ts
Normal file
@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Inject, ReflectiveInjector, forwardRef, resolveForwardRef} from '@angular/core';
|
||||
|
||||
export function main() {
|
||||
describe('forwardRef examples', () => {
|
||||
it('ForwardRefFn example works', () => {
|
||||
// #docregion forward_ref_fn
|
||||
const ref = forwardRef(() => Lock);
|
||||
// #enddocregion
|
||||
expect(ref).not.toBeNull();
|
||||
|
||||
class Lock {}
|
||||
});
|
||||
|
||||
it('can be used to inject a class defined later', () => {
|
||||
// #docregion forward_ref
|
||||
class Door {
|
||||
lock: Lock;
|
||||
|
||||
// Door attempts to inject Lock, despite it not being defined yet.
|
||||
// forwardRef makes this possible.
|
||||
constructor(@Inject(forwardRef(() => Lock)) lock: Lock) { this.lock = lock; }
|
||||
}
|
||||
|
||||
// Only at this point Lock is defined.
|
||||
class Lock {}
|
||||
|
||||
const injector = ReflectiveInjector.resolveAndCreate([Door, Lock]);
|
||||
const door = injector.get(Door);
|
||||
expect(door instanceof Door).toBeTruthy();
|
||||
expect(door.lock instanceof Lock).toBeTruthy();
|
||||
// #enddocregion
|
||||
});
|
||||
|
||||
it('can be unwrapped', () => {
|
||||
// #docregion resolve_forward_ref
|
||||
const ref = forwardRef(() => 'refValue');
|
||||
expect(resolveForwardRef(ref)).toEqual('refValue');
|
||||
expect(resolveForwardRef('regularValue')).toEqual('regularValue');
|
||||
// #enddocregion
|
||||
});
|
||||
});
|
||||
}
|
41
packages/examples/core/di/ts/injector_spec.ts
Normal file
41
packages/examples/core/di/ts/injector_spec.ts
Normal file
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {InjectionToken, Injector, ReflectiveInjector} from '@angular/core';
|
||||
|
||||
export function main() {
|
||||
describe('injector metadata examples', () => {
|
||||
it('works', () => {
|
||||
// #docregion Injector
|
||||
const injector: Injector =
|
||||
ReflectiveInjector.resolveAndCreate([{provide: 'validToken', useValue: 'Value'}]);
|
||||
expect(injector.get('validToken')).toEqual('Value');
|
||||
expect(() => injector.get('invalidToken')).toThrowError();
|
||||
expect(injector.get('invalidToken', 'notFound')).toEqual('notFound');
|
||||
// #enddocregion
|
||||
});
|
||||
|
||||
it('injects injector', () => {
|
||||
// #docregion injectInjector
|
||||
const injector = ReflectiveInjector.resolveAndCreate([]);
|
||||
expect(injector.get(Injector)).toBe(injector);
|
||||
// #enddocregion
|
||||
});
|
||||
|
||||
it('should infer type', () => {
|
||||
// #docregion InjectionToken
|
||||
const BASE_URL = new InjectionToken<string>('BaseUrl');
|
||||
const injector =
|
||||
ReflectiveInjector.resolveAndCreate([{provide: BASE_URL, useValue: 'http://localhost'}]);
|
||||
const url = injector.get(BASE_URL);
|
||||
// here `url` is inferred to be `string` because `BASE_URL` is `InjectionToken<string>`.
|
||||
expect(url).toBe('http://localhost');
|
||||
// #enddocregion
|
||||
});
|
||||
});
|
||||
}
|
185
packages/examples/core/di/ts/metadata_spec.ts
Normal file
185
packages/examples/core/di/ts/metadata_spec.ts
Normal file
@ -0,0 +1,185 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, Directive, Host, Inject, Injectable, Optional, ReflectiveInjector, Self, SkipSelf} from '@angular/core';
|
||||
import {ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
|
||||
export function main() {
|
||||
describe('di metadata examples', () => {
|
||||
describe('Inject', () => {
|
||||
it('works', () => {
|
||||
// #docregion Inject
|
||||
class Engine {}
|
||||
|
||||
@Injectable()
|
||||
class Car {
|
||||
constructor(@Inject('MyEngine') public engine: Engine) {}
|
||||
}
|
||||
|
||||
const injector =
|
||||
ReflectiveInjector.resolveAndCreate([{provide: 'MyEngine', useClass: Engine}, Car]);
|
||||
|
||||
expect(injector.get(Car).engine instanceof Engine).toBe(true);
|
||||
// #enddocregion
|
||||
});
|
||||
|
||||
it('works without decorator', () => {
|
||||
// #docregion InjectWithoutDecorator
|
||||
class Engine {}
|
||||
|
||||
@Injectable()
|
||||
class Car {
|
||||
constructor(public engine: Engine) {
|
||||
} // same as constructor(@Inject(Engine) engine:Engine)
|
||||
}
|
||||
|
||||
const injector = ReflectiveInjector.resolveAndCreate([Engine, Car]);
|
||||
expect(injector.get(Car).engine instanceof Engine).toBe(true);
|
||||
// #enddocregion
|
||||
});
|
||||
});
|
||||
|
||||
describe('Optional', () => {
|
||||
it('works', () => {
|
||||
// #docregion Optional
|
||||
class Engine {}
|
||||
|
||||
@Injectable()
|
||||
class Car {
|
||||
constructor(@Optional() public engine: Engine) {}
|
||||
}
|
||||
|
||||
const injector = ReflectiveInjector.resolveAndCreate([Car]);
|
||||
expect(injector.get(Car).engine).toBeNull();
|
||||
// #enddocregion
|
||||
});
|
||||
});
|
||||
|
||||
describe('Injectable', () => {
|
||||
it('works', () => {
|
||||
// #docregion Injectable
|
||||
@Injectable()
|
||||
class UsefulService {
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
class NeedsService {
|
||||
constructor(public service: UsefulService) {}
|
||||
}
|
||||
|
||||
const injector = ReflectiveInjector.resolveAndCreate([NeedsService, UsefulService]);
|
||||
expect(injector.get(NeedsService).service instanceof UsefulService).toBe(true);
|
||||
// #enddocregion
|
||||
});
|
||||
|
||||
it('throws without Injectable', () => {
|
||||
// #docregion InjectableThrows
|
||||
class UsefulService {}
|
||||
|
||||
class NeedsService {
|
||||
constructor(public service: UsefulService) {}
|
||||
}
|
||||
|
||||
expect(() => ReflectiveInjector.resolveAndCreate([NeedsService, UsefulService])).toThrow();
|
||||
// #enddocregion
|
||||
});
|
||||
});
|
||||
|
||||
describe('Self', () => {
|
||||
it('works', () => {
|
||||
// #docregion Self
|
||||
class Dependency {}
|
||||
|
||||
@Injectable()
|
||||
class NeedsDependency {
|
||||
constructor(@Self() public dependency: Dependency) {}
|
||||
}
|
||||
|
||||
let inj = ReflectiveInjector.resolveAndCreate([Dependency, NeedsDependency]);
|
||||
const nd = inj.get(NeedsDependency);
|
||||
|
||||
expect(nd.dependency instanceof Dependency).toBe(true);
|
||||
|
||||
inj = ReflectiveInjector.resolveAndCreate([Dependency]);
|
||||
const child = inj.resolveAndCreateChild([NeedsDependency]);
|
||||
expect(() => child.get(NeedsDependency)).toThrowError();
|
||||
// #enddocregion
|
||||
});
|
||||
});
|
||||
|
||||
describe('SkipSelf', () => {
|
||||
it('works', () => {
|
||||
// #docregion SkipSelf
|
||||
class Dependency {}
|
||||
|
||||
@Injectable()
|
||||
class NeedsDependency {
|
||||
constructor(@SkipSelf() public dependency: Dependency) { this.dependency = dependency; }
|
||||
}
|
||||
|
||||
const parent = ReflectiveInjector.resolveAndCreate([Dependency]);
|
||||
const child = parent.resolveAndCreateChild([NeedsDependency]);
|
||||
expect(child.get(NeedsDependency).dependency instanceof Dependency).toBe(true);
|
||||
|
||||
const inj = ReflectiveInjector.resolveAndCreate([Dependency, NeedsDependency]);
|
||||
expect(() => inj.get(NeedsDependency)).toThrowError();
|
||||
// #enddocregion
|
||||
});
|
||||
});
|
||||
|
||||
describe('Host', () => {
|
||||
it('works', () => {
|
||||
// #docregion Host
|
||||
class OtherService {}
|
||||
class HostService {}
|
||||
|
||||
@Directive({selector: 'child-directive'})
|
||||
class ChildDirective {
|
||||
logs: string[] = [];
|
||||
|
||||
constructor(@Optional() @Host() os: OtherService, @Optional() @Host() hs: HostService) {
|
||||
// os is null: true
|
||||
this.logs.push(`os is null: ${os === null}`);
|
||||
// hs is an instance of HostService: true
|
||||
this.logs.push(`hs is an instance of HostService: ${hs instanceof HostService}`);
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'parent-cmp',
|
||||
viewProviders: [HostService],
|
||||
template: '<child-directive></child-directive>',
|
||||
})
|
||||
class ParentCmp {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app',
|
||||
viewProviders: [OtherService],
|
||||
template: '<parent-cmp></parent-cmp>',
|
||||
})
|
||||
class App {
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [App, ParentCmp, ChildDirective],
|
||||
});
|
||||
|
||||
let cmp: ComponentFixture<App>;
|
||||
expect(() => cmp = TestBed.createComponent(App)).not.toThrow();
|
||||
|
||||
expect(cmp.debugElement.children[0].children[0].injector.get(ChildDirective).logs).toEqual([
|
||||
'os is null: true',
|
||||
'hs is an instance of HostService: true',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
149
packages/examples/core/di/ts/provider_spec.ts
Normal file
149
packages/examples/core/di/ts/provider_spec.ts
Normal file
@ -0,0 +1,149 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Inject, Injectable, InjectionToken, Optional, ReflectiveInjector} from '@angular/core';
|
||||
|
||||
export function main() {
|
||||
describe('Provider examples', () => {
|
||||
describe('TypeProvider', () => {
|
||||
it('works', () => {
|
||||
// #docregion TypeProvider
|
||||
@Injectable()
|
||||
class Greeting {
|
||||
salutation = 'Hello';
|
||||
}
|
||||
|
||||
const injector = ReflectiveInjector.resolveAndCreate([
|
||||
Greeting, // Shorthand for { provide: Greeting, useClass: Greeting }
|
||||
]);
|
||||
|
||||
expect(injector.get(Greeting).salutation).toBe('Hello');
|
||||
// #enddocregion
|
||||
});
|
||||
});
|
||||
|
||||
describe('ValueProvider', () => {
|
||||
it('works', () => {
|
||||
// #docregion ValueProvider
|
||||
const injector =
|
||||
ReflectiveInjector.resolveAndCreate([{provide: String, useValue: 'Hello'}]);
|
||||
|
||||
expect(injector.get(String)).toEqual('Hello');
|
||||
// #enddocregion
|
||||
});
|
||||
});
|
||||
|
||||
describe('MultiProviderAspect', () => {
|
||||
it('works', () => {
|
||||
// #docregion MultiProviderAspect
|
||||
const injector = ReflectiveInjector.resolveAndCreate([
|
||||
{provide: 'local', multi: true, useValue: 'en'},
|
||||
{provide: 'local', multi: true, useValue: 'sk'},
|
||||
]);
|
||||
|
||||
const locales: string[] = injector.get('local');
|
||||
expect(locales).toEqual(['en', 'sk']);
|
||||
// #enddocregion
|
||||
});
|
||||
});
|
||||
|
||||
describe('ClassProvider', () => {
|
||||
it('works', () => {
|
||||
// #docregion ClassProvider
|
||||
abstract class Shape { name: string; }
|
||||
|
||||
class Square extends Shape {
|
||||
name = 'square';
|
||||
}
|
||||
|
||||
const injector = ReflectiveInjector.resolveAndCreate([{provide: Shape, useClass: Square}]);
|
||||
|
||||
const shape: Shape = injector.get(Shape);
|
||||
expect(shape.name).toEqual('square');
|
||||
expect(shape instanceof Square).toBe(true);
|
||||
// #enddocregion
|
||||
});
|
||||
|
||||
it('is different then useExisting', () => {
|
||||
// #docregion ClassProviderDifference
|
||||
class Greeting {
|
||||
salutation = 'Hello';
|
||||
}
|
||||
|
||||
class FormalGreeting extends Greeting {
|
||||
salutation = 'Greetings';
|
||||
}
|
||||
|
||||
const injector = ReflectiveInjector.resolveAndCreate(
|
||||
[FormalGreeting, {provide: Greeting, useClass: FormalGreeting}]);
|
||||
|
||||
// The injector returns different instances.
|
||||
// See: {provide: ?, useExisting: ?} if you want the same instance.
|
||||
expect(injector.get(FormalGreeting)).not.toBe(injector.get(Greeting));
|
||||
// #enddocregion
|
||||
});
|
||||
});
|
||||
|
||||
describe('ExistingProvider', () => {
|
||||
it('works', () => {
|
||||
// #docregion ExistingProvider
|
||||
class Greeting {
|
||||
salutation = 'Hello';
|
||||
}
|
||||
|
||||
class FormalGreeting extends Greeting {
|
||||
salutation = 'Greetings';
|
||||
}
|
||||
|
||||
const injector = ReflectiveInjector.resolveAndCreate(
|
||||
[FormalGreeting, {provide: Greeting, useExisting: FormalGreeting}]);
|
||||
|
||||
expect(injector.get(Greeting).salutation).toEqual('Greetings');
|
||||
expect(injector.get(FormalGreeting).salutation).toEqual('Greetings');
|
||||
expect(injector.get(FormalGreeting)).toBe(injector.get(Greeting));
|
||||
// #enddocregion
|
||||
});
|
||||
});
|
||||
|
||||
describe('FactoryProvider', () => {
|
||||
it('works', () => {
|
||||
// #docregion FactoryProvider
|
||||
const Location = new InjectionToken('location');
|
||||
const Hash = new InjectionToken('hash');
|
||||
|
||||
const injector = ReflectiveInjector.resolveAndCreate([
|
||||
{provide: Location, useValue: 'http://angular.io/#someLocation'}, {
|
||||
provide: Hash,
|
||||
useFactory: (location: string) => location.split('#')[1],
|
||||
deps: [Location]
|
||||
}
|
||||
]);
|
||||
|
||||
expect(injector.get(Hash)).toEqual('someLocation');
|
||||
// #enddocregion
|
||||
});
|
||||
|
||||
it('supports optional dependencies', () => {
|
||||
// #docregion FactoryProviderOptionalDeps
|
||||
const Location = new InjectionToken('location');
|
||||
const Hash = new InjectionToken('hash');
|
||||
|
||||
const injector = ReflectiveInjector.resolveAndCreate([{
|
||||
provide: Hash,
|
||||
useFactory: (location: string) => `Hash for: ${location}`,
|
||||
// use a nested array to define metadata for dependencies.
|
||||
deps: [[new Optional(), Location]]
|
||||
}]);
|
||||
|
||||
expect(injector.get(Hash)).toEqual('Hash for: null');
|
||||
// #enddocregion
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../../_common/e2e_util';
|
||||
|
||||
describe('viewChild example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
let button: ElementFinder;
|
||||
let result: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/core/di/ts/viewChild/index.html');
|
||||
button = element(by.css('button'));
|
||||
result = element(by.css('div'));
|
||||
});
|
||||
|
||||
it('should query view child', () => {
|
||||
expect(result.getText()).toEqual('Selected: 1');
|
||||
|
||||
button.click();
|
||||
|
||||
expect(result.getText()).toEqual('Selected: 2');
|
||||
});
|
||||
});
|
17
packages/examples/core/di/ts/viewChild/module.ts
Normal file
17
packages/examples/core/di/ts/viewChild/module.ts
Normal file
@ -0,0 +1,17 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
|
||||
import {Pane, ViewChildComp} from './view_child_example';
|
||||
|
||||
@NgModule(
|
||||
{imports: [BrowserModule], declarations: [ViewChildComp, Pane], bootstrap: [ViewChildComp]})
|
||||
export class AppModule {
|
||||
}
|
37
packages/examples/core/di/ts/viewChild/view_child_example.ts
Normal file
37
packages/examples/core/di/ts/viewChild/view_child_example.ts
Normal file
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion Component
|
||||
import {Component, Directive, Input, ViewChild} from '@angular/core';
|
||||
|
||||
@Directive({selector: 'pane'})
|
||||
export class Pane {
|
||||
@Input() id: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<pane id="1" *ngIf="shouldShow"></pane>
|
||||
<pane id="2" *ngIf="!shouldShow"></pane>
|
||||
|
||||
<button (click)="toggle()">Toggle</button>
|
||||
|
||||
<div>Selected: {{selectedPane}}</div>
|
||||
`,
|
||||
})
|
||||
export class ViewChildComp {
|
||||
@ViewChild(Pane)
|
||||
set pane(v: Pane) {
|
||||
setTimeout(() => { this.selectedPane = v.id; }, 0);
|
||||
}
|
||||
selectedPane: string = '';
|
||||
shouldShow = true;
|
||||
toggle() { this.shouldShow = !this.shouldShow; }
|
||||
}
|
||||
// #enddocregion
|
24
packages/examples/core/di/ts/viewChild/view_child_howto.ts
Normal file
24
packages/examples/core/di/ts/viewChild/view_child_howto.ts
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion HowTo
|
||||
import {AfterViewInit, Component, Directive, ViewChild} from '@angular/core';
|
||||
|
||||
@Directive({selector: 'child-directive'})
|
||||
class ChildDirective {
|
||||
}
|
||||
|
||||
@Component({selector: 'someCmp', templateUrl: 'someCmp.html'})
|
||||
class SomeCmp implements AfterViewInit {
|
||||
@ViewChild(ChildDirective) child: ChildDirective;
|
||||
|
||||
ngAfterViewInit() {
|
||||
// child is set
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,31 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
|
||||
import {ElementFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../../_common/e2e_util';
|
||||
|
||||
describe('viewChildren example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
let button: ElementFinder;
|
||||
let result: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/core/di/ts/viewChildren/index.html');
|
||||
button = element(by.css('button'));
|
||||
result = element(by.css('div'));
|
||||
});
|
||||
|
||||
it('should query view children', () => {
|
||||
expect(result.getText()).toEqual('panes: 1, 2');
|
||||
|
||||
button.click();
|
||||
|
||||
expect(result.getText()).toEqual('panes: 1, 2, 3');
|
||||
});
|
||||
});
|
20
packages/examples/core/di/ts/viewChildren/module.ts
Normal file
20
packages/examples/core/di/ts/viewChildren/module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
|
||||
import {Pane, ViewChildrenComp} from './view_children_example';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule],
|
||||
declarations: [ViewChildrenComp, Pane],
|
||||
bootstrap: [ViewChildrenComp]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion Component
|
||||
import {AfterViewInit, Component, Directive, Input, QueryList, ViewChildren} from '@angular/core';
|
||||
|
||||
@Directive({selector: 'pane'})
|
||||
export class Pane {
|
||||
@Input() id: string;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<pane id="1"></pane>
|
||||
<pane id="2"></pane>
|
||||
<pane id="3" *ngIf="shouldShow"></pane>
|
||||
|
||||
<button (click)="show()">Show 3</button>
|
||||
|
||||
<div>panes: {{serializedPanes}}</div>
|
||||
`,
|
||||
})
|
||||
export class ViewChildrenComp implements AfterViewInit {
|
||||
@ViewChildren(Pane) panes: QueryList<Pane>;
|
||||
serializedPanes: string = '';
|
||||
|
||||
shouldShow = false;
|
||||
|
||||
show() { this.shouldShow = true; }
|
||||
|
||||
ngAfterViewInit() {
|
||||
this.calculateSerializedPanes();
|
||||
this.panes.changes.subscribe((r) => { this.calculateSerializedPanes(); });
|
||||
}
|
||||
|
||||
calculateSerializedPanes() {
|
||||
setTimeout(() => { this.serializedPanes = this.panes.map(p => p.id).join(', '); }, 0);
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion HowTo
|
||||
import {AfterViewInit, Component, Directive, QueryList, ViewChildren} from '@angular/core';
|
||||
|
||||
@Directive({selector: 'child-directive'})
|
||||
class ChildDirective {
|
||||
}
|
||||
|
||||
@Component({selector: 'someCmp', templateUrl: 'someCmp.html'})
|
||||
class SomeCmp implements AfterViewInit {
|
||||
@ViewChildren(ChildDirective) viewChildren: QueryList<ChildDirective>;
|
||||
|
||||
ngAfterViewInit() {
|
||||
// viewChildren is set
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
0
packages/examples/core/ts/.gitkeep
Normal file
0
packages/examples/core/ts/.gitkeep
Normal file
27
packages/examples/core/ts/bootstrap/bootstrap.ts
Normal file
27
packages/examples/core/ts/bootstrap/bootstrap.ts
Normal file
@ -0,0 +1,27 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
|
||||
// #docregion bootstrap
|
||||
@Component({selector: 'my-app', template: 'Hello {{ name }}!'})
|
||||
class MyApp {
|
||||
name: string = 'World';
|
||||
}
|
||||
|
||||
@NgModule({imports: [BrowserModule], bootstrap: [MyApp]})
|
||||
class AppModule {
|
||||
}
|
||||
|
||||
export function main() {
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
}
|
||||
|
||||
// #enddocregion
|
150
packages/examples/core/ts/metadata/lifecycle_hooks_spec.ts
Normal file
150
packages/examples/core/ts/metadata/lifecycle_hooks_spec.ts
Normal file
@ -0,0 +1,150 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {AfterContentChecked, AfterContentInit, AfterViewChecked, AfterViewInit, Component, DoCheck, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, Type} from '@angular/core';
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
|
||||
export function main() {
|
||||
describe('lifecycle hooks examples', () => {
|
||||
it('should work with ngOnInit', () => {
|
||||
// #docregion OnInit
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements OnInit {
|
||||
ngOnInit() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngOnInit', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngDoCheck', () => {
|
||||
// #docregion DoCheck
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements DoCheck {
|
||||
ngDoCheck() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngDoCheck', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngAfterContentChecked', () => {
|
||||
// #docregion AfterContentChecked
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements AfterContentChecked {
|
||||
ngAfterContentChecked() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterContentChecked', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngAfterContentInit', () => {
|
||||
// #docregion AfterContentInit
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements AfterContentInit {
|
||||
ngAfterContentInit() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterContentInit', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngAfterViewChecked', () => {
|
||||
// #docregion AfterViewChecked
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements AfterViewChecked {
|
||||
ngAfterViewChecked() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterViewChecked', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngAfterViewInit', () => {
|
||||
// #docregion AfterViewInit
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements AfterViewInit {
|
||||
ngAfterViewInit() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngAfterViewInit', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngOnDestroy', () => {
|
||||
// #docregion OnDestroy
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements OnDestroy {
|
||||
ngOnDestroy() {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
expect(createAndLogComponent(MyComponent)).toEqual([['ngOnDestroy', []]]);
|
||||
});
|
||||
|
||||
it('should work with ngOnChanges', () => {
|
||||
// #docregion OnChanges
|
||||
@Component({selector: 'my-cmp', template: `...`})
|
||||
class MyComponent implements OnChanges {
|
||||
@Input()
|
||||
prop: number;
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
// changes.prop contains the old and the new value...
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
const log = createAndLogComponent(MyComponent, ['prop']);
|
||||
expect(log.length).toBe(1);
|
||||
expect(log[0][0]).toBe('ngOnChanges');
|
||||
const changes: SimpleChanges = log[0][1][0];
|
||||
expect(changes['prop'].currentValue).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
function createAndLogComponent(clazz: Type<any>, inputs: string[] = []): any[] {
|
||||
const log: any[] = [];
|
||||
createLoggingSpiesFromProto(clazz, log);
|
||||
|
||||
const inputBindings = inputs.map(input => `[${input}] = true`).join(' ');
|
||||
|
||||
@Component({template: `<my-cmp ${inputBindings}></my-cmp>`})
|
||||
class ParentComponent {
|
||||
}
|
||||
|
||||
|
||||
const fixture = TestBed.configureTestingModule({declarations: [ParentComponent, clazz]})
|
||||
.createComponent(ParentComponent);
|
||||
fixture.detectChanges();
|
||||
fixture.destroy();
|
||||
return log;
|
||||
}
|
||||
|
||||
function createLoggingSpiesFromProto(clazz: Type<any>, log: any[]) {
|
||||
const proto = clazz.prototype;
|
||||
Object.keys(proto).forEach((method) => {
|
||||
proto[method] = (...args: any[]) => { log.push([method, args]); };
|
||||
});
|
||||
}
|
||||
}
|
51
packages/examples/core/ts/metadata/metadata.ts
Normal file
51
packages/examples/core/ts/metadata/metadata.ts
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Attribute, Component, Directive, Pipe} from '@angular/core';
|
||||
|
||||
class CustomDirective {};
|
||||
|
||||
// #docregion component
|
||||
@Component({selector: 'greet', template: 'Hello {{name}}!'})
|
||||
class Greet {
|
||||
name: string = 'World';
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// #docregion attributeFactory
|
||||
@Component({selector: 'page', template: 'Title: {{title}}'})
|
||||
class Page {
|
||||
title: string;
|
||||
constructor(@Attribute('title') title: string) { this.title = title; }
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// #docregion attributeMetadata
|
||||
@Directive({selector: 'input'})
|
||||
class InputAttrDirective {
|
||||
constructor(@Attribute('type') type: string) {
|
||||
// type would be 'text' in this example
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// #docregion directive
|
||||
@Directive({selector: 'input'})
|
||||
class InputDirective {
|
||||
constructor() {
|
||||
// Add some logic.
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
||||
|
||||
// #docregion pipe
|
||||
@Pipe({name: 'lowercase'})
|
||||
class Lowercase {
|
||||
transform(v: string, args: any[]) { return v.toLowerCase(); }
|
||||
}
|
||||
// #enddocregion
|
19
packages/examples/core/ts/platform/platform.ts
Normal file
19
packages/examples/core/ts/platform/platform.ts
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component, createPlatformFactory} from '@angular/core';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
|
||||
// #docregion longform
|
||||
@Component({selector: 'my-app', template: 'Hello World'})
|
||||
class MyApp {
|
||||
}
|
||||
|
||||
const myPlatformFactory = createPlatformFactory(platformBrowserDynamic, 'myPlatform');
|
||||
myPlatformFactory().bootstrapModule(MyApp);
|
||||
// #enddocregion
|
13
packages/examples/core/ts/prod_mode/my_component.ts
Normal file
13
packages/examples/core/ts/prod_mode/my_component.ts
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({selector: 'my-component', template: '<h1>My Component</h1>'})
|
||||
export class MyComponent {
|
||||
}
|
20
packages/examples/core/ts/prod_mode/prod_mode_example.ts
Normal file
20
packages/examples/core/ts/prod_mode/prod_mode_example.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion enableProdMode
|
||||
import {NgModule, enableProdMode} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
import {MyComponent} from './my_component';
|
||||
|
||||
enableProdMode();
|
||||
@NgModule({imports: [BrowserModule], bootstrap: [MyComponent]})
|
||||
class AppModule {
|
||||
}
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
// #enddocregion
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementArrayFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
describe('formBuilder example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
let inputs: ElementArrayFinder;
|
||||
let paragraphs: ElementArrayFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/forms/ts/formBuilder/index.html');
|
||||
inputs = element.all(by.css('input'));
|
||||
paragraphs = element.all(by.css('p'));
|
||||
});
|
||||
|
||||
it('should populate the UI with initial values', () => {
|
||||
expect(inputs.get(0).getAttribute('value')).toEqual('Nancy');
|
||||
expect(inputs.get(1).getAttribute('value')).toEqual('Drew');
|
||||
});
|
||||
|
||||
it('should update the validation status', () => {
|
||||
expect(paragraphs.get(1).getText()).toEqual('Validation status: VALID');
|
||||
|
||||
inputs.get(0).click();
|
||||
inputs.get(0).clear();
|
||||
inputs.get(0).sendKeys('a');
|
||||
expect(paragraphs.get(1).getText()).toEqual('Validation status: INVALID');
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion Component
|
||||
import {Component, Inject} from '@angular/core';
|
||||
import {FormBuilder, FormGroup, Validators} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<form [formGroup]="form">
|
||||
<div formGroupName="name">
|
||||
<input formControlName="first" placeholder="First">
|
||||
<input formControlName="last" placeholder="Last">
|
||||
</div>
|
||||
<input formControlName="email" placeholder="Email">
|
||||
<button>Submit</button>
|
||||
</form>
|
||||
|
||||
<p>Value: {{ form.value | json }}</p>
|
||||
<p>Validation status: {{ form.status }}</p>
|
||||
`
|
||||
})
|
||||
export class FormBuilderComp {
|
||||
form: FormGroup;
|
||||
|
||||
constructor(@Inject(FormBuilder) fb: FormBuilder) {
|
||||
this.form = fb.group({
|
||||
name: fb.group({
|
||||
first: ['Nancy', Validators.minLength(2)],
|
||||
last: 'Drew',
|
||||
}),
|
||||
email: '',
|
||||
});
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
20
packages/examples/forms/ts/formBuilder/module.ts
Normal file
20
packages/examples/forms/ts/formBuilder/module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {FormBuilderComp} from './form_builder_example';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule, ReactiveFormsModule],
|
||||
declarations: [FormBuilderComp],
|
||||
bootstrap: [FormBuilderComp]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementArrayFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
describe('nestedFormArray example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
let inputs: ElementArrayFinder;
|
||||
let buttons: ElementArrayFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/forms/ts/nestedFormArray/index.html');
|
||||
inputs = element.all(by.css('input'));
|
||||
buttons = element.all(by.css('button'));
|
||||
});
|
||||
|
||||
it('should populate the UI with initial values', () => {
|
||||
expect(inputs.get(0).getAttribute('value')).toEqual('SF');
|
||||
expect(inputs.get(1).getAttribute('value')).toEqual('NY');
|
||||
});
|
||||
|
||||
it('should add inputs programmatically', () => {
|
||||
expect(inputs.count()).toBe(2);
|
||||
|
||||
buttons.get(1).click();
|
||||
inputs = element.all(by.css('input'));
|
||||
|
||||
expect(inputs.count()).toBe(3);
|
||||
});
|
||||
|
||||
it('should set the value programmatically', () => {
|
||||
buttons.get(2).click();
|
||||
expect(inputs.get(0).getAttribute('value')).toEqual('LA');
|
||||
expect(inputs.get(1).getAttribute('value')).toEqual('MTV');
|
||||
});
|
||||
|
||||
});
|
20
packages/examples/forms/ts/nestedFormArray/module.ts
Normal file
20
packages/examples/forms/ts/nestedFormArray/module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {NestedFormArray} from './nested_form_array_example';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule, ReactiveFormsModule],
|
||||
declarations: [NestedFormArray],
|
||||
bootstrap: [NestedFormArray]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
/* tslint:disable:no-console */
|
||||
// #docregion Component
|
||||
import {Component} from '@angular/core';
|
||||
import {FormArray, FormControl, FormGroup} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<form [formGroup]="form" (ngSubmit)="onSubmit()">
|
||||
<div formArrayName="cities">
|
||||
<div *ngFor="let city of cities.controls; let i=index">
|
||||
<input [formControlName]="i" placeholder="City">
|
||||
</div>
|
||||
</div>
|
||||
<button>Submit</button>
|
||||
</form>
|
||||
|
||||
<button (click)="addCity()">Add City</button>
|
||||
<button (click)="setPreset()">Set preset</button>
|
||||
`,
|
||||
})
|
||||
export class NestedFormArray {
|
||||
form = new FormGroup({
|
||||
cities: new FormArray([
|
||||
new FormControl('SF'),
|
||||
new FormControl('NY'),
|
||||
]),
|
||||
});
|
||||
|
||||
get cities(): FormArray { return this.form.get('cities') as FormArray; }
|
||||
|
||||
addCity() { this.cities.push(new FormControl()); }
|
||||
|
||||
onSubmit() {
|
||||
console.log(this.cities.value); // ['SF', 'NY']
|
||||
console.log(this.form.value); // { cities: ['SF', 'NY'] }
|
||||
}
|
||||
|
||||
setPreset() { this.cities.patchValue(['LA', 'MTV']); }
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
describe('nestedFormGroup example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
let firstInput: ElementFinder;
|
||||
let lastInput: ElementFinder;
|
||||
let button: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/forms/ts/nestedFormGroup/index.html');
|
||||
firstInput = element(by.css('[formControlName="first"]'));
|
||||
lastInput = element(by.css('[formControlName="last"]'));
|
||||
button = element(by.css('button:not([type="submit"])'));
|
||||
});
|
||||
|
||||
it('should populate the UI with initial values', () => {
|
||||
expect(firstInput.getAttribute('value')).toEqual('Nancy');
|
||||
expect(lastInput.getAttribute('value')).toEqual('Drew');
|
||||
});
|
||||
|
||||
it('should show the error when name is invalid', () => {
|
||||
firstInput.click();
|
||||
firstInput.clear();
|
||||
firstInput.sendKeys('a');
|
||||
|
||||
expect(element(by.css('p')).getText()).toEqual('Name is invalid.');
|
||||
});
|
||||
|
||||
it('should set the value programmatically', () => {
|
||||
button.click();
|
||||
expect(firstInput.getAttribute('value')).toEqual('Bess');
|
||||
expect(lastInput.getAttribute('value')).toEqual('Marvin');
|
||||
});
|
||||
|
||||
});
|
20
packages/examples/forms/ts/nestedFormGroup/module.ts
Normal file
20
packages/examples/forms/ts/nestedFormGroup/module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {NestedFormGroupComp} from './nested_form_group_example';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule, ReactiveFormsModule],
|
||||
declarations: [NestedFormGroupComp],
|
||||
bootstrap: [NestedFormGroupComp]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
/* tslint:disable:no-console */
|
||||
// #docregion Component
|
||||
import {Component} from '@angular/core';
|
||||
import {FormControl, FormGroup, Validators} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<form [formGroup]="form" (ngSubmit)="onSubmit()">
|
||||
<p *ngIf="name.invalid">Name is invalid.</p>
|
||||
|
||||
<div formGroupName="name">
|
||||
<input formControlName="first" placeholder="First name">
|
||||
<input formControlName="last" placeholder="Last name">
|
||||
</div>
|
||||
<input formControlName="email" placeholder="Email">
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
|
||||
<button (click)="setPreset()">Set preset</button>
|
||||
`,
|
||||
})
|
||||
export class NestedFormGroupComp {
|
||||
form = new FormGroup({
|
||||
name: new FormGroup({
|
||||
first: new FormControl('Nancy', Validators.minLength(2)),
|
||||
last: new FormControl('Drew', Validators.required)
|
||||
}),
|
||||
email: new FormControl()
|
||||
});
|
||||
|
||||
get first(): any { return this.form.get('name.first'); }
|
||||
|
||||
get name(): any { return this.form.get('name'); }
|
||||
|
||||
onSubmit() {
|
||||
console.log(this.first.value); // 'Nancy'
|
||||
console.log(this.name.value); // {first: 'Nancy', last: 'Drew'}
|
||||
console.log(this.form.value); // {name: {first: 'Nancy', last: 'Drew'}, email: ''}
|
||||
console.log(this.form.status); // VALID
|
||||
}
|
||||
|
||||
setPreset() { this.name.setValue({first: 'Bess', last: 'Marvin'}); }
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementArrayFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
describe('ngModelGroup example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
let inputs: ElementArrayFinder;
|
||||
let buttons: ElementArrayFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/forms/ts/ngModelGroup/index.html');
|
||||
inputs = element.all(by.css('input'));
|
||||
buttons = element.all(by.css('button'));
|
||||
});
|
||||
|
||||
it('should populate the UI with initial values', () => {
|
||||
expect(inputs.get(0).getAttribute('value')).toEqual('Nancy');
|
||||
expect(inputs.get(1).getAttribute('value')).toEqual('Drew');
|
||||
});
|
||||
|
||||
it('should show the error when name is invalid', () => {
|
||||
inputs.get(0).click();
|
||||
inputs.get(0).clear();
|
||||
inputs.get(0).sendKeys('a');
|
||||
|
||||
expect(element(by.css('p')).getText()).toEqual('Name is invalid.');
|
||||
});
|
||||
|
||||
it('should set the value when changing the domain model', () => {
|
||||
buttons.get(1).click();
|
||||
expect(inputs.get(0).getAttribute('value')).toEqual('Bess');
|
||||
expect(inputs.get(1).getAttribute('value')).toEqual('Marvin');
|
||||
});
|
||||
|
||||
});
|
20
packages/examples/forms/ts/ngModelGroup/module.ts
Normal file
20
packages/examples/forms/ts/ngModelGroup/module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {NgModelGroupComp} from './ng_model_group_example';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule, FormsModule],
|
||||
declarations: [NgModelGroupComp],
|
||||
bootstrap: [NgModelGroupComp]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
/* tslint:disable:no-console */
|
||||
// #docregion Component
|
||||
import {Component} from '@angular/core';
|
||||
import {NgForm} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<form #f="ngForm" (ngSubmit)="onSubmit(f)">
|
||||
<p *ngIf="nameCtrl.invalid">Name is invalid.</p>
|
||||
|
||||
<div ngModelGroup="name" #nameCtrl="ngModelGroup">
|
||||
<input name="first" [ngModel]="name.first" minlength="2">
|
||||
<input name="last" [ngModel]="name.last" required>
|
||||
</div>
|
||||
|
||||
<input name="email" ngModel>
|
||||
<button>Submit</button>
|
||||
</form>
|
||||
|
||||
<button (click)="setValue()">Set value</button>
|
||||
`,
|
||||
})
|
||||
export class NgModelGroupComp {
|
||||
name = {first: 'Nancy', last: 'Drew'};
|
||||
|
||||
onSubmit(f: NgForm) {
|
||||
console.log(f.value); // {name: {first: 'Nancy', last: 'Drew'}, email: ''}
|
||||
console.log(f.valid); // true
|
||||
}
|
||||
|
||||
setValue() { this.name = {first: 'Bess', last: 'Marvin'}; }
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementArrayFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
describe('radioButtons example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
let inputs: ElementArrayFinder;
|
||||
let paragraphs: ElementArrayFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/forms/ts/radioButtons/index.html');
|
||||
inputs = element.all(by.css('input'));
|
||||
paragraphs = element.all(by.css('p'));
|
||||
});
|
||||
|
||||
it('should populate the UI with initial values', () => {
|
||||
expect(inputs.get(0).getAttribute('checked')).toEqual(null);
|
||||
expect(inputs.get(1).getAttribute('checked')).toEqual('true');
|
||||
expect(inputs.get(2).getAttribute('checked')).toEqual(null);
|
||||
|
||||
expect(paragraphs.get(0).getText()).toEqual('Form value: { "food": "lamb" }');
|
||||
expect(paragraphs.get(1).getText()).toEqual('myFood value: lamb');
|
||||
});
|
||||
|
||||
it('update model and other buttons as the UI value changes', () => {
|
||||
inputs.get(0).click();
|
||||
|
||||
expect(inputs.get(0).getAttribute('checked')).toEqual('true');
|
||||
expect(inputs.get(1).getAttribute('checked')).toEqual(null);
|
||||
expect(inputs.get(2).getAttribute('checked')).toEqual(null);
|
||||
|
||||
expect(paragraphs.get(0).getText()).toEqual('Form value: { "food": "beef" }');
|
||||
expect(paragraphs.get(1).getText()).toEqual('myFood value: beef');
|
||||
});
|
||||
});
|
20
packages/examples/forms/ts/radioButtons/module.ts
Normal file
20
packages/examples/forms/ts/radioButtons/module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {RadioButtonComp} from './radio_button_example';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule, FormsModule],
|
||||
declarations: [RadioButtonComp],
|
||||
bootstrap: [RadioButtonComp]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion TemplateDriven
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<form #f="ngForm">
|
||||
<input type="radio" value="beef" name="food" [(ngModel)]="myFood"> Beef
|
||||
<input type="radio" value="lamb" name="food" [(ngModel)]="myFood"> Lamb
|
||||
<input type="radio" value="fish" name="food" [(ngModel)]="myFood"> Fish
|
||||
</form>
|
||||
|
||||
<p>Form value: {{ f.value | json }}</p> <!-- {food: 'lamb' } -->
|
||||
<p>myFood value: {{ myFood }}</p> <!-- 'lamb' -->
|
||||
`,
|
||||
})
|
||||
export class RadioButtonComp {
|
||||
myFood = 'lamb';
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementArrayFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
describe('radioButtons example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
let inputs: ElementArrayFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/forms/ts/reactiveRadioButtons/index.html');
|
||||
inputs = element.all(by.css('input'));
|
||||
});
|
||||
|
||||
it('should populate the UI with initial values', () => {
|
||||
expect(inputs.get(0).getAttribute('checked')).toEqual(null);
|
||||
expect(inputs.get(1).getAttribute('checked')).toEqual('true');
|
||||
expect(inputs.get(2).getAttribute('checked')).toEqual(null);
|
||||
|
||||
expect(element(by.css('p')).getText()).toEqual('Form value: { "food": "lamb" }');
|
||||
});
|
||||
|
||||
it('update model and other buttons as the UI value changes', () => {
|
||||
inputs.get(0).click();
|
||||
|
||||
expect(inputs.get(0).getAttribute('checked')).toEqual('true');
|
||||
expect(inputs.get(1).getAttribute('checked')).toEqual(null);
|
||||
expect(inputs.get(2).getAttribute('checked')).toEqual(null);
|
||||
|
||||
expect(element(by.css('p')).getText()).toEqual('Form value: { "food": "beef" }');
|
||||
});
|
||||
});
|
20
packages/examples/forms/ts/reactiveRadioButtons/module.ts
Normal file
20
packages/examples/forms/ts/reactiveRadioButtons/module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {ReactiveRadioButtonComp} from './reactive_radio_button_example';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule, ReactiveFormsModule],
|
||||
declarations: [ReactiveRadioButtonComp],
|
||||
bootstrap: [ReactiveRadioButtonComp]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion Reactive
|
||||
import {Component} from '@angular/core';
|
||||
import {FormControl, FormGroup} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<form [formGroup]="form">
|
||||
<input type="radio" formControlName="food" value="beef" > Beef
|
||||
<input type="radio" formControlName="food" value="lamb"> Lamb
|
||||
<input type="radio" formControlName="food" value="fish"> Fish
|
||||
</form>
|
||||
|
||||
<p>Form value: {{ form.value | json }}</p> <!-- {food: 'lamb' } -->
|
||||
`,
|
||||
})
|
||||
export class ReactiveRadioButtonComp {
|
||||
form = new FormGroup({
|
||||
food: new FormControl('lamb'),
|
||||
});
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementArrayFinder, ElementFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
describe('reactiveSelectControl example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
let select: ElementFinder;
|
||||
let options: ElementArrayFinder;
|
||||
let p: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/forms/ts/reactiveSelectControl/index.html');
|
||||
select = element(by.css('select'));
|
||||
options = element.all(by.css('option'));
|
||||
p = element(by.css('p'));
|
||||
});
|
||||
|
||||
it('should populate the initial selection', () => {
|
||||
expect(select.getAttribute('value')).toEqual('3: Object');
|
||||
expect(options.get(3).getAttribute('selected')).toBe('true');
|
||||
});
|
||||
|
||||
it('should update the model when the value changes in the UI', () => {
|
||||
select.click();
|
||||
options.get(0).click();
|
||||
|
||||
expect(p.getText()).toEqual('Form value: { "state": { "name": "Arizona", "abbrev": "AZ" } }');
|
||||
});
|
||||
|
||||
});
|
20
packages/examples/forms/ts/reactiveSelectControl/module.ts
Normal file
20
packages/examples/forms/ts/reactiveSelectControl/module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {ReactiveSelectComp} from './reactive_select_control_example';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule, ReactiveFormsModule],
|
||||
declarations: [ReactiveSelectComp],
|
||||
bootstrap: [ReactiveSelectComp]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion Component
|
||||
import {Component} from '@angular/core';
|
||||
import {FormControl, FormGroup} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<form [formGroup]="form">
|
||||
<select formControlName="state">
|
||||
<option *ngFor="let state of states" [ngValue]="state">
|
||||
{{ state.abbrev }}
|
||||
</option>
|
||||
</select>
|
||||
</form>
|
||||
|
||||
<p>Form value: {{ form.value | json }}</p>
|
||||
<!-- {state: {name: 'New York', abbrev: 'NY'} } -->
|
||||
`,
|
||||
})
|
||||
export class ReactiveSelectComp {
|
||||
states = [
|
||||
{name: 'Arizona', abbrev: 'AZ'},
|
||||
{name: 'California', abbrev: 'CA'},
|
||||
{name: 'Colorado', abbrev: 'CO'},
|
||||
{name: 'New York', abbrev: 'NY'},
|
||||
{name: 'Pennsylvania', abbrev: 'PA'},
|
||||
];
|
||||
|
||||
form = new FormGroup({
|
||||
state: new FormControl(this.states[3]),
|
||||
});
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementArrayFinder, ElementFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
describe('selectControl example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
let select: ElementFinder;
|
||||
let options: ElementArrayFinder;
|
||||
let p: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/forms/ts/selectControl/index.html');
|
||||
select = element(by.css('select'));
|
||||
options = element.all(by.css('option'));
|
||||
p = element(by.css('p'));
|
||||
});
|
||||
|
||||
it('should initially select the placeholder option',
|
||||
() => { expect(options.get(0).getAttribute('selected')).toBe('true'); });
|
||||
|
||||
it('should update the model when the value changes in the UI', () => {
|
||||
select.click();
|
||||
options.get(1).click();
|
||||
|
||||
expect(p.getText()).toEqual('Form value: { "state": { "name": "Arizona", "abbrev": "AZ" } }');
|
||||
});
|
||||
|
||||
});
|
20
packages/examples/forms/ts/selectControl/module.ts
Normal file
20
packages/examples/forms/ts/selectControl/module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {SelectControlComp} from './select_control_example';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule, FormsModule],
|
||||
declarations: [SelectControlComp],
|
||||
bootstrap: [SelectControlComp]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion Component
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<form #f="ngForm">
|
||||
<select name="state" ngModel>
|
||||
<option value="" disabled>Choose a state</option>
|
||||
<option *ngFor="let state of states" [ngValue]="state">
|
||||
{{ state.abbrev }}
|
||||
</option>
|
||||
</select>
|
||||
</form>
|
||||
|
||||
<p>Form value: {{ f.value | json }}</p>
|
||||
<!-- example value: {state: {name: 'New York', abbrev: 'NY'} } -->
|
||||
`,
|
||||
})
|
||||
export class SelectControlComp {
|
||||
states = [
|
||||
{name: 'Arizona', abbrev: 'AZ'},
|
||||
{name: 'California', abbrev: 'CA'},
|
||||
{name: 'Colorado', abbrev: 'CO'},
|
||||
{name: 'New York', abbrev: 'NY'},
|
||||
{name: 'Pennsylvania', abbrev: 'PA'},
|
||||
];
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementArrayFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
describe('simpleForm example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
let inputs: ElementArrayFinder;
|
||||
let paragraphs: ElementArrayFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/forms/ts/simpleForm/index.html');
|
||||
inputs = element.all(by.css('input'));
|
||||
paragraphs = element.all(by.css('p'));
|
||||
});
|
||||
|
||||
it('should update the domain model as you type', () => {
|
||||
inputs.get(0).click();
|
||||
inputs.get(0).sendKeys('Nancy');
|
||||
|
||||
inputs.get(1).click();
|
||||
inputs.get(1).sendKeys('Drew');
|
||||
|
||||
expect(paragraphs.get(0).getText()).toEqual('First name value: Nancy');
|
||||
expect(paragraphs.get(2).getText()).toEqual('Form value: { "first": "Nancy", "last": "Drew" }');
|
||||
});
|
||||
|
||||
it('should report the validity correctly', () => {
|
||||
expect(paragraphs.get(1).getText()).toEqual('First name valid: false');
|
||||
expect(paragraphs.get(3).getText()).toEqual('Form valid: false');
|
||||
inputs.get(0).click();
|
||||
inputs.get(0).sendKeys('a');
|
||||
|
||||
expect(paragraphs.get(1).getText()).toEqual('First name valid: true');
|
||||
expect(paragraphs.get(3).getText()).toEqual('Form valid: true');
|
||||
});
|
||||
|
||||
});
|
20
packages/examples/forms/ts/simpleForm/module.ts
Normal file
20
packages/examples/forms/ts/simpleForm/module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {SimpleFormComp} from './simple_form_example';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule, FormsModule],
|
||||
declarations: [SimpleFormComp],
|
||||
bootstrap: [SimpleFormComp]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
35
packages/examples/forms/ts/simpleForm/simple_form_example.ts
Normal file
35
packages/examples/forms/ts/simpleForm/simple_form_example.ts
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
/* tslint:disable:no-console */
|
||||
// #docregion Component
|
||||
import {Component} from '@angular/core';
|
||||
import {NgForm} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<form #f="ngForm" (ngSubmit)="onSubmit(f)" novalidate>
|
||||
<input name="first" ngModel required #first="ngModel">
|
||||
<input name="last" ngModel>
|
||||
<button>Submit</button>
|
||||
</form>
|
||||
|
||||
<p>First name value: {{ first.value }}</p>
|
||||
<p>First name valid: {{ first.valid }}</p>
|
||||
<p>Form value: {{ f.value | json }}</p>
|
||||
<p>Form valid: {{ f.valid }}</p>
|
||||
`,
|
||||
})
|
||||
export class SimpleFormComp {
|
||||
onSubmit(f: NgForm) {
|
||||
console.log(f.value); // { first: '', last: '' }
|
||||
console.log(f.valid); // false
|
||||
}
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,54 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
describe('simpleFormControl example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
|
||||
describe('index view', () => {
|
||||
let input: ElementFinder;
|
||||
let valueP: ElementFinder;
|
||||
let statusP: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/forms/ts/simpleFormControl/index.html');
|
||||
input = element(by.css('input'));
|
||||
valueP = element(by.css('p:first-of-type'));
|
||||
statusP = element(by.css('p:last-of-type'));
|
||||
});
|
||||
|
||||
it('should populate the form control value in the DOM', () => {
|
||||
expect(input.getAttribute('value')).toEqual('value');
|
||||
expect(valueP.getText()).toEqual('Value: value');
|
||||
});
|
||||
|
||||
it('should update the value as user types', () => {
|
||||
input.click();
|
||||
input.sendKeys('s!');
|
||||
|
||||
expect(valueP.getText()).toEqual('Value: values!');
|
||||
});
|
||||
|
||||
it('should show the correct validity state', () => {
|
||||
expect(statusP.getText()).toEqual('Validation status: VALID');
|
||||
|
||||
input.click();
|
||||
input.clear();
|
||||
input.sendKeys('a');
|
||||
expect(statusP.getText()).toEqual('Validation status: INVALID');
|
||||
});
|
||||
|
||||
it('should set the value programmatically', () => {
|
||||
element(by.css('button')).click();
|
||||
expect(input.getAttribute('value')).toEqual('new value');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
20
packages/examples/forms/ts/simpleFormControl/module.ts
Normal file
20
packages/examples/forms/ts/simpleFormControl/module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {SimpleFormControl} from './simple_form_control_example';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule, ReactiveFormsModule],
|
||||
declarations: [SimpleFormControl],
|
||||
bootstrap: [SimpleFormControl]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion Component
|
||||
import {Component} from '@angular/core';
|
||||
import {FormControl, Validators} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<input [formControl]="control">
|
||||
|
||||
<p>Value: {{ control.value }}</p>
|
||||
<p>Validation status: {{ control.status }}</p>
|
||||
|
||||
<button (click)="setValue()">Set value</button>
|
||||
`,
|
||||
})
|
||||
export class SimpleFormControl {
|
||||
control: FormControl = new FormControl('value', Validators.minLength(2));
|
||||
|
||||
setValue() { this.control.setValue('new value'); }
|
||||
}
|
||||
// #enddocregion
|
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
describe('formControlName example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
|
||||
describe('index view', () => {
|
||||
let firstInput: ElementFinder;
|
||||
let lastInput: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/forms/ts/simpleFormGroup/index.html');
|
||||
firstInput = element(by.css('[formControlName="first"]'));
|
||||
lastInput = element(by.css('[formControlName="last"]'));
|
||||
});
|
||||
|
||||
it('should populate the form control values in the DOM', () => {
|
||||
expect(firstInput.getAttribute('value')).toEqual('Nancy');
|
||||
expect(lastInput.getAttribute('value')).toEqual('Drew');
|
||||
});
|
||||
|
||||
it('should show the error when the form is invalid', () => {
|
||||
firstInput.click();
|
||||
firstInput.clear();
|
||||
firstInput.sendKeys('a');
|
||||
|
||||
expect(element(by.css('div')).getText()).toEqual('Name is too short.');
|
||||
});
|
||||
|
||||
it('should set the value programmatically', () => {
|
||||
element(by.css('button:not([type="submit"])')).click();
|
||||
expect(firstInput.getAttribute('value')).toEqual('Carson');
|
||||
expect(lastInput.getAttribute('value')).toEqual('Drew');
|
||||
});
|
||||
|
||||
});
|
||||
});
|
20
packages/examples/forms/ts/simpleFormGroup/module.ts
Normal file
20
packages/examples/forms/ts/simpleFormGroup/module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {ReactiveFormsModule} from '@angular/forms';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {SimpleFormGroup} from './simple_form_group_example';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule, ReactiveFormsModule],
|
||||
declarations: [SimpleFormGroup],
|
||||
bootstrap: [SimpleFormGroup]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
/* tslint:disable:no-console */
|
||||
// #docregion Component
|
||||
import {Component} from '@angular/core';
|
||||
import {FormControl, FormGroup, Validators} from '@angular/forms';
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<form [formGroup]="form" (ngSubmit)="onSubmit()">
|
||||
<div *ngIf="first.invalid"> Name is too short. </div>
|
||||
|
||||
<input formControlName="first" placeholder="First name">
|
||||
<input formControlName="last" placeholder="Last name">
|
||||
|
||||
<button type="submit">Submit</button>
|
||||
</form>
|
||||
<button (click)="setValue()">Set preset value</button>
|
||||
`,
|
||||
})
|
||||
export class SimpleFormGroup {
|
||||
form = new FormGroup({
|
||||
first: new FormControl('Nancy', Validators.minLength(2)),
|
||||
last: new FormControl('Drew'),
|
||||
});
|
||||
|
||||
get first(): any { return this.form.get('first'); }
|
||||
|
||||
onSubmit(): void {
|
||||
console.log(this.form.value); // {first: 'Nancy', last: 'Drew'}
|
||||
}
|
||||
|
||||
setValue() { this.form.setValue({first: 'Carson', last: 'Drew'}); }
|
||||
}
|
||||
|
||||
|
||||
// #enddocregion
|
@ -0,0 +1,45 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {ElementArrayFinder, ElementFinder, browser, by, element} from 'protractor';
|
||||
import {verifyNoBrowserErrors} from '../../../../_common/e2e_util';
|
||||
|
||||
describe('simpleNgModel example', () => {
|
||||
afterEach(verifyNoBrowserErrors);
|
||||
let input: ElementFinder;
|
||||
let paragraphs: ElementArrayFinder;
|
||||
let button: ElementFinder;
|
||||
|
||||
beforeEach(() => {
|
||||
browser.get('/forms/ts/simpleNgModel/index.html');
|
||||
input = element(by.css('input'));
|
||||
paragraphs = element.all(by.css('p'));
|
||||
button = element(by.css('button'));
|
||||
});
|
||||
|
||||
it('should update the domain model as you type', () => {
|
||||
input.click();
|
||||
input.sendKeys('Carson');
|
||||
|
||||
expect(paragraphs.get(0).getText()).toEqual('Value: Carson');
|
||||
});
|
||||
|
||||
it('should report the validity correctly', () => {
|
||||
expect(paragraphs.get(1).getText()).toEqual('Valid: false');
|
||||
input.click();
|
||||
input.sendKeys('a');
|
||||
|
||||
expect(paragraphs.get(1).getText()).toEqual('Valid: true');
|
||||
});
|
||||
|
||||
it('should set the value by changing the domain model', () => {
|
||||
button.click();
|
||||
expect(input.getAttribute('value')).toEqual('Nancy');
|
||||
});
|
||||
|
||||
});
|
20
packages/examples/forms/ts/simpleNgModel/module.ts
Normal file
20
packages/examples/forms/ts/simpleNgModel/module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgModule} from '@angular/core';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {SimpleNgModelComp} from './simple_ng_model_example';
|
||||
|
||||
@NgModule({
|
||||
imports: [BrowserModule, FormsModule],
|
||||
declarations: [SimpleNgModelComp],
|
||||
bootstrap: [SimpleNgModelComp]
|
||||
})
|
||||
export class AppModule {
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// #docregion Component
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'example-app',
|
||||
template: `
|
||||
<input [(ngModel)]="name" #ctrl="ngModel" required>
|
||||
|
||||
<p>Value: {{ name }}</p>
|
||||
<p>Valid: {{ ctrl.valid }}</p>
|
||||
|
||||
<button (click)="setValue()">Set value</button>
|
||||
`,
|
||||
})
|
||||
export class SimpleNgModelComp {
|
||||
name: string = '';
|
||||
|
||||
setValue() { this.name = 'Nancy'; }
|
||||
}
|
||||
// #enddocregion
|
0
packages/examples/http/ts/.gitkeep
Normal file
0
packages/examples/http/ts/.gitkeep
Normal file
25
packages/examples/platform-browser/dom/debug/ts/by/by.ts
Normal file
25
packages/examples/platform-browser/dom/debug/ts/by/by.ts
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {DebugElement} from '@angular/core';
|
||||
import {By} from '@angular/platform-browser';
|
||||
|
||||
let debugElement: DebugElement;
|
||||
class MyDirective {}
|
||||
|
||||
// #docregion by_all
|
||||
debugElement.query(By.all());
|
||||
// #enddocregion
|
||||
|
||||
// #docregion by_css
|
||||
debugElement.query(By.css('[attribute]'));
|
||||
// #enddocregion
|
||||
|
||||
// #docregion by_directive
|
||||
debugElement.query(By.directive(MyDirective));
|
||||
// #enddocregion
|
@ -0,0 +1,23 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
|
||||
import {Component, NgModule} from '@angular/core';
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||
|
||||
@Component({selector: 'my-component'})
|
||||
class MyAppComponent {
|
||||
}
|
||||
|
||||
// #docregion providers
|
||||
@NgModule({imports: [BrowserModule], bootstrap: [MyAppComponent]})
|
||||
class AppModule {
|
||||
}
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
// #enddocregion
|
8
packages/examples/test.sh
Executable file
8
packages/examples/test.sh
Executable file
@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd `dirname $0`
|
||||
./build.sh
|
||||
|
||||
gulp serve-examples &
|
||||
|
||||
(cd ../../../ && NODE_PATH=$NODE_PATH:dist/all $(npm bin)/protractor protractor-examples-e2e.conf.js --bundles=true)
|
38
packages/examples/testing/ts/fake_async.ts
Normal file
38
packages/examples/testing/ts/fake_async.ts
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {discardPeriodicTasks, fakeAsync, tick} from '@angular/core/testing';
|
||||
|
||||
|
||||
// #docregion basic
|
||||
describe('this test', () => {
|
||||
it('looks async but is synchronous', <any>fakeAsync((): void => {
|
||||
let flag = false;
|
||||
setTimeout(() => { flag = true; }, 100);
|
||||
expect(flag).toBe(false);
|
||||
tick(50);
|
||||
expect(flag).toBe(false);
|
||||
tick(50);
|
||||
expect(flag).toBe(true);
|
||||
}));
|
||||
});
|
||||
// #enddocregion
|
||||
|
||||
// #docregion pending
|
||||
describe('this test', () => {
|
||||
it('aborts a periodic timer', <any>fakeAsync((): void => {
|
||||
// This timer is scheduled but doesn't need to complete for the
|
||||
// test to pass (maybe it's a timeout for some operation).
|
||||
// Leaving it will cause the test to fail...
|
||||
setInterval(() => {}, 100);
|
||||
|
||||
// Unless we clean it up first.
|
||||
discardPeriodicTasks();
|
||||
}));
|
||||
});
|
||||
// #enddocregion
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user