Merge branch 'pr/2' into fix-styleguide-trigger-positioning

This commit is contained in:
Jacob Müller 2016-09-21 16:21:50 +02:00
commit 0bae5fca69
1088 changed files with 22114 additions and 19593 deletions

30
.eslintrc.js Normal file
View File

@ -0,0 +1,30 @@
module.exports = {
"globals": {
"describe": true,
"beforeEach": true,
"it": true,
"expect": true
},
"env": {
"node": true
},
"extends": "eslint:recommended",
"rules": {
"indent": [
"error",
2
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
]
}
};

6
.firebaserc Normal file
View File

@ -0,0 +1,6 @@
{
"projects": {
"live": "angular-io",
"ngdocsdev": "ngdocsdev"
}
}

4
.gitignore vendored
View File

@ -21,10 +21,12 @@ _.*
**/resources/zips
public/docs/xref-*.*
_zip-output
www
www*
npm-debug*.log*
*.plnkr.html
plnkr.html
*.eplnkr.html
eplnkr.html
*plnkr.no-link.html
public/docs/*/latest/guide/cheatsheet.json
protractor-results.txt

2
.nvmrc
View File

@ -1 +1 @@
5
6

View File

@ -2,7 +2,7 @@ dist: trusty
sudo: required
language: node_js
node_js:
- "5"
- "6"
os:
- linux
env:
@ -10,20 +10,20 @@ env:
- DBUS_SESSION_BUS_ADDRESS=/dev/null
- DISPLAY=:99.0
- CHROME_BIN=chromium-browser
- LATEST_RELEASE=2.0.0-rc.4
# using SHA instead of version to fix build-compile issue
- LATEST_RELEASE=cfc12c653970c9ad6d807a6a8ebff58edbc568a0
- TASK_FLAGS="--dgeni-log=warn"
# - TASK_FLAGS=""
matrix:
- TASK=lint
- TASK="run-e2e-tests --fast" SCRIPT=examples-install.sh
- TASK="run-e2e-tests --fast" SCRIPT=examples-install-preview.sh
- TASK=build-compile SCRIPT=deploy-install.sh WAIT="travis_wait 50"
- TASK=build-compile SCRIPT=deploy-install-preview.sh WAIT="travis_wait 50"
- TASK=build-compile SCRIPT=deploy-install.sh WAIT="travis_wait 50" POST_SCRIPT="check-docs.sh -v"
- TASK=build-compile SCRIPT=deploy-install-preview.sh WAIT="travis_wait 50" POST_SCRIPT="check-docs.sh -v"
matrix:
fast_finish: true
allow_failures:
- env: TASK="run-e2e-tests --fast" SCRIPT=examples-install-preview.sh
- env: TASK=build-compile SCRIPT=deploy-install-preview.sh WAIT="travis_wait 50"
- env: TASK=build-compile SCRIPT=deploy-install-preview.sh WAIT="travis_wait 50" POST_SCRIPT="check-docs.sh -v"
before_install:
- source ./scripts/env-set.sh
- ./scripts/before-install.sh
@ -34,3 +34,4 @@ before_script:
- sh -e /etc/init.d/xvfb start
script:
- $WAIT gulp $TASK $TASK_FLAGS
- if [[ -n "$POST_SCRIPT" ]]; then ./scripts/$POST_SCRIPT; fi

View File

@ -1,7 +1,7 @@
# Angular.io
[![Build Status][travis-badge]][travis-badge-url]
Angular.io is site for Angular 2 **documentation** .
Angular.io is site for Angular **documentation** .
This site also includes links to other helpful angular resources including
Angular 2, Angular 1, Angular Material, and AngularFire.
@ -21,16 +21,18 @@ Filing issues is helpful but **pull requests** that improve the docs are even be
Learn how to [contribute to Angular.io](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md).
> **IMPORTANT**: Do _NOT_ make changes to cached files under `public/docs/ts/_cache`. Cached files are updated through a separate workflow.
## Development Setup
This site relies heavily on node and npm.
1. Make sure you are using at least node v.5+ and latest npm;
if not install [nvm](https://github.com/creationix/nvm) to get node going on your machine.
1. install these npm packages *globally*: `npm install -g harp gulp`
1. Install these npm packages *globally*: `npm install -g harp gulp`
1. clone this repo and the [angular source code repo](https://github.com/angular/angular) to the same parent directory.
The two cloned repo directories must be sibling.
1. Clone this repo, the [angular/angular source code repo](https://github.com/angular/angular), and the [dart-lang/angular2 source code repo](https://github.com/dart-lang/angular2) to the same parent directory.
The three cloned repo directories must be siblings, with the latter two repo directories named **angular** and **angular-dart**, respectively.
1. cd into root directory `angular.io/`
@ -71,11 +73,11 @@ If you are only going to work on a specific part of the docs, such as the dev gu
## Code Sample Development
All documentation is supported by sample code and plunkers.
Such code resides in the `public/docs/_examples` directory, under chapter-specific directories, further divided by language track.
Such code resides in the `public/docs/_examples` directory, under page-specific directories, further divided by language track.
For example, the TypeScript QuickStart sample is in `public/docs/_examples/quickstart/ts`.
All samples are in a consistent directory structure using the same styles and the same npm packages, including the latest release of Angular 2.
All samples are in a consistent directory structure using the same styles and the same npm packages, including the latest release of Angular.
This consistency is possible in part thanks to gulp-driven tooling.
To run the samples locally and confirm that they work properly,
take the following extra steps to prepare the environment:

View File

@ -45,7 +45,8 @@ var STYLES_SOURCE_PATH = path.join(TOOLS_PATH, 'styles-builder/less');
var docShredder = require(path.resolve(TOOLS_PATH, 'doc-shredder/doc-shredder'));
var exampleZipper = require(path.resolve(TOOLS_PATH, '_example-zipper/exampleZipper'));
var plunkerBuilder = require(path.resolve(TOOLS_PATH, 'plunker-builder/plunkerBuilder'));
var regularPlunker = require(path.resolve(TOOLS_PATH, 'plunker-builder/regularPlunker'));
var embeddedPlunker = require(path.resolve(TOOLS_PATH, 'plunker-builder/embeddedPlunker'));
var fsUtils = require(path.resolve(TOOLS_PATH, 'fs-utils/fsUtils'));
const isSilent = !!argv.silent;
@ -72,9 +73,10 @@ var _apiShredOptions = {
logLevel: _dgeniLogLevel
};
const relDartDocApiDir = path.join('doc', 'api');
var _apiShredOptionsForDart = {
lang: 'dart',
examplesDir: path.resolve(ngPathFor('dart'), 'examples'),
examplesDir: path.resolve(ngPathFor('dart'), 'example'),
fragmentsDir: path.join(DOCS_PATH, '_fragments/_api'),
zipDir: path.join(RESOURCES_PATH, 'zips/api'),
logLevel: _dgeniLogLevel
@ -89,15 +91,12 @@ var _excludeMatchers = _excludePatterns.map(function(excludePattern){
var _exampleBoilerplateFiles = [
'.editorconfig',
'a2docs.css',
'karma.conf.js',
'karma-test-shim.js',
'package.json',
'styles.css',
'systemjs.config.js',
'tsconfig.json',
'tslint.json',
'typings.json',
'wallaby.js'
'typings.json'
];
var _exampleDartWebBoilerPlateFiles = ['a2docs.css', 'styles.css'];
@ -118,22 +117,35 @@ var _styleLessName = 'a2docs.less';
// or a regex pattern to match any one of 'ts', 'js', or 'dart'.
// Default: 'ts|js' except for the "full site build" tasks (see below),
// for which it is 'all'.
//
var lang, langs, buildDartApiDocs = false;
// langs and skipLangs partition ['ts', 'js', 'dart'].
var lang, langs, skipLangs, buildDartApiDocs = false;
function configLangs(langOption) {
const fullSiteBuildTasks = ['build-compile', 'check-serve', 'check-deploy'];
const fullSiteBuildTasks = ['build-compile', 'check-deploy', 'harp-compile'];
const buildAllDocs = argv['_'] &&
fullSiteBuildTasks.some((task) => argv['_'].indexOf(task) >= 0);
const langDefault = buildAllDocs ? 'all' : 'ts|js';
if (langOption === '') {
lang = '';
langs = [];
} else {
lang = (langOption || langDefault).toLowerCase();
if (lang === 'all') lang = 'ts|js|dart';
langs = lang.match(/\w+/g); // the languages in `lang` as an array
gutil.log('Building docs for: ' + lang);
}
gutil.log(`Building docs for: [${langs}]`);
if (langs.indexOf('dart') >= 0) {
buildDartApiDocs = true;
// For Dart, be proactive about checking for the repo
checkAngularProjectPath(ngPathFor('dart'));
} else {
argv.pub = false;
}
skipLangs = [];
['ts', 'js', 'dart'].forEach(lang => {
if (langs.indexOf(lang) < 0) skipLangs.push(lang);
});
gutil.log(`Skipped languages: [${skipLangs}]`);
}
configLangs(argv.lang);
@ -344,10 +356,15 @@ function runE2eDartTests(appDir, outputFile) {
gutil.log('http-server failed to launch over ' + deployDir);
return false;
}
if (argv.pub === false) {
var prepPromise = Promise.resolve(true);
gutil.log('Skipping pub upgrade and pub build (--no-pub flag present)');
} else {
var pubUpgradeSpawnInfo = spawnExt('pub', ['upgrade'], { cwd: appDir });
var prepPromise = pubUpgradeSpawnInfo.promise.then(function (data) {
return spawnExt('pub', ['build'], { cwd: appDir }).promise;
});
}
return runProtractor(prepPromise, appDir, appRunSpawnInfo, outputFile);
}
@ -441,10 +458,10 @@ gulp.task('add-example-boilerplate', function(done) {
// copies boilerplate files to locations
// where an example app is found
gulp.task('_copy-example-boilerplate', function (done) {
if (!argv.fast) buildStyles(copyExampleBoilerplate, done);
return argv.fast ? done() : buildStyles(copyExampleBoilerplate, done);
});
//Builds Angular 2 Docs CSS file from Bootstrap npm LESS source
//Builds Angular Docs CSS file from Bootstrap npm LESS source
//and copies the result to the _examples folder to be included as
//part of the example boilerplate.
function buildStyles(cb, done){
@ -504,23 +521,42 @@ gulp.task('remove-example-boilerplate', function() {
// either release or current build packages
// Examples:
// gulp install-example-angular --build // use current build packages
// gulp install-example-angular --build=2.0.0-b43f954 // use tagged packages
// gulp install-example-angular // restore release packages
//
// Find the tags here: https://github.com/angular/core-builds/releases
gulp.task('install-example-angular', installExampleAngular);
function installExampleAngular() {
var sources;
var template;
var libs = [
'core', 'common', 'compiler',
'core', 'common', 'compiler', 'compiler-cli',
'platform-browser', 'platform-browser-dynamic',
'forms', 'http', 'router', 'upgrade'];
var build = argv.build;
if (build) {
if (typeof build === 'string') {
build = (build[0]==='#' ? '' : '#') + build;
} else {
build = '';
}
} else{
build = 'npm';
}
// Like: "angular/core-builds" or "@angular/core"
sources = libs.map( lib => argv.build ? `angular/${lib}-builds` : `@angular/${lib}`);
sources = libs.map( lib => {
return build === 'npm'
? `@angular/${lib}`
: `git+https://github.com/angular/${lib}-builds${build}`;
});
if (argv.build) { sources.push('@angular/tsc-wrapped');} // tsc-wrapped needed for builds
sources.push('@angular/router-deprecated');
gutil.log(`Installing Angular npm packages from ${argv.build ? 'BUILD' : 'RELEASE'}`);
gutil.log(`Installing Angular packages from ${build === 'npm' ? 'NPM' : 'BUILD ' + build}`);
var spawnInfo = spawnExt('rm', ['-rf', 'node_modules/@angular'], { cwd: EXAMPLES_PATH});
return spawnInfo.promise
@ -594,8 +630,10 @@ gulp.task('build-dart-api-docs', ['_shred-api-examples', 'dartdoc'], function()
return buildApiDocsForDart();
});
// Using the --build flag will use systemjs.config.plunker.build.js (for preview builds)
gulp.task('build-plunkers', ['_copy-example-boilerplate'], function() {
return plunkerBuilder.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH, { errFn: gutil.log, build: argv.build });
regularPlunker.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH, { errFn: gutil.log, build: argv.build });
return embeddedPlunker.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH, { errFn: gutil.log, build: argv.build, targetSelf: argv.targetSelf });
});
gulp.task('build-dart-cheatsheet', [], function() {
@ -604,20 +642,20 @@ gulp.task('build-dart-cheatsheet', [], function() {
gulp.task('dartdoc', ['pub upgrade'], function() {
const ngRepoPath = ngPathFor('dart');
if (argv.fast && fs.existsSync(path.resolve(ngRepoPath, 'doc'))) {
gutil.log('Skipping dartdoc: --fast flag enabled and "doc" dir exists');
if (argv.fast && fs.existsSync(path.resolve(ngRepoPath, relDartDocApiDir))) {
gutil.log(`Skipping dartdoc: --fast flag enabled and api dir exists (${relDartDocApiDir})`);
return true;
}
checkAngularProjectPath(ngRepoPath);
const topLevelLibFilePath = path.resolve(ngRepoPath, 'lib', 'angular2.dart');
const tmpPath = topLevelLibFilePath + '.disabled';
if (!fs.existsSync(topLevelLibFilePath)) throw new Error(`Missing file: ${topLevelLibFilePath}`);
fs.renameSync(topLevelLibFilePath, tmpPath);
renameIfExistsSync(topLevelLibFilePath, tmpPath);
gutil.log(`Hiding top-level angular2 library: ${topLevelLibFilePath}`);
const dartdoc = spawnExt('dartdoc', ['--output', 'doc/api', '--add-crossdart'], { cwd: ngRepoPath});
// Remove dartdoc '--add-crossdart' flag while we are fixing links to API pages.
const dartdoc = spawnExt('dartdoc', ['--output', relDartDocApiDir], { cwd: ngRepoPath});
return dartdoc.promise.finally(() => {
gutil.log(`Restoring top-level angular2 library: ${topLevelLibFilePath}`);
fs.renameSync(tmpPath, topLevelLibFilePath);
renameIfExistsSync(tmpPath, topLevelLibFilePath);
})
});
@ -678,12 +716,12 @@ gulp.task('git-changed-examples', ['_shred-devguide-examples'], function(){
});
});
gulp.task('harp-compile', [], function() {
gulp.task('harp-compile', () => {
return harpCompile()
});
gulp.task('serve', [], function() {
// Harp will serve files from workspace.
gulp.task('harp-serve', () => {
// Harp will watch and serve workspace files.
const cmd = 'npm run harp -- server .';
gutil.log('Launching harp server (over project files)');
gutil.log(` > ${cmd}`);
@ -691,7 +729,7 @@ gulp.task('serve', [], function() {
return execPromise(cmd);
});
gulp.task('serve-www', [], function() {
gulp.task('serve-www', () => {
// Serve generated site.
return execPromise('npm run live-server ./www');
});
@ -700,13 +738,6 @@ gulp.task('build-compile', ['build-docs'], function() {
return harpCompile();
});
gulp.task('check-serve', ['build-docs'], function() {
return harpCompile().then(function() {
gutil.log('Launching live-server over ./www');
return execPromise('npm run live-server ./www');
});
});
gulp.task('check-deploy', ['build-docs'], function() {
return harpCompile().then(function() {
gutil.log('compile ok');
@ -802,7 +833,7 @@ gulp.task('_shred-clean-devguide', function(cb) {
gulp.task('_shred-api-examples', ['_shred-clean-api'], function() {
const promises = [];
gutil.log('Shredding API examples for languages: ' + langs.join(', '));
langs.forEach((lang) => {
langs.forEach(lang => {
if (lang === 'js') return; // JS is handled via TS.
checkAngularProjectPath(ngPathFor(lang));
const options = lang == 'dart' ? _apiShredOptionsForDart : _apiShredOptions;
@ -852,26 +883,40 @@ gulp.task('lint', function() {
function harpCompile() {
// Supposedly running in production makes harp faster
// and less likely to drown in node_modules.
env({
vars: { NODE_ENV: "production" }
});
env({ vars: { NODE_ENV: "production" } });
gutil.log("NODE_ENV: " + process.env.NODE_ENV);
if(skipLangs && fs.existsSync('www') && backupApiHtmlFilesExist('www')) {
gutil.log(`Harp site recompile: skipping recompilation of API docs for [${skipLangs}]`);
gutil.log(`API docs will be copied from existing www folder.`)
del.sync('www-backup'); // remove existing backup if it exists
renameIfExistsSync('www', 'www-backup');
} else {
gutil.log(`Harp full site compile, including API docs for all languages.`);
if (skipLangs)
gutil.log(`Ignoring API docs skip set (${skipLangs}) because full ` +
`site has not been built yet or some API HTML files are missing.`);
}
var deferred = Q.defer();
gutil.log('running harp compile...');
showHideExampleNodeModules('hide');
showHideApiDir('hide');
var spawnInfo = spawnExt('npm',['run','harp', '--', 'compile', '.', './www' ]);
spawnInfo.promise.then(function(x) {
gutil.log("NODE_ENV: " + process.env.NODE_ENV);
showHideExampleNodeModules('show');
showHideApiDir('show');
if (x !== 0) {
deferred.reject(x)
} else {
restoreApiHtml();
deferred.resolve(x);
}
}).catch(function(e) {
gutil.log("NODE_ENV: " + process.env.NODE_ENV);
showHideExampleNodeModules('show');
showHideApiDir('show');
deferred.reject(e);
});
return deferred.promise;
@ -970,6 +1015,54 @@ function showHideExampleNodeModules(showOrHide) {
}
}
// Show/hide the API docs harp source folder for every lang in skipLangs.
function showHideApiDir(showOrHide) {
skipLangs.forEach(lang => {
_showHideApiDir(lang, showOrHide);
});
}
// Rename the API docs harp source folder for lang to/from 'api' to '_api-tmp-foo'.
function _showHideApiDir(lang, showOrHide) {
const vers = 'latest';
const basePath = path.join(DOCS_PATH, lang, vers);
const apiDirPath = path.join(basePath, 'api');
const disabledApiDirPath = path.join(basePath, '_api-tmp-hide-from-jade');
const args = showOrHide == 'hide'
? [apiDirPath, disabledApiDirPath]
: [disabledApiDirPath, apiDirPath];
renameIfExistsSync(...args);
}
// For each lang in skipLangs, copy the API dir from www-backup to www.
function restoreApiHtml() {
const vers = 'latest';
skipLangs.forEach(lang => {
const relApiDir = path.join('docs', lang, vers, 'api');
const wwwApiSubdir = path.join('www', relApiDir);
const backupApiSubdir = path.join('www-backup', relApiDir);
if (fs.existsSync(backupApiSubdir) || argv.forceSkipApi !== true) {
gutil.log(`cp ${backupApiSubdir} ${wwwApiSubdir}`)
fs.copySync(backupApiSubdir, wwwApiSubdir);
}
});
}
// For each lang in skipLangs, ensure API dir exists in www-backup
function backupApiHtmlFilesExist(folderName) {
const vers = 'latest';
var result = 1;
skipLangs.forEach(lang => {
const relApiDir = path.join('docs', lang, vers, 'api');
const backupApiSubdir = path.join(folderName, relApiDir);
if (!fs.existsSync(backupApiSubdir)) {
gutil.log(`WARNING: API docs HTML folder doesn't exist: ${backupApiSubdir}`);
result = 0;
}
});
return result;
}
// Copies fileNames into destPaths, setting the mode of the
// files at the destination as optional_destFileMode if given.
// returns a promise
@ -1069,11 +1162,16 @@ function watchAndSync(options, cb) {
var browserSync = require('browser-sync').create();
browserSync.init({proxy: 'localhost:9000'});
// When using the --focus=name flag, only **/name/**/*.* example files and
// **/name.jade files are watched. This is useful for performance reasons.
// Example: gulp serve-and-sync --focus=architecture
var focus = argv.focus;
if (options.devGuide) {
devGuideExamplesWatch(_devguideShredOptions, browserSync.reload);
devGuideExamplesWatch(_devguideShredOptions, browserSync.reload, focus);
}
if (options.devGuideJade) {
devGuideSharedJadeWatch( { jadeDir: DOCS_PATH}, browserSync.reload);
devGuideSharedJadeWatch( { jadeDir: DOCS_PATH}, browserSync.reload, focus);
}
if (options.apiDocs) {
apiSourceWatch(browserSync.reload);
@ -1088,11 +1186,10 @@ function watchAndSync(options, cb) {
// returns a promise;
function askDeploy() {
prompt.start();
var schema = {
name: 'shouldDeploy',
description: 'Deploy to Firebase? (y/n): ',
description: 'Deploy to Firebase? (y/n)',
type: 'string',
pattern: /Y|N|y|n/,
message: "Respond with either a 'y' or 'n'",
@ -1114,7 +1211,7 @@ function filterOutExcludedPatterns(fileNames, excludeMatchers) {
}
function apiSourceWatch(postBuildAction) {
var srcPattern = [path.join(ANGULAR_PROJECT_PATH, 'modules/@angular/src/**/*.*')];
var srcPattern = [path.join(ANGULAR_PROJECT_PATH, 'modules/@angular/**/*.*')];
gulp.watch(srcPattern, {readDelay: 500}, function (event, done) {
gutil.log('API source changed');
gutil.log('Event type: ' + event.event); // added, changed, or deleted
@ -1141,8 +1238,9 @@ function apiExamplesWatch(postShredAction) {
});
}
function devGuideExamplesWatch(shredOptions, postShredAction) {
var includePattern = path.join(shredOptions.examplesDir, '**/*.*');
function devGuideExamplesWatch(shredOptions, postShredAction, focus) {
var watchPattern = focus ? '**/' + focus + '/**/*.*' : '**/*.*';
var includePattern = path.join(shredOptions.examplesDir, watchPattern);
// removed this version because gulp.watch has the same glob issue that dgeni has.
// var excludePattern = '!' + path.join(shredOptions.examplesDir, '**/node_modules/**/*.*');
// gulp.watch([includePattern, excludePattern], {readDelay: 500}, function (event, done) {
@ -1158,8 +1256,9 @@ function devGuideExamplesWatch(shredOptions, postShredAction) {
});
}
function devGuideSharedJadeWatch(shredOptions, postShredAction) {
var includePattern = path.join(DOCS_PATH, '**/*.jade');
function devGuideSharedJadeWatch(shredOptions, postShredAction, focus) {
var watchPattern = focus ? '**/' + focus + '.jade' : '**/*.jade';
var includePattern = path.join(DOCS_PATH, watchPattern);
// removed this version because gulp.watch has the same glob issue that dgeni has.
// var excludePattern = '!' + path.join(shredOptions.jadeDir, '**/node_modules/**/*.*');
// gulp.watch([includePattern, excludePattern], {readDelay: 500}, function (event, done) {
@ -1235,15 +1334,14 @@ function buildDartCheatsheet() {
function buildApiDocsForDart() {
const apiDir = 'api';
const vers = 'latest';
const dab = require('./tools/dart-api-builder/dab')(ANGULAR_IO_PROJECT_PATH);
const log = dab.log;
log.level = _dgeniLogLevel;
const dabInfo = dab.dartPkgConfigInfo;
dabInfo.ngIoDartApiDocPath = path.join(DOCS_PATH, 'dart', vers, apiDir);
dabInfo.ngDartDocPath = path.join(ngPathFor('dart'), 'doc', apiDir);
dabInfo.ngIoDartApiDocPath = path.join(DOCS_PATH, 'dart', vers, 'api');
dabInfo.ngDartDocPath = path.join(ngPathFor('dart'), relDartDocApiDir);
// Exclude API entries for developer/internal libraries. Also exclude entries for
// the top-level catch all "angular2" library (otherwise every entry appears twice).
dabInfo.excludeLibRegExp = new RegExp(/^(?!angular2)|\.testing|_|codegen|^angular2$/);
@ -1455,3 +1553,12 @@ function checkAngularProjectPath(_ngPath) {
if (fs.existsSync(ngPath)) return;
throw new Error('API related tasks require the angular2 repo to be at ' + ngPath);
}
function renameIfExistsSync(oldPath, newPath) {
if (fs.existsSync(oldPath)) {
gutil.log(`Rename: mv ${oldPath} ${newPath}`);
fs.renameSync(oldPath, newPath);
} else {
gutil.log(`renameIfExistsSync cannot rename, path not found: ${oldPath}`);
}
}

View File

@ -85,7 +85,7 @@
"picture": "/resources/images/bios/tobias.jpg",
"twitter": "tbosch1009",
"website": "https://plus.google.com/+TobiasBosch",
"bio": "Tobias Bosch is a software engineer at Google. He is part of the Angular core team and works on Angular 2.",
"bio": "Tobias Bosch is a software engineer at Google. He is part of the Angular core team and works on Angular.",
"type": "Google"
},
@ -184,7 +184,7 @@
"picture": "/resources/images/bios/hansl.jpg",
"twitter": "hanslatwork",
"website": "http://www.codingatwork.com/",
"bio": "Hans is a software engineer at Google on the Angular team and was previously at Slack. He works everyday to help make it easier for everyone to create beautiful, consistent web applications using Angular2, using Material Design components and the CLI tool.",
"bio": "Hans is a software engineer at Google on the Angular team and was previously at Slack. He works everyday to help make it easier for everyone to create beautiful, consistent web applications using Angular, using Material Design components and the CLI tool.",
"type": "Google"
},
@ -316,6 +316,12 @@
"bio": "Max Sills is Angular's Open Source lawyer.",
"type": "Google"
},
"shannon": {
"name": "Shannon Ayres",
"picture": "/resources/images/bios/shannon.jpg",
"bio": "Shannon is a technical editor in Developer Relations at Google. She loves movies, especially Sunset Boulevard, and her favorite TV show is The Walking Dead. Her mission: Righting wrong writing!",
"type": "Google"
},
"pawel": {
"name": "Pawel Kozlowski",
@ -354,7 +360,7 @@
"picture": "/resources/images/bios/marclaval.jpg",
"twitter": "marclaval",
"website": "https://github.com/mlaval",
"bio": "Marc is a manager at Amadeus where he leads the team in charge of developing and recommending UI frameworks for the company. He is also an open source developer and a contributor to Angular 2.",
"bio": "Marc is a manager at Amadeus where he leads the team in charge of developing and recommending UI frameworks for the company. He is also an open source developer and a contributor to Angular.",
"type": "Community"
},
@ -372,7 +378,7 @@
"picture": "/resources/images/bios/patrick-stapleton.jpg",
"twitter": "gdi2290",
"website": "https://angularclass.com",
"bio": "Also know as PatrickJS where JS stands for his middle and last names. Patrick is very active in Open-Source with over 4,300+ contributions in the last year alone on projects such as Angular2, AngularJS, FalcorJS, Docker, Bootstrap, gulp, and redis to name a few. He is also working on the development of Angular 2 server-side rendering as Universal Angular 2 and teaching Modern Web Development at AngularClass. He was previously the CTO of Keychain Logistics, a HackReactor Instructor and Alum.",
"bio": "Also know as PatrickJS where JS stands for his middle and last names. Patrick is very active in Open-Source with over 4,300+ contributions in the last year alone on projects such as Angular2, AngularJS, FalcorJS, Docker, Bootstrap, gulp, and redis to name a few. He is also working on the development of Angular server-side rendering as Universal Angular and teaching Modern Web Development at AngularClass. He was previously the CTO of Keychain Logistics, a HackReactor Instructor and Alum.",
"type": "Community"
},
@ -391,6 +397,7 @@
"bio": "Ward is an all-around developer with JavaScript, node, and .net chops. He's a frequent conference speaker and podcaster, trainer, Google Developer Expert for Angular, Microsoft MVP, and PluralSight author. He is also president of IdeaBlade, an enterprise software consulting firm and the makers of breeze.js. He would like to get more sleep and spend more time in the mountains.",
"type": "Community"
},
"johnpapa": {
"name": "John Papa",
"picture": "/resources/images/bios/john-papa.jpg",
@ -399,6 +406,7 @@
"bio": "John is a Google Developer Expert, Microsoft Regional Director and MVP, frequent author of courses for Pluralsight, a former technology Evangelist for Microsoft front end teams, and author of the popular Angular Style Guide. He can often be found speaking around the world at keynotes and sessions for many conferences. You can always find John at johnpapa.net or on twitter at @john_papa.",
"type": "Community"
},
"martinstaffa": {
"name": "Martin Staffa",
"picture": "/resources/images/bios/martinstaffa.jpg",
@ -406,6 +414,7 @@
"bio": "Martin is an English major turned web developer who loves frontend stuff. He's been part of the Angular 1 team since 2014. If you can't find him roaming the Github issue queues, he's probably out with his camera somewhere.",
"type": "Community"
},
"topherfangio": {
"name": "Topher Fangio",
"picture": "/resources/images/bios/topherfangio.jpg",
@ -414,6 +423,7 @@
"bio": "Topher loves the web and how it empowers new forms of creativity, connection and business. He is currently a core contributor on the Angular Material project and sometimes blogs about random things.",
"type": "Community"
},
"filipesilva": {
"name": "Filipe Silva",
"picture": "/resources/images/bios/filipe-silva.jpg",
@ -422,6 +432,7 @@
"bio": "Filipe is a passion-driven developer that always strives for the most elegant solution for each problem. He is currently an author for Angular.io, a core contributor for Angular-CLI and senior front end engineer at KonnectAgain. When not busy going through PRs, you can find him scouring reddit for new dinner recipes to cook or enjoying a craft beer in Dublin.",
"type": "Community"
},
"teropa": {
"name": "Tero Parviainen",
"picture": "/resources/images/bios/teropa.jpg",
@ -430,6 +441,7 @@
"bio": "Tero is an independent software developer and writer. He's been building web applications for his whole professional career, and has almost figured out how to do vertical centering in CSS.",
"type": "Community"
},
"deborah": {
"name": "Deborah Kurata",
"picture": "/resources/images/bios/deborah.jpg",
@ -438,6 +450,7 @@
"bio": "Deborah is an independent software developer and author. She is author of several Pluralsight courses including: 'Angular 2: Getting Started'",
"type": "Community"
},
"jesusrodriguez": {
"name": "Jesús Rodríguez",
"picture": "/resources/images/bios/jesus-rodriguez.jpg",
@ -446,6 +459,7 @@
"bio": "Jesus is an open source lover, a book author and editor, and AngularUI lead developer. He is currently a core contributor to the UI Bootstrap project.",
"type": "Community"
},
"torgeirhelgevold": {
"name": "Torgeir Helgevold",
"picture": "/resources/images/bios/torgeirhelgevold.jpg",
@ -454,6 +468,7 @@
"bio": "Torgeir (Tor) is a front-end architect with a passion for JavaScript development. He is also an author for angular.io and an active tech blogger.",
"type": "Community"
},
"fatimaremtullah": {
"name": "Fatima Remtullah",
"picture": "/resources/images/bios/fatima.jpg",
@ -462,6 +477,7 @@
"bio": "Fatima is a Product Designer and Front-End Developer. When she is not nerding out she is probably eating an abundance of cookies.",
"type": "Community"
},
"eric": {
"name": "Eric Jimenez",
"picture": "/resources/images/bios/eric.jpg",
@ -470,6 +486,7 @@
"bio": "Eric is a gamer, writer, and programmer.",
"type": "Community"
},
"mikeryan": {
"name": "Mike Ryan",
"picture": "/resources/images/bios/mikeryan.jpg",
@ -478,6 +495,7 @@
"bio": "Mike Ryan is a Software Engineer at Synapse Wireless, working on solving challenging problems in the internet-of-things space. He is an advocate of reactive programming and a core contributor to the ngrx project.",
"type": "Community"
},
"rex": {
"name": "Rex Ye",
"picture": "/resources/images/bios/rex.jpg",
@ -485,6 +503,7 @@
"bio": "Rex is a full-stack developer. He maintains the Angular.cn website with his old pal Ralph Wang and he plays a key role in bridging between the Chinese Angular community and the world-wide community. He loves playing with flashy new technologies and enjoys the challenge of mastering new skills. His biggest challenge to date is figuring out how to sooth a crying 4-month-old baby.",
"type": "Community"
},
"ralph": {
"name": "Ralph Wang",
"picture": "/resources/images/bios/ralph.jpg",
@ -492,6 +511,7 @@
"bio": "Ralph(Zhicheng Wang) is a senior consultant at ThoughWorks and also a GDE. He is a technology enthusiast and he is a passionate advocate of “Simplicity, Professionalism and Sharing”. In his eighteen years of R&D career, he worked as tester, R&D engineer, project manager, product manager and CTO. He is looking forward to the birth of his baby.",
"type": "Community"
},
"brandonroberts": {
"name": "Brandon Roberts",
"picture": "/resources/images/bios/brandonroberts.jpg",
@ -500,12 +520,28 @@
"bio": "Brandon is a front-end developer for a game studio developing web applications for STEM-based learning games. He is also a natural born troubleshooter who helps solve Angular issues on Github and Gitter support channels, particularly dealing with routing. He is also a member of the Angular docs team.",
"type": "Community"
},
"crisbeto": {
"name": "Kristiyan Kostadinov",
"picture": "/resources/images/bios/crisbeto.jpg",
"website": "http://crisbeto.com/",
"bio": "Kristiyan is a front-end developer, passionate open-source contributor and a core team member on Angular Material.",
"type": "Community"
},
"gkalpak": {
"name": "Georgios Kalpakas",
"picture": "/resources/images/bios/gkalpak.jpg",
"website": "https://github.com/gkalpak",
"bio": "George is a Software Engineer with a passion for chess, robotics and automating stuff. He has a strong need to know how things work (so if you already know, he'd love to have a talk with you). He has been a member of the AngularJS team since 2014. When not doing geeky stuff, he is probably trying to convince his wife and kids to apply programming principles in real life. (Or is it the other way around?)",
"type": "Community"
},
"kapunahelewong": {
"name": "Kapunahele Wong",
"picture": "/resources/images/bios/kapunahelewong.jpg",
"website": " https://github.com/kapunahelewong",
"bio": "Kapunahele is a front-end developer at Capital One. She loves just about anything to do with JavaScript, Angular and electronics. She enjoys mapping Hawaiian star names and constellations to Western ones and loves dancing native Hawaiian hula.",
"type": "Community"
}
}
}

View File

@ -2,7 +2,7 @@
"name": "angular.io",
"version": "0.0.0",
"private": true,
"description": "Angular 2 documentation",
"description": "Angular documentation",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
@ -36,20 +36,19 @@
"cross-spawn": "^4.0.0",
"del": "^2.2.0",
"dgeni": "^0.4.0",
"dgeni-packages": "^0.13.1",
"dgeni-packages": "^0.16.0",
"diff": "^2.1.3",
"fs-extra": "^0.30.0",
"globby": "^4.0.0",
"grunt-sass": "^1.2.0",
"gulp": "^3.5.6",
"gulp-env": "0.4.0",
"gulp-sass": "^2.3.2",
"gulp-less": "^3.1.0",
"gulp-sass": "^2.3.2",
"gulp-task-listing": "^1.0.1",
"gulp-tslint": "^5.0.0",
"gulp-util": "^3.0.6",
"gulp-watch": "^4.3.4",
"harp": "^0.20.3",
"harp": "0.21.0-pre.1",
"html2jade": "^0.8.4",
"indent-string": "^2.1.0",
"jasmine-core": "^2.3.4",
@ -71,7 +70,7 @@
"protractor": "^3.0.0",
"q": "^1.4.1",
"tree-kill": "^1.0.0",
"tslint": "^3.2.2",
"tslint": "^3.15.1",
"yargs": "^4.7.1"
},
"dependencies": {

View File

@ -2,7 +2,7 @@
"index": {
"hero": "home",
"title": "One framework.",
"subtitle": "Mobile and desktop."
"subtitle": "Mobile & desktop."
},
"features": {

View File

@ -8,7 +8,7 @@ else
- var styleguide = "/docs/ts/latest/styleguide.html"
.main-footer
nav.background-blue-grey-900.grid-fluid
nav.background-midnight.grid-fluid
.c3.main-footer-branding
.logo-inverse-large
@ -17,7 +17,7 @@ else
h3.text-headline RESOURCES
ul.text-body
// TODO: (ericjim) make a libraries page to showcase all angular 2 libraries
// TODO: (ericjim) make a libraries page to showcase all angular libraries
//li <a href="/libraries.html">Libraries</a>
li <a href="/about/">About</a>
li <a href="/resources/">Books & Training</a>
@ -51,7 +51,7 @@ else
ul.text-body
li <a href="https://angular.cn/">中文版</a>
footer(class="background-steel")
small.text-caption Powered by Google ©2010-2016. Code licensed under an <a href="/license" class="text-snow">MIT-style License</a>. Documentation licensed under <a class="text-snow" href="http://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.
a(aria-label="View Style Guide" href=styleguide title="Style Guide" class="styleguide-trigger text-snow")
footer(class="background-midnight")
small.text-caption Powered by Google ©2010-2016. Code licensed under an <a href="/license">MIT-style License</a>. Documentation licensed under <a href="http://creativecommons.org/licenses/by/4.0/">CC BY 4.0</a>.
a(aria-label="View Style Guide" href=styleguide title="Style Guide" class="styleguide-trigger")
span.icon-favorite

View File

@ -12,7 +12,7 @@ if title == "Angular"
else if language
title #{title} - #{language}
else
title #{title} - Angular 2
title #{title} - Angular
meta(charset="utf-8")
meta(http-equiv="X-UA-Compatible" content="IE=edge")
@ -22,14 +22,14 @@ meta(name="robots" content="all")
meta(name="referrer" content="origin")
meta(name="viewport" id="viewport" content="width=device-width, initial-scale=1")
meta(property="og:title" content="Angular 2")
meta(property="og:title" content="Angular")
meta(property="og:image" content="/resources/images/logos/standard/shield-large.png")
meta(property="og:image:type" content="image/png")
meta(property="og:image:width" content="184")
meta(property="og:image:height" content="200")
meta(property="og:description" content="#{description}")
meta(itemprop="name" content="Angular 2")
meta(itemprop="name" content="Angular")
meta(itemprop="description" content="#{description}")
meta(itemprop="image" content="https://angular.io/resources/images/logos/standard/shield-large.png")

View File

@ -1,13 +1,18 @@
header(class="background-sky")
header(class="background-sky l-relative")
.hero.background-superhero-paper.is-large
h1.text-headline.hero-logo #{title}<br>#{subtitle}
img(class="hero-logo" src='/resources/images/logos/angular2/angular.svg')
h1.text-headline #{title}<br>#{subtitle}
a(href="/docs/ts/latest/quickstart.html" class="hero-cta md-raised button button-large button-plain" md-button) Get Started
.hero-cta
a(href="/docs/ts/latest/quickstart.html" class="md-raised button button-large button-plain" md-button) Get Started
.banner.banner-floaty
.banner-ng-annoucement
div(class="banner-text" align="center")
p Join us for AngularConnect in London, UK this September!
div(class="banner-button")
a(href="http://angularconnect.com/?utm_source=angular&utm_medium=banner&utm_campaign=angular-banner" target="_blank" class="button md-button") Register now
announcement-bar
.announcement-bar-slide.clearfix
img(src="/resources/images/logos/angular2/angular-logo-banner.png")
p Angular 2.0 Final Release Now Live!
a(href="http://angularjs.blogspot.com/2016/09/angular2-final.html" target="_blank" class="button " + "md-button") Learn More
.announcement-bar-slide.clearfix
img(src="/resources/images/logos/ng-europe/ng-europe-logo.png")
p Join us for <strong>ng-europe in Paris</strong>, France this October!
a(href="https://ngeurope.org/?utm_source=angular&utm_medium=banner&utm_campaign=angular-banner" target="_blank" class="button md-button") Register now

View File

@ -13,27 +13,27 @@
if current.path[4] && current.path[3] == 'api'
- var textFormat = 'is-standard-case'
header(class="hero background-sky", style=fixHeroCss ? "height:auto" : "")
div(class="inner-header")
h1(class="hero-title text-display-1 #{textFormat}") #{headerTitle}
header.hero.background-sky
h1(class="hero-title #{textFormat}") #{headerTitle}
if useBadges
span(class="badges")
if docType
span(class="status-badge").
#{renamer(capitalize(docType))}
if stability
span(layout="row" class="status-badge")
// badge circle is filled based on stability by matching a css selector in _hero.scss
span(class="status-circle status-#{stability}")
span Stability: #{capitalize(stability)}
span(class="badge is-#{stability}").
#{capitalize(stability)}
if security
span(class="status-badge security-risk-badge").
span(class="badge is-deprecated").
Security Risk
if subtitle
h2.hero-subtitle.text-subhead #{subtitle}
//CLEAR FLOAT ELEMENTS
.clear
else if current.path[3] == 'api' && current.path[1] == 'dart'
if subtitle
h2.hero-subtitle #{subtitle}
else if docType
h2.hero-subtitle #{renamer(capitalize(docType))}
if current.path[3] == 'api' && current.path[1] == 'dart'
block breadcrumbs
else if current.path[0] == "docs"
!= partial("_version-dropdown")

View File

@ -1,8 +1,7 @@
- var language = current.path[1] || 'ts'
- if (language !== 'ts' || language !== 'js' || language !== 'dart') { language = 'ts'; }
md-toolbar(class="main-nav background-regal l-pinned-top l-layer-5",scroll-y-offset-element)
nav
nav(class="main-nav l-pinned-top l-layer-5", scroll-y-offset-element)
h1 <a href="/" md-button>Angular <sup>by Google</sup></a>
button(class="main-nav-button main-nav-mobile-trigger l-right" aria-label="View Menu" ng-click="appCtrl.toggleMainMenu($event)" md-button) Site Menu <span class="icon icon-arrow-drop-down"></span>

View File

@ -28,6 +28,7 @@ script(src="/resources/js/directives/cheatsheet.js")
script(src="/resources/js/directives/api-list.js")
script(src="/resources/js/directives/bio.js")
script(src="/resources/js/directives/bold.js")
script(src="/resources/js/directives/announcement-bar.js")
script(src="/resources/js/directives/code.js")
script(src="/resources/js/directives/copy.js")
script(src="/resources/js/directives/code-tabs.js")

View File

@ -38,6 +38,15 @@
//- Location of sample code
- var _liveLink = 'live link';
//- NgModule related
- var _AppModuleVsAppComp = 'AppModule'
- var _appModuleTsVsAppCompTs = 'app/app.module.ts'
- var _appModuleTsVsMainTs = 'app/app.module.ts'
- var _bootstrapModule = 'bootstrapModule'
- var _moduleVsComp = 'module'
- var _moduleVsRootComp = 'module'
- var _platformBrowserDynamicVsBootStrap = 'platformBrowserDynamic'
//- Other
- var _truthy = 'truthy';
- var _falsey = 'falsey';
@ -74,12 +83,12 @@ mixin makeExample(_filePath, region, _title, stylePatterns)
- var format = attributes.format || defaultFormat;
- if (attributes.format === '.') format = '';
- var avoid = !!attributes.avoid;
- var avoidClass = avoid ? 'is-anti-pattern' : '';
div(class="code-example #{avoidClass}")
if (title)
if (avoid)
.example-title.avoid AVOID: #{title}
else
.example-title #{title}
header
h4 #{title}
code-example(language="#{language}" format="#{format}")
!= styleString(frag, stylePatterns)
@ -89,14 +98,14 @@ mixin makeExample(_filePath, region, _title, stylePatterns)
//- ending is given or is just (), then the title will be suffixed with
//- either "(excerpt)", or "(#{_region})" when _region is defined.
mixin makeExcerpt(_filePath, _region, _title, stylePatterns)
- var matches = _filePath.match(/(.*)\s+\(([\w ]*)\)$/);
- var matches = _filePath.match(/(.*)\s+\(([^\)]*)\)$/);
- var parenText;
- if (matches) { _filePath = matches[1]; parenText = matches[2]; }
- var adjustments = adjustExamplePathAndTitle({filePath:_filePath, title:_title});
- var filePath = adjustments.filePath;
- var title = adjustments.title;
- var region = _region || parenText;
- var excerpt = !region || parenText === '' ? 'excerpt' : parenText || region;
- var region = _region || (_region === '' ? '' : parenText);
- var excerpt = parenText || region || 'excerpt';
- if (title) title = title + ' (' + excerpt + ')';
+makeExample(filePath, region, title, stylePatterns)(format='.')
@ -133,19 +142,20 @@ mixin makeJson( filePath, jsonConfig, title, stylePatterns)
- var json = unescapeHtml(frag);
- var jsonExtract = extractJson(json, jsonConfig);
- var avoid = !!attributes.avoid;
- var avoidClass = avoid ? 'is-anti-pattern' : '';
div(class="code-example #{avoidClass}")
if (title)
if (avoid)
.example-title.avoid #{title}
else
.example-title #{title}
header
h4 #{title}
code-example(language="#{language}" format="#{format}")
if (jsonExtract == 'ERROR')
err ERROR: Unable to extract json using config: "#{jsonConfig.toString()}"
else
!= styleString(jsonExtract, stylePatterns)
- // Open (and close) an explanation <div>. See QuickStart
if !jade2ng
//- Open (and close) an explanation <div>. See QuickStart
script.
function why(id, backTo) {
var id = "#"+id;
@ -203,6 +213,7 @@ script.
else
return CCSstyle[style] = value
}
//---------------------------------------------------------------------------------------------------------
//- Converts the given project-relative path (like 'app/main.ts')
//- to a doc folder relative path (like 'quickstart/ts/app/main.ts')
@ -213,8 +224,8 @@ script.
- // E.g. of a project relative path is 'app/main.ts'
- if (ex.title === null || ex.title === undefined) {
- // Title is not given so take it to be ex.filePath.
- // Is title like styles.1.css? Then drop the '.1' qualifier:
- var matches = ex.filePath.match(/^(.*)\.\d(\.\w+)$/);
- // Title like styles.1.css or foo_1.dart? Then drop the '.1' or '_1' qualifier:
- var matches = ex.filePath.match(/^(.*)[\._]\d(\.\w+)$/);
- ex.title = matches ? matches[1] + matches[2] : ex.filePath;
- }
- ex.filePath = getExampleName() + '/' + _docsFor + '/' + ex.filePath;
@ -289,7 +300,7 @@ script.
- } else {
- // ``` gets translated to <pre><code>.....</code></pre> and we need
- // to remove this from the fragment prefix is 11 long and suffix is 13 long
- frag = frag.substring(11, frag.length-13);
- frag = jade2ng ? frag : frag.substring(11, frag.length-13);
- // Uncomment next line for debugging.
- // frag = "FileName: " + fullFileName + " Current path: " + current.path + " PathToDocs: " + getPathToDocs() + "\n" + frag;
- return frag;

View File

@ -5,7 +5,7 @@
- var version = ''
- var page = ''
<!-- Replace _ underscores with . dots -->
//- Replace _ underscores with . dots
if current.path[2]
- var version = current.path[2].replace(/\_+/gm, ".")
@ -33,32 +33,31 @@ else if current.path[3]
else
- var page = current.path[3] + '.html'
<!-- VERSION TREE CREATOR MIXIN -->
//- VERSION TREE CREATOR MIXIN
mixin tree(directory, urlPrefix, name, latest)
ul
for val, semvar in directory
if semvar !== '.git' && semvar !== '_data'
- var libVersion = (semvar == "latest") ? latest : semvar.replace(/\_+/gm, ".")
li <a href="#{urlPrefix}/#{semvar}/#{page}" md-button>#{name} #{libVersion}</a>
<!-- BUTTON TITLE GENERATION -->
//- BUTTON TITLE GENERATION
if language == 'ts'
if version == "latest"
- var title = 'Angular 2 for TypeScript'
- var title = 'Angular for TypeScript'
else
- var title = 'Angular ' + version + ' for TypeScript'
if language == 'js'
if version == "latest"
- var title = 'Angular 2 for JavaScript'
- var title = 'Angular for JavaScript'
else
- var title = 'Angular ' + version + ' for JavaScript'
if language == 'dart'
if version == "latest"
- var title = 'Angular 2 for Dart'
- var title = 'Angular for Dart'
else
- var title = 'Angular ' + version + ' for Dart'
@ -69,7 +68,9 @@ nav.dropdown
div(class="overlay ng-hide" ng-click="appCtrl.toggleVersionMenu($event)" ng-show="appCtrl.showMenu")
<!-- DROPDOWN MENU -->
div(class="dropdown-menu" ng-class="appCtrl.showMenu ? 'is-visible' : ''")
mixin tree(public.docs.ts, "/docs/ts", "Angular 2 for TypeScript")
mixin tree(public.docs.js, "/docs/js", "Angular 2 for JavaScript")
mixin tree(public.docs.dart, "/docs/dart", "Angular 2 for Dart")
ul(class="dropdown-menu" ng-class="appCtrl.showMenu ? 'is-visible' : ''")
mixin tree(public.docs.ts, "/docs/ts", "Angular for TypeScript")
mixin tree(public.docs.js, "/docs/js", "Angular for JavaScript")
//- Disable cross-language link for API entry pages (but keep for top API search page):
if ! (current.path[3] === 'api' && public.docs[current.path[1]][current.path[2]][current.path[3]][current.path[4]])
mixin tree(public.docs.dart, "/docs/dart", "Angular for Dart")

View File

@ -3,11 +3,11 @@
p We'd love for you to contribute to our source code and to make Angular projects even better.
.l-sub-section
h3 Angular 2
h3 Angular
p Angular 2 is a next generation mobile and desktop application development platform.
p Angular is a next generation mobile and desktop application development platform.
a(href="https://github.com/angular/angular/blob/master/CONTRIBUTING.md" class="button" md-button) Contribute to Angular 2
a(href="https://github.com/angular/angular/blob/master/CONTRIBUTING.md" class="button" md-button) Contribute to Angular
.l-sub-section
h3 Angular for JavaScript or Dart

View File

@ -13,7 +13,9 @@
"license": "ISC",
"devDependencies": {
"protractor": "^3.3.0",
"typings": "^1.0.4"
"typings": "^1.0.4",
"ts-node": "^1.3.0",
"typescript": "^2.0.2"
},
"repository": {}
}

View File

@ -26,7 +26,7 @@ exports.config = {
// Framework to use. Jasmine is recommended.
framework: 'jasmine',
// For angular2 tests
// For angular tests
useAllAngular2AppRoots: true,
// Base URL for application server

View File

@ -4,7 +4,7 @@
* The tests here basically just checking that the end styles
* of each animation are in effect.
*
* Relies on the Angular 2 testability only becoming stable once
* Relies on the Angular testability only becoming stable once
* animation(s) have finished.
*
* Ideally we'd use https://developer.mozilla.org/en-US/docs/Web/API/Document/getAnimations
@ -289,6 +289,19 @@ describe('Animation Tests', () => {
});
});
describe('callbacks', () => {
it('fires a callback on start and done', () => {
addActiveHero();
browser.manage().logs().get('browser').then((logs) => {
const animationMessages = logs.filter((log) => {
return log.message.indexOf('Animation') !== -1 ? true : false;
});
expect(animationMessages.length).toBeGreaterThan(0);
});
});
});
function addActiveHero(sleep?: number) {
sleep = sleep || 500;
element(by.buttonText('Add active hero')).click();

View File

@ -17,7 +17,7 @@ import { Heroes } from './hero.service';
template: `
<ul>
<li *ngFor="let hero of heroes"
@shrinkOut="'in'">
[@shrinkOut]="'in'">
{{hero.name}}
</li>
</ul>

View File

@ -27,7 +27,7 @@ import { Heroes } from './hero.service';
template: `
<ul>
<li *ngFor="let hero of heroes"
@heroState="hero.state"
[@heroState]="hero.state"
(click)="hero.toggleState()">
{{hero.name}}
</li>

View File

@ -20,7 +20,7 @@ import { Heroes } from './hero.service';
template: `
<ul>
<li *ngFor="let hero of heroes"
@heroState="hero.state"
[@heroState]="hero.state"
(click)="hero.toggleState()">
{{hero.name}}
</li>

View File

@ -18,7 +18,7 @@ import { Heroes } from './hero.service';
<ul>
<li *ngFor="let hero of heroes"
(click)="hero.toggleState()"
@heroState="hero.state">
[@heroState]="hero.state">
{{hero.name}}
</li>
</ul>

View File

@ -17,7 +17,7 @@ import { Heroes } from './hero.service';
template: `
<ul>
<li *ngFor="let hero of heroes"
@flyInOut="'in'">
[@flyInOut]="'in'">
{{hero.name}}
</li>
</ul>

View File

@ -17,7 +17,7 @@ import { Heroes } from './hero.service';
template: `
<ul>
<li *ngFor="let hero of heroes"
@flyInOut="'in'">
[@flyInOut]="'in'">
{{hero.name}}
</li>
</ul>

View File

@ -19,7 +19,7 @@ import { Heroes } from './hero.service';
template: `
<ul>
<li *ngFor="let hero of heroes"
@heroState="hero.state"
[@heroState]="hero.state"
(click)="hero.toggleState()">
{{hero.name}}
</li>

View File

@ -6,7 +6,8 @@ import {
style,
animate,
transition,
keyframes
keyframes,
AnimationTransitionEvent
} from '@angular/core';
import { Heroes } from './hero.service';
@ -14,14 +15,18 @@ import { Heroes } from './hero.service';
@Component({
moduleId: module.id,
selector: 'hero-list-multistep',
// #docregion template
template: `
<ul>
<li *ngFor="let hero of heroes"
@flyInOut="'in'">
(@flyInOut.start)="animationStarted($event)"
(@flyInOut.done)="animationDone($event)"
[@flyInOut]="'in'">
{{hero.name}}
</li>
</ul>
`,
// #enddocregion template
styleUrls: ['hero-list.component.css'],
/* The element here always has the state "in" when it
* is present. We animate two transitions: From void
@ -54,4 +59,12 @@ import { Heroes } from './hero.service';
})
export class HeroListMultistepComponent {
@Input() heroes: Heroes;
animationStarted(event: AnimationTransitionEvent) {
console.warn('Animation started: ', event);
}
animationDone(event: AnimationTransitionEvent) {
console.warn('Animation done: ', event);
}
}

View File

@ -16,7 +16,7 @@ import { Heroes } from './hero.service';
template: `
<ul>
<li *ngFor="let hero of heroes"
@flyInOut="'in'"
[@flyInOut]="'in'"
(click)="hero.toggleState()">
{{hero.name}}
</li>

View File

@ -20,7 +20,7 @@ import { Heroes } from './hero.service';
template: `
<ul>
<li *ngFor="let hero of heroes"
@heroState="hero.state"
[@heroState]="hero.state"
(click)="hero.toggleState()">
{{hero.name}}
</li>

View File

@ -7,7 +7,7 @@
<link rel="stylesheet" href="styles.css">
<!-- Polyfill for Web Animations -->
<script src="https://npmcdn.com/web-animations-js@2.2.1"></script>
<script src="https://unpkg.com/web-animations-js@2.2.1"></script>
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>

View File

@ -1,5 +1,5 @@
{
"description": "Angular 2 Animations",
"description": "Angular Animations",
"files":[
"!**/*.d.ts",
"!**/*.js"

View File

@ -5,7 +5,7 @@ version: 0.0.1
environment:
sdk: '>=1.13.0 <2.0.0'
dependencies:
angular2: 2.0.0-beta.18
angular2: 2.0.0-beta.21
browser: ^0.10.0
dart_to_js_script_rewriter: ^1.0.1
transformers:

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Architecture of Angular 2</title>
<title>Architecture of Angular</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">

View File

@ -10,7 +10,7 @@ class Hero {
describe('Architecture', () => {
const expectedTitle = 'Architecture of Angular 2';
const expectedTitle = 'Architecture of Angular';
const expectedH2 = ['Hero List', 'Sales Tax Calculator'];
beforeAll(() => browser.get(''));

View File

@ -13,7 +13,7 @@ const HEROES = [
export class BackendService {
constructor(private logger: Logger) {}
getAll(type: Type): PromiseLike<any[]> {
getAll(type: Type<any>): PromiseLike<any[]> {
if (type === Hero) {
// TODO get from the database
return Promise.resolve<Hero[]>(HEROES);

View File

@ -13,7 +13,7 @@ import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: 'Welcome to Angular 2'
template: 'Welcome to Angular'
})
export class AppComponent {
constructor(logger: Logger) {

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Architecture of Angular 2</title>
<title>Architecture of Angular</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">

View File

@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Architecture of Angular 2</title>
<title>Architecture of Angular</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">

View File

@ -1,5 +1,5 @@
{
"description": "Intro to Angular2",
"description": "Intro to Angular",
"files":[
"!**/*.d.ts",
"!**/*.js",

View File

@ -5,7 +5,7 @@ version: 0.0.1
environment:
sdk: '>=1.13.0 <2.0.0'
dependencies:
angular2: 2.0.0-beta.18
angular2: 2.0.0-beta.21
browser: ^0.10.0
dart_to_js_script_rewriter: ^1.0.1
transformers:

View File

@ -1,10 +1,10 @@
/* tslint:disable:no-unused-variable */
// #docregion
import { Directive, ElementRef, Input } from '@angular/core';
import { Directive, ElementRef, Input, Renderer } from '@angular/core';
@Directive({ selector: '[myHighlight]' })
export class HighlightDirective {
constructor(el: ElementRef) {
el.nativeElement.style.backgroundColor = 'yellow';
constructor(el: ElementRef, renderer: Renderer) {
renderer.setElementStyle(el.nativeElement, 'backgroundColor', 'yellow');
}
}

View File

@ -1,6 +1,6 @@
/* tslint:disable:no-unused-variable */
// #docregion
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
import { Directive, ElementRef, HostListener, Input, Renderer } from '@angular/core';
@Directive({
selector: '[myHighlight]'
@ -8,9 +8,7 @@ import { Directive, ElementRef, HostListener, Input } from '@angular/core';
export class HighlightDirective {
// #docregion ctor
private el: HTMLElement;
constructor(el: ElementRef) { this.el = el.nativeElement; }
constructor(private el: ElementRef, private renderer: Renderer) { }
// #enddocregion ctor
// #docregion mouse-methods, host
@ -28,7 +26,7 @@ export class HighlightDirective {
// #enddocregion host
private highlight(color: string) {
this.el.style.backgroundColor = color;
this.renderer.setElementStyle(this.el.nativeElement, 'backgroundColor', color);
}
// #enddocregion mouse-methods

View File

@ -1,6 +1,6 @@
// #docplaster
// #docregion full
import { Directive, ElementRef, HostListener, Input } from '@angular/core';
import { Directive, ElementRef, HostListener, Input, Renderer } from '@angular/core';
@Directive({
selector: '[myHighlight]'
@ -8,9 +8,8 @@ import { Directive, ElementRef, HostListener, Input } from '@angular/core';
// #docregion class
export class HighlightDirective {
private _defaultColor = 'red';
private el: HTMLElement;
constructor(el: ElementRef) { this.el = el.nativeElement; }
constructor(private el: ElementRef, private renderer: Renderer) { }
// #enddocregion class
// #docregion defaultColor
@ -34,7 +33,7 @@ export class HighlightDirective {
}
private highlight(color: string) {
this.el.style.backgroundColor = color;
this.renderer.setElementStyle(this.el.nativeElement, 'backgroundColor', color);
}
}
// #enddocregion class

View File

@ -2,17 +2,16 @@
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { RouterModule } from '@angular/router';
import { AppComponent } from './app.component';
import { MovieListComponent } from './movie-list.component';
import { routes } from './app.routes';
import { routing } from './app.routing';
@NgModule({
imports: [
BrowserModule,
FormsModule,
RouterModule.forRoot(routes, {})
routing
],
declarations: [
AppComponent,

View File

@ -1,9 +0,0 @@
// #docregion
import { RouterConfig } from '@angular/router';
import { MovieListComponent } from './movie-list.component';
export const routes: RouterConfig = [
{ path: '', redirectTo: '/movies', pathMatch: 'full' },
{ path: 'movies', component: MovieListComponent }
];

View File

@ -0,0 +1,12 @@
// #docregion
import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { MovieListComponent } from './movie-list.component';
const routes: Routes = [
{ path: '', redirectTo: '/movies', pathMatch: 'full' },
{ path: 'movies', component: MovieListComponent }
];
export const routing: ModuleWithProviders = RouterModule.forRoot(routes);

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,25 @@
/// <reference path='../_protractor/e2e.d.ts' />
'use strict';
/* tslint:disable:quotemark */
describe('AOT Compilation', function () {
beforeAll(function () {
browser.get('');
});
it('should load page and click button', function (done) {
let headingSelector = element.all(by.css('h1')).get(0);
expect(headingSelector.getText()).toEqual('My First Angular App');
expect(element.all(by.xpath('//div[text()="Magneta"]')).get(0).isPresent()).toBe(true);
expect(element.all(by.xpath('//div[text()="Bombasto"]')).get(0).isPresent()).toBe(true);
expect(element.all(by.xpath('//div[text()="Magma"]')).get(0).isPresent()).toBe(true);
expect(element.all(by.xpath('//div[text()="Tornado"]')).get(0).isPresent()).toBe(true);
let toggleButton = element.all(by.css('button')).get(0);
toggleButton.click().then(function() {
expect(headingSelector.isPresent()).toBe(false);
done();
});
});
});

View File

@ -0,0 +1,5 @@
**/*.ngfactory.ts
**/*.metadata.json
dist
!app/tsconfig.json
!rollup.js

View File

@ -0,0 +1,7 @@
<!-- #docregion -->
<button (click)="toggleHeading()">Toggle Heading</button>
<h1 *ngIf="showHeading">My First Angular App</h1>
<h3>List of Heroes</h3>
<div *ngFor="let hero of heroes">{{hero}}</div>

View File

@ -0,0 +1,17 @@
// #docregion
// #docregion
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
templateUrl: 'app.component.html'
})
export class AppComponent {
showHeading = true;
heroes = ['Magneta', 'Bombasto', 'Magma', 'Tornado'];
toggleHeading() {
this.showHeading = !this.showHeading;
}
}

View File

@ -0,0 +1,12 @@
// #docregion
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@NgModule({
imports: [ BrowserModule ],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }

View File

@ -0,0 +1,6 @@
// #docregion
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -0,0 +1,6 @@
// #docregion
import { platformBrowser } from '@angular/platform-browser';
import { AppModuleNgFactory } from '../aot/app/app.module.ngfactory';
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory);

View File

@ -0,0 +1,4 @@
{
"build": "build:aot",
"run": "http-server:e2e"
}

View File

@ -0,0 +1,23 @@
<!-- #docregion -->
<!DOCTYPE html>
<html>
<head>
<title>Ahead of time compilation</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<script src="node_modules/core-js/client/shim.min.js"></script>
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
</head>
<!-- #docregion bundle -->
<body>
<my-app>Loading...</my-app>
</body>
<script src="dist/build.js"></script>
<!-- #enddocregion bundle -->
</html>

View File

@ -0,0 +1,25 @@
// #docregion
import rollup from 'rollup'
import nodeResolve from 'rollup-plugin-node-resolve'
import commonjs from 'rollup-plugin-commonjs';
import uglify from 'rollup-plugin-uglify'
// #docregion config
export default {
entry: 'app/main.js',
dest: 'dist/build.js', // output a single application bundle
sourceMap: false,
format: 'iife',
plugins: [
nodeResolve({jsnext: true, module: true}),
// #docregion commonjs
commonjs({
include: 'node_modules/rxjs/**',
}),
// #enddocregion commonjs
// #docregion uglify
uglify()
// #enddocregion uglify
]
}
// #enddocregion config

View File

@ -1,7 +1,7 @@
{
"compilerOptions": {
"target": "es5",
"module": "system",
"module": "es2015",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
@ -9,5 +9,16 @@
"removeComments": false,
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
},
"files": [
"app/app.module.ts",
"app/main.ts",
"./typings/index.d.ts"
],
"angularCompilerOptions": {
"genDir": "aot",
"skipMetadataEmit" : true
}
}

View File

@ -1,4 +1,4 @@
import { NgModule } from '@angular/core';
import { NgModule, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
@ -30,12 +30,17 @@ let directives: any[] = [
VoteTakerComponent
];
let schemas: any[] = [];
// Include Countdown examples
// unless in e2e tests which they break.
if (!/e2e/.test(location.search)) {
console.log('adding countdown timer examples');
directives.push(CountdownLocalVarParentComponent);
directives.push(CountdownViewChildParentComponent);
} else {
// In e2e test use CUSTOM_ELEMENTS_SCHEMA to supress unknown element errors
schemas.push(CUSTOM_ELEMENTS_SCHEMA);
}
@NgModule({
@ -43,6 +48,7 @@ if (!/e2e/.test(location.search)) {
BrowserModule
],
declarations: directives,
bootstrap: [ AppComponent ]
bootstrap: [ AppComponent ],
schemas: schemas
})
export class AppModule { }

View File

@ -1,5 +1,5 @@
import { browserDynamicPlatform } from '@angular/platform-browser-dynamic';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
browserDynamicPlatform().bootstrapModule(AppModule);
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -1,15 +1,12 @@
// #docregion
import { Component } from '@angular/core';
import { SomeAbsoluteComponent, SomeRelativeComponent } from './some.component';
@Component({
selector: 'my-app',
template:
`<h1>Absolute & <i>Component-Relative</i> Paths</h1>
<absolute-path></absolute-path>
<relative-path></relative-path>
`,
directives: [SomeAbsoluteComponent, SomeRelativeComponent]
`
})
export class AppComponent {}

View File

@ -2,13 +2,16 @@ import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { SomeAbsoluteComponent, SomeRelativeComponent } from './some.component';
@NgModule({
imports: [
BrowserModule
],
declarations: [
AppComponent
AppComponent,
SomeAbsoluteComponent,
SomeRelativeComponent
],
bootstrap: [ AppComponent ]
})

View File

@ -1,15 +1,16 @@
// #docregion
import { BrowserModule } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';
import { XHRBackend } from '@angular/http';
// import { appRouterProviders } from './app.routes';
import { HttpModule } from '@angular/http';
/* import { routing } from './app.routing';*/
import { LocationStrategy,
HashLocationStrategy } from '@angular/common';
import { NgModule } from '@angular/core';
import { HeroData } from './hero-data';
import { InMemoryBackendService,
SEED_DATA } from 'angular2-in-memory-web-api';
import { InMemoryWebApiModule } from 'angular2-in-memory-web-api';
import { AppComponent } from './app.component';
import { HeroBioComponent } from './hero-bio.component';
@ -31,44 +32,43 @@ import { ParentFinderComponent,
BethComponent,
BobComponent } from './parent-finder.component';
const DIRECTIVES = [
const declarations = [
AppComponent,
HeroBiosComponent, HeroBiosAndContactsComponent, HeroBioComponent,
HeroesBaseComponent, SortedHeroesComponent,
HeroOfTheMonthComponent, HeroContactComponent,
HighlightDirective,
ParentFinderComponent,
AppComponent
];
const B_DIRECTIVES = [ BarryComponent, BethComponent, BobComponent ];
const a_components = [AliceComponent, AlexComponent ];
// #docregion C_DIRECTIVES
const C_DIRECTIVES = [
const b_components = [ BarryComponent, BethComponent, BobComponent ];
const c_components = [
CarolComponent, ChrisComponent, CraigComponent,
CathyComponent
];
// #enddocregion C_DIRECTIVES
// #docregion bootstrap
@NgModule({
imports: [ BrowserModule, FormsModule ],
declarations: [ ...DIRECTIVES,
...B_DIRECTIVES,
...C_DIRECTIVES,
AliceComponent,
AlexComponent ],
imports: [
BrowserModule,
FormsModule,
HttpModule,
InMemoryWebApiModule.forRoot(HeroData)
// routing TODO: add routes
],
declarations: [
declarations,
a_components,
b_components,
c_components,
],
bootstrap: [ AppComponent ],
// #docregion providers
providers: [
// appRouterProviders, TODO: add routes
{ provide: LocationStrategy, useClass: HashLocationStrategy },
{ provide: XHRBackend, useClass: InMemoryBackendService }, // in-mem server
{ provide: SEED_DATA, useClass: HeroData } // in-mem server data
{ provide: LocationStrategy, useClass: HashLocationStrategy }
]
// #enddocregion providers
})
export class AppModule {
constructor() {
}
}
// #enddocregion bootstraps
export class AppModule { }

View File

@ -1,7 +0,0 @@
import { provideRouter, RouterConfig } from '@angular/router';
const routes: RouterConfig = [];
export const appRouterProviders = [
provideRouter(routes)
];

View File

@ -0,0 +1,10 @@
import { ModuleWithProviders } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
const routes: Routes = [];
export const routing: ModuleWithProviders = RouterModule.forRoot(routes);
export const appRoutingProviders: any[] = [
];

View File

@ -2,7 +2,7 @@
/* tslint:disable:*/
// #docplaster
// #docregion
import { Component, forwardRef, Optional, provide, SkipSelf } from '@angular/core';
import { Component, forwardRef, Optional, SkipSelf } from '@angular/core';
// A component base class (see AlexComponent)
export abstract class Base { name = 'Count Basie'; }

View File

@ -0,0 +1,180 @@
/// <reference path="../_protractor/e2e.d.ts" />
'use strict'; // necessary for node!
// THESE TESTS ARE INCOMPLETE
describeIf(browser.appIsTs || browser.appIsJs, 'Form Validation Tests', function () {
beforeAll(function () {
browser.get('');
});
describe('Hero Form 1', () => {
beforeAll(() => {
getPage('hero-form-template1');
});
tests();
});
describe('Hero Form 2', () => {
beforeAll(() => {
getPage('hero-form-template2');
});
tests();
bobTests();
});
describe('Hero Form 3 (Reactive)', () => {
beforeAll(() => {
getPage('hero-form-reactive3');
makeNameTooLong();
});
tests();
bobTests();
});
});
//////////
const testName = 'Test Name';
let page: {
section: protractor.ElementFinder,
form: protractor.ElementFinder,
title: protractor.ElementFinder,
nameInput: protractor.ElementFinder,
alterEgoInput: protractor.ElementFinder,
powerSelect: protractor.ElementFinder,
errorMessages: protractor.ElementArrayFinder,
heroFormButtons: protractor.ElementArrayFinder,
heroSubmitted: protractor.ElementFinder
};
function getPage(sectionTag: string) {
let section = element(by.css(sectionTag));
let buttons = section.all(by.css('button'));
page = {
section: section,
form: section.element(by.css('form')),
title: section.element(by.css('h1')),
nameInput: section.element(by.css('#name')),
alterEgoInput: section.element(by.css('#alterEgo')),
powerSelect: section.element(by.css('#power')),
errorMessages: section.all(by.css('div.alert')),
heroFormButtons: buttons,
heroSubmitted: section.element(by.css('hero-submitted > div'))
};
}
function tests() {
it('should display correct title', function () {
expect(page.title.getText()).toContain('Hero Form');
});
it('should not display submitted message before submit', function () {
expect(page.heroSubmitted.isElementPresent(by.css('h2'))).toBe(false);
});
it('should have form buttons', function () {
expect(page.heroFormButtons.count()).toEqual(2);
});
it('should have error at start', function () {
expectFormIsInvalid();
});
// it('showForm', function () {
// page.form.getInnerHtml().then(html => console.log(html));
// });
it('should have disabled submit button', function () {
expect(page.heroFormButtons.get(0).isEnabled()).toBe(false);
});
it('resetting name to valid name should clear errors', function () {
const ele = page.nameInput;
expect(ele.isPresent()).toBe(true, 'nameInput should exist');
ele.clear();
ele.sendKeys(testName);
expectFormIsValid();
});
it('should produce "required" error after clearing name', function () {
page.nameInput.clear();
// page.alterEgoInput.click(); // to blur ... didn't work
page.nameInput.sendKeys('x', protractor.Key.BACK_SPACE); // ugh!
expect(page.form.getAttribute('class')).toMatch('ng-invalid');
expect(page.errorMessages.get(0).getText()).toContain('required');
});
it('should produce "at least 4 characters" error when name="x"', function () {
page.nameInput.clear();
page.nameInput.sendKeys('x'); // too short
expectFormIsInvalid();
expect(page.errorMessages.get(0).getText()).toContain('at least 4 characters');
});
it('resetting name to valid name again should clear errors', function () {
page.nameInput.sendKeys(testName);
expectFormIsValid();
});
it('should have enabled submit button', function () {
const submitBtn = page.heroFormButtons.get(0);
expect(submitBtn.isEnabled()).toBe(true);
});
it('should hide form after submit', function () {
page.heroFormButtons.get(0).click();
expect(page.title.isDisplayed()).toBe(false);
});
it('submitted form should be displayed', function () {
expect(page.heroSubmitted.isElementPresent(by.css('h2'))).toBe(true);
});
it('submitted form should have new hero name', function () {
expect(page.heroSubmitted.getText()).toContain(testName);
});
it('clicking edit button should reveal form again', function () {
const editBtn = page.heroSubmitted.element(by.css('button'));
editBtn.click();
expect(page.heroSubmitted.isElementPresent(by.css('h2')))
.toBe(false, 'submitted hidden again');
expect(page.title.isDisplayed()).toBe(true, 'can see form title');
});
}
function expectFormIsValid() {
expect(page.form.getAttribute('class')).toMatch('ng-valid');
}
function expectFormIsInvalid() {
expect(page.form.getAttribute('class')).toMatch('ng-invalid');
}
function bobTests() {
const emsg = 'Someone named "Bob" cannot be a hero.';
it('should produce "no bob" error after setting name to "Bobby"', function () {
page.nameInput.clear();
page.nameInput.sendKeys('Bobby');
expectFormIsInvalid();
expect(page.errorMessages.get(0).getText()).toBe(emsg);
});
it('should be ok again with valid name', function () {
page.nameInput.clear();
page.nameInput.sendKeys(testName);
expectFormIsValid();
});
}
function makeNameTooLong() {
// make the first name invalid
page.nameInput.sendKeys('ThisHeroNameHasWayWayTooManyLetters');
}

View File

@ -0,0 +1,12 @@
// #docregion
import { Component } from '@angular/core';
@Component({
selector: 'my-app',
template: `<hero-form-template1></hero-form-template1>
<hr>
<hero-form-template2></hero-form-template2>
<hr>
<hero-form-reactive3></hero-form-reactive3>`
})
export class AppComponent { }

View File

@ -0,0 +1,18 @@
// #docregion
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { HeroFormTemplateModule } from './template/hero-form-template.module';
import { HeroFormReactiveModule } from './reactive/hero-form-reactive.module';
@NgModule({
imports: [
BrowserModule,
HeroFormTemplateModule,
HeroFormReactiveModule
],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }

View File

@ -0,0 +1,6 @@
// #docregion
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -0,0 +1,47 @@
<!-- #docregion -->
<div class="container">
<div [hidden]="submitted">
<h1>Hero Form 3 (Reactive)</h1>
<!-- #docregion form-tag-->
<form [formGroup]="heroForm" *ngIf="active" (ngSubmit)="onSubmit()">
<!-- #enddocregion form-tag-->
<div class="form-group">
<!-- #docregion name-with-error-msg -->
<label for="name">Name</label>
<input type="text" id="name" class="form-control"
formControlName="name" required >
<div *ngIf="formErrors.name" class="alert alert-danger">
{{ formErrors.name }}
</div>
<!-- #enddocregion name-with-error-msg -->
</div>
<div class="form-group">
<label for="alterEgo">Alter Ego</label>
<input type="text" id="alterEgo" class="form-control"
formControlName="alterEgo" >
</div>
<div class="form-group">
<label for="power">Hero Power</label>
<select id="power" class="form-control"
formControlName="power" required >
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
</select>
<div *ngIf="formErrors.power" class="alert alert-danger">
{{ formErrors.power }}
</div>
</div>
<button type="submit" class="btn btn-default"
[disabled]="!heroForm.valid">Submit</button>
<button type="button" class="btn btn-default"
(click)="addHero()">New Hero</button>
</form>
</div>
<hero-submitted [hero]="hero" [(submitted)]="submitted"></hero-submitted>
</div>

View File

@ -0,0 +1,117 @@
/* tslint:disable: member-ordering forin */
// #docplaster
// #docregion
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { Hero } from '../shared/hero';
import { forbiddenNameValidator } from '../shared/forbidden-name.directive';
@Component({
moduleId: module.id,
selector: 'hero-form-reactive3',
templateUrl: 'hero-form-reactive.component.html'
})
export class HeroFormReactiveComponent implements OnInit {
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
hero = new Hero(18, 'Dr. WhatIsHisName', this.powers[0], 'Dr. What');
submitted = false;
// #docregion on-submit
onSubmit() {
this.submitted = true;
this.hero = this.heroForm.value;
}
// #enddocregion on-submit
// #enddocregion
// Reset the form with a new hero AND restore 'pristine' class state
// by toggling 'active' flag which causes the form
// to be removed/re-added in a tick via NgIf
// TODO: Workaround until NgForm has a reset method (#6822)
active = true;
// #docregion
// #docregion add-hero
addHero() {
this.hero = new Hero(42, '', '');
this.buildForm();
// #enddocregion add-hero
// #enddocregion class
this.active = false;
setTimeout(() => this.active = true, 0);
// #docregion
// #docregion add-hero
}
// #enddocregion add-hero
// #docregion form-builder
heroForm: FormGroup;
constructor(private fb: FormBuilder) { }
ngOnInit(): void {
this.buildForm();
}
buildForm(): void {
this.heroForm = this.fb.group({
// #docregion name-validators
'name': [this.hero.name, [
Validators.required,
Validators.minLength(4),
Validators.maxLength(24),
forbiddenNameValidator(/bob/i)
]
],
// #enddocregion name-validators
'alterEgo': [this.hero.alterEgo],
'power': [this.hero.power, Validators.required]
});
this.heroForm.valueChanges
.subscribe(data => this.onValueChanged(data));
this.onValueChanged(); // (re)set validation messages now
}
// #enddocregion form-builder
onValueChanged(data?: any) {
if (!this.heroForm) { return; }
const form = this.heroForm;
for (const field in this.formErrors) {
// clear previous error message (if any)
this.formErrors[field] = '';
const control = form.get(field);
if (control && control.dirty && !control.valid) {
const messages = this.validationMessages[field];
for (const key in control.errors) {
this.formErrors[field] += messages[key] + ' ';
}
}
}
}
formErrors = {
'name': '',
'power': ''
};
validationMessages = {
'name': {
'required': 'Name is required.',
'minlength': 'Name must be at least 4 characters long.',
'maxlength': 'Name cannot be more than 24 characters long.',
'forbiddenName': 'Someone named "Bob" cannot be a hero.'
},
'power': {
'required': 'Power is required.'
}
};
}
// #enddocregion

View File

@ -0,0 +1,13 @@
// #docregion
import { NgModule } from '@angular/core';
import { ReactiveFormsModule } from '@angular/forms';
import { SharedModule } from '../shared/shared.module';
import { HeroFormReactiveComponent } from './hero-form-reactive.component';
@NgModule({
imports: [ SharedModule, ReactiveFormsModule ],
declarations: [ HeroFormReactiveComponent ],
exports: [ HeroFormReactiveComponent ]
})
export class HeroFormReactiveModule { }

View File

@ -0,0 +1,43 @@
// #docregion
import { Directive, Input, OnChanges, SimpleChanges } from '@angular/core';
import { AbstractControl, NG_VALIDATORS, Validator, ValidatorFn, Validators } from '@angular/forms';
// #docregion custom-validator
/** A hero's name can't match the given regular expression */
export function forbiddenNameValidator(nameRe: RegExp): ValidatorFn {
return (control: AbstractControl): {[key: string]: any} => {
const name = control.value;
const no = nameRe.test(name);
return no ? {'forbiddenName': {name}} : null;
};
}
// #enddocregion custom-validator
// #docregion directive
@Directive({
selector: '[forbiddenName]',
// #docregion directive-providers
providers: [{provide: NG_VALIDATORS, useExisting: ForbiddenValidatorDirective, multi: true}]
// #enddocregion directive-providers
})
export class ForbiddenValidatorDirective implements Validator, OnChanges {
@Input() forbiddenName: string;
private valFn = Validators.nullValidator;
ngOnChanges(changes: SimpleChanges): void {
const change = changes['forbiddenName'];
if (change) {
const val: string | RegExp = change.currentValue;
const re = val instanceof RegExp ? val : new RegExp(val, 'i');
this.valFn = forbiddenNameValidator(re);
} else {
this.valFn = Validators.nullValidator;
}
}
validate(control: AbstractControl): {[key: string]: any} {
return this.valFn(control);
}
}
// #docregion directive

View File

@ -1,11 +1,9 @@
// #docregion
export class Hero {
constructor(
public id: number,
public name: string,
public power: string,
public alterEgo?: string
) { }
}

View File

@ -0,0 +1,14 @@
// #docregion
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ForbiddenValidatorDirective } from './forbidden-name.directive';
import { SubmittedComponent } from './submitted.component';
@NgModule({
imports: [ CommonModule],
declarations: [ ForbiddenValidatorDirective, SubmittedComponent ],
exports: [ ForbiddenValidatorDirective, SubmittedComponent,
CommonModule ]
})
export class SharedModule { }

View File

@ -0,0 +1,32 @@
// #docregion
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { Hero } from './hero';
@Component({
selector: 'hero-submitted',
template: `
<div *ngIf="submitted">
<h2>You submitted the following:</h2>
<div class="row">
<div class="col-xs-3">Name</div>
<div class="col-xs-9 pull-left">{{ hero.name }}</div>
</div>
<div class="row">
<div class="col-xs-3">Alter Ego</div>
<div class="col-xs-9 pull-left">{{ hero.alterEgo }}</div>
</div>
<div class="row">
<div class="col-xs-3">Power</div>
<div class="col-xs-9 pull-left">{{ hero.power }}</div>
</div>
<br>
<button class="btn btn-default" (click)="onClick()">Edit</button>
</div>`
})
export class SubmittedComponent {
@Input() hero: Hero;
@Input() submitted = false;
@Output() submittedChange = new EventEmitter<boolean>();
onClick() { this.submittedChange.emit(false); }
}

View File

@ -0,0 +1,14 @@
// #docregion
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { SharedModule } from '../shared/shared.module';
import { HeroFormTemplate1Component } from './hero-form-template1.component';
import { HeroFormTemplate2Component } from './hero-form-template2.component';
@NgModule({
imports: [ SharedModule, FormsModule ],
declarations: [ HeroFormTemplate1Component, HeroFormTemplate2Component ],
exports: [ HeroFormTemplate1Component, HeroFormTemplate2Component ]
})
export class HeroFormTemplateModule { }

View File

@ -0,0 +1,61 @@
<!-- #docregion -->
<div class="container">
<div [hidden]="submitted">
<h1>Hero Form 1 (Template)</h1>
<!-- #docregion form-tag-->
<form #heroForm="ngForm" *ngIf="active" (ngSubmit)="onSubmit()">
<!-- #enddocregion form-tag-->
<div class="form-group">
<!-- #docregion name-with-error-msg -->
<label for="name">Name</label>
<input type="text" id="name" class="form-control"
required minlength="4" maxlength="24"
name="name" [(ngModel)]="hero.name"
#name="ngModel" >
<div *ngIf="name.errors && (name.dirty || name.touched)"
class="alert alert-danger">
<div [hidden]="!name.errors.required">
Name is required
</div>
<div [hidden]="!name.errors.minlength">
Name must be at least 4 characters long.
</div>
<div [hidden]="!name.errors.maxlength">
Name cannot be more than 24 characters long.
</div>
</div>
<!-- #enddocregion name-with-error-msg -->
</div>
<div class="form-group">
<label for="alterEgo">Alter Ego</label>
<input type="text" id="alterEgo" class="form-control"
name="alterEgo"
[(ngModel)]="hero.alterEgo" >
</div>
<div class="form-group">
<label for="power">Hero Power</label>
<select id="power" class="form-control"
name="power"
[(ngModel)]="hero.power" required
#power="ngModel" >
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
</select>
<div *ngIf="power.errors && power.touched" class="alert alert-danger">
<div [hidden]="!power.errors.required">Power is required</div>
</div>
</div>
<button type="submit" class="btn btn-default"
[disabled]="!heroForm.form.valid">Submit</button>
<button type="button" class="btn btn-default"
(click)="addHero()">New Hero</button>
</form>
</div>
<hero-submitted [hero]="hero" [(submitted)]="submitted"></hero-submitted>
</div>

View File

@ -0,0 +1,48 @@
/* tslint:disable: member-ordering */
// #docplaster
// #docregion
import { Component } from '@angular/core';
import { Hero } from '../shared/hero';
@Component({
moduleId: module.id,
selector: 'hero-form-template1',
templateUrl: 'hero-form-template1.component.html'
})
// #docregion class
export class HeroFormTemplate1Component {
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
hero = new Hero(18, 'Dr. WhatIsHisWayTooLongName', this.powers[0], 'Dr. What');
submitted = false;
onSubmit() {
this.submitted = true;
}
// #enddocregion class
// #enddocregion
// Reset the form with a new hero AND restore 'pristine' class state
// by toggling 'active' flag which causes the form
// to be removed/re-added in a tick via NgIf
// TODO: Workaround until NgForm has a reset method (#6822)
active = true;
// #docregion
// #docregion class
addHero() {
this.hero = new Hero(42, '', '');
// #enddocregion class
// #enddocregion
this.active = false;
setTimeout(() => this.active = true, 0);
// #docregion
// #docregion class
}
}
// #enddocregion class
// #enddocregion

View File

@ -0,0 +1,52 @@
<!-- #docregion -->
<div class="container">
<div [hidden]="submitted">
<h1>Hero Form 2 (Template & Messages)</h1>
<!-- #docregion form-tag-->
<form #heroForm="ngForm" *ngIf="active" (ngSubmit)="onSubmit()">
<!-- #enddocregion form-tag-->
<div class="form-group">
<!-- #docregion name-with-error-msg -->
<label for="name">Name</label>
<!-- #docregion name-input -->
<input type="text" id="name" class="form-control"
required minlength="4" maxlength="24" forbiddenName="bob"
name="name" [(ngModel)]="hero.name" >
<!-- #enddocregion name-input -->
<div *ngIf="formErrors.name" class="alert alert-danger">
{{ formErrors.name }}
</div>
<!-- #enddocregion name-with-error-msg -->
</div>
<div class="form-group">
<label for="alterEgo">Alter Ego</label>
<input type="text" id="alterEgo" class="form-control"
name="alterEgo"
[(ngModel)]="hero.alterEgo" >
</div>
<div class="form-group">
<label for="power">Hero Power</label>
<select id="power" class="form-control"
name="power"
[(ngModel)]="hero.power" required >
<option *ngFor="let p of powers" [value]="p">{{p}}</option>
</select>
<div *ngIf="formErrors.power" class="alert alert-danger">
{{ formErrors.power }}
</div>
</div>
<button type="submit" class="btn btn-default"
[disabled]="!heroForm.form.valid">Submit</button>
<button type="button" class="btn btn-default"
(click)="addHero()">New Hero</button>
</form>
</div>
<hero-submitted [hero]="hero" [(submitted)]="submitted"></hero-submitted>
</div>

View File

@ -0,0 +1,100 @@
/* tslint:disable: member-ordering forin */
// #docplaster
// #docregion
import { Component, AfterViewChecked, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import { Hero } from '../shared/hero';
@Component({
moduleId: module.id,
selector: 'hero-form-template2',
templateUrl: 'hero-form-template2.component.html'
})
export class HeroFormTemplate2Component implements AfterViewChecked {
powers = ['Really Smart', 'Super Flexible', 'Weather Changer'];
hero = new Hero(18, 'Dr. WhatIsHisWayTooLongName', this.powers[0], 'Dr. What');
submitted = false;
onSubmit() {
this.submitted = true;
}
// #enddocregion
// Reset the form with a new hero AND restore 'pristine' class state
// by toggling 'active' flag which causes the form
// to be removed/re-added in a tick via NgIf
// TODO: Workaround until NgForm has a reset method (#6822)
active = true;
// #docregion
addHero() {
this.hero = new Hero(42, '', '');
// #enddocregion
this.active = false;
setTimeout(() => this.active = true, 0);
// #docregion
}
// #docregion view-child
heroForm: NgForm;
@ViewChild('heroForm') currentForm: NgForm;
ngAfterViewChecked() {
this.formChanged();
}
formChanged() {
if (this.currentForm === this.heroForm) { return; }
this.heroForm = this.currentForm;
if (this.heroForm) {
this.heroForm.valueChanges
.subscribe(data => this.onValueChanged(data));
}
}
// #enddocregion view-child
// #docregion handler
onValueChanged(data?: any) {
if (!this.heroForm) { return; }
const form = this.heroForm.form;
for (const field in this.formErrors) {
// clear previous error message (if any)
this.formErrors[field] = '';
const control = form.get(field);
if (control && control.dirty && !control.valid) {
const messages = this.validationMessages[field];
for (const key in control.errors) {
this.formErrors[field] += messages[key] + ' ';
}
}
}
}
formErrors = {
'name': '',
'power': ''
};
// #enddocregion handler
// #docregion messages
validationMessages = {
'name': {
'required': 'Name is required.',
'minlength': 'Name must be at least 4 characters long.',
'maxlength': 'Name cannot be more than 24 characters long.',
'forbiddenName': 'Someone named "Bob" cannot be a hero.'
},
'power': {
'required': 'Power is required.'
}
};
// #enddocregion messages
}
// #enddocregion

View File

@ -1,9 +1,7 @@
/* #docregion */
.ng-valid[required] {
.ng-valid[required], .ng-valid.required {
border-left: 5px solid #42A948; /* green */
}
.ng-invalid {
.ng-invalid:not(form) {
border-left: 5px solid #a94442; /* red */
}
/* #enddocregion */

View File

@ -1,18 +1,13 @@
<!DOCTYPE html>
<!-- #docregion -->
<html>
<head>
<title>Hero Form</title>
<title>Hero Form with Validation</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- #docregion bootstrap -->
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
<!-- #enddocregion bootstrap -->
<!-- #docregion styles -->
<link rel="stylesheet" href="styles.css">
<link rel="stylesheet" href="forms.css">
<!-- #enddocregion styles -->
<!-- Polyfill(s) for older browsers -->
<script src="node_modules/core-js/client/shim.min.js"></script>
@ -30,5 +25,5 @@
<body>
<my-app>Loading...</my-app>
</body>
</html>

View File

@ -1,5 +1,5 @@
{
"description": "Forms-Deprecated",
"description": "Validation",
"files":[
"!**/*.d.ts",
"!**/*.js"

View File

@ -1,6 +1,6 @@
// #docregion
import { browserDynamicPlatform } from '@angular/platform-browser-dynamic';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';
browserDynamicPlatform().bootstrapModule(AppModule);
platformBrowserDynamic().bootstrapModule(AppModule);

View File

@ -1,5 +1,5 @@
{
"description": "Set The Document Title In Angular 2",
"description": "Set The Document Title In Angular",
"files": [
"!**/*.d.ts",
"!**/*.js",

View File

@ -25,7 +25,7 @@ describe('TypeScript to Javascript tests', function () {
it('should support optional, attribute, and query injections', function () {
let app = element(by.css('hero-di-inject-additional'));
let h1 = app.element(by.css('h1'));
let okMsg = app.element(by.css('.ok-msg'));
let okMsg = app.element(by.css('p'));
expect(h1.getText()).toBe('Tour of Heroes');
app.element(by.buttonText('OK')).click();

View File

@ -6,7 +6,7 @@
template:
'<h1>{{titlePrefix}} {{title}}</h1>' +
'<button (click)="ok()">OK</button>' +
'<ng-content></ng-content>'
'<p>{{ msg }}</p>'
}).Class({
constructor: [
[
@ -14,20 +14,14 @@
new ng.core.Inject('titlePrefix')
],
new ng.core.Attribute('title'),
[
new ng.core.Query('okMsg'),
ng.core.ElementRef
],
function(titlePrefix, title, msg) {
function(titlePrefix, title) {
this.titlePrefix = titlePrefix;
this.title = title;
this.msg = msg;
this.msg = '';
}
],
ok: function() {
var msgEl =
this.msg.first.nativeElement;
msgEl.textContent = 'OK!';
this.msg = 'OK!';
}
});
// #enddocregion
@ -35,7 +29,6 @@
var AppComponent = ng.core.Component({
selector: 'hero-di-inject-additional',
template: '<hero-title title="Tour of Heroes">' +
'<span #okMsg class="ok-msg"></span>' +
'</hero-title>'
}).Class({
constructor: function() { }

View File

@ -4,8 +4,8 @@
// #enddocregion appimport
// #docregion ng2import
var bootstrap =
ng.platformBrowserDynamic.bootstrap;
var platformBrowserDynamic =
ng.platformBrowserDynamic.platformBrowserDynamic;
var LocationStrategy =
ng.common.LocationStrategy;
var HashLocationStrategy =
@ -17,20 +17,17 @@
// #enddocregion appimport
document.addEventListener('DOMContentLoaded', function() {
var platformBrowserDynamic = ng.platformBrowserDynamic.platformBrowserDynamic();
platformBrowserDynamic.bootstrapModule(app.HeroesModule);
platformBrowserDynamic.bootstrapModule(app.HeroesDslModule);
platformBrowserDynamic.bootstrapModule(app.HeroesLifecycleModule);
platformBrowserDynamic.bootstrapModule(app.HeroesDIModule);
platformBrowserDynamic.bootstrapModule(app.HeroDIInlineModule);
platformBrowserDynamic.bootstrapModule(app.HeroesDIInjectModule);
platformBrowserDynamic.bootstrapModule(app.HeroesDIInjectModule2);
platformBrowserDynamic.bootstrapModule(app.HeroesDIInjectAdditionalModule);
platformBrowserDynamic.bootstrapModule(app.HeroesIOModule);
platformBrowserDynamic.bootstrapModule(app.HeroesHostBindingsModule);
platformBrowserDynamic.bootstrapModule(app.HeroesQueriesModule);
platformBrowserDynamic().bootstrapModule(app.HeroesModule);
platformBrowserDynamic().bootstrapModule(app.HeroesDslModule);
platformBrowserDynamic().bootstrapModule(app.HeroesLifecycleModule);
platformBrowserDynamic().bootstrapModule(app.HeroesDIModule);
platformBrowserDynamic().bootstrapModule(app.HeroDIInlineModule);
platformBrowserDynamic().bootstrapModule(app.HeroesDIInjectModule);
platformBrowserDynamic().bootstrapModule(app.HeroesDIInjectModule2);
platformBrowserDynamic().bootstrapModule(app.HeroesDIInjectAdditionalModule);
platformBrowserDynamic().bootstrapModule(app.HeroesIOModule);
platformBrowserDynamic().bootstrapModule(app.HeroesHostBindingsModule);
platformBrowserDynamic().bootstrapModule(app.HeroesQueriesModule);
});
// #docregion appimport

View File

@ -10,7 +10,7 @@
<script src="node_modules/zone.js/dist/zone.js"></script>
<script src="node_modules/reflect-metadata/Reflect.js"></script>
<script src="node_modules/rxjs/bundles/Rx.umd.js"></script>
<script src="node_modules/rxjs/bundles/Rx.js"></script>
<script src="node_modules/@angular/core/bundles/core.umd.js"></script>
<script src="node_modules/@angular/common/bundles/common.umd.js"></script>
<script src="node_modules/@angular/compiler/bundles/compiler.umd.js"></script>

View File

@ -1,11 +1,8 @@
import {
Attribute,
Component,
ElementRef,
Inject,
Optional,
Query,
QueryList,
NgModule
} from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
@ -16,24 +13,21 @@ import { BrowserModule } from '@angular/platform-browser';
template: `
<h1>{{titlePrefix}} {{title}}</h1>
<button (click)="ok()">OK</button>
<ng-content></ng-content>
<p>{{ msg }}</p>
`
})
class TitleComponent {
private msg: string = '';
constructor(
@Inject('titlePrefix')
@Optional()
private titlePrefix: string,
@Attribute('title')
private title: string,
@Query('okMsg')
private msg: QueryList<ElementRef>) {
private title: string) {
}
ok() {
let msgEl =
this.msg.first.nativeElement;
msgEl.textContent = 'OK!';
this.msg = 'OK!';
}
}
// #enddocregion
@ -41,7 +35,6 @@ class TitleComponent {
@Component({
selector: 'hero-di-inject-additional',
template: `<hero-title title="Tour of Heroes">
<span #okMsg class="ok-msg"></span>
</hero-title>`
})
class AppComponent { }

View File

@ -1,7 +1,6 @@
/* tslint:disable no-unused-variable */
// #docregion ng2import
import { bootstrap }
from '@angular/platform-browser-dynamic';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import {
LocationStrategy,
HashLocationStrategy
@ -12,8 +11,6 @@ import {
import { HeroComponent } from './hero.component';
// #enddocregion appimport
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { HeroesModule } from './hero.component';
import { HeroesLifecycleModule } from './hero-lifecycle.component';
import { HeroesDIModule } from './hero-di.component';

View File

@ -7,6 +7,6 @@ describe('cli-quickstart App', () => {
it('should display message saying app works', () => {
let pageTitle = element(by.css('cli-quickstart-app h1')).getText();
expect(pageTitle).toEqual('My First Angular 2 App');
expect(pageTitle).toEqual('My First Angular App');
});
});

Some files were not shown because too many files have changed in this diff Show More