Merge remote-tracking branch 'origin/master'
# Conflicts: # README.md # public/_includes/_scripts-include.jade # public/docs/_examples/homepage-hello-world/ts/index.1.html # public/docs/_examples/homepage-tabs/ts/index.1.html # public/docs/_examples/homepage-todo/ts/index.1.html # public/docs/_examples/systemjs.config.plunker.build.js # public/docs/_examples/systemjs.config.plunker.js # public/docs/js/latest/cookbook/ts-to-js.jade # public/docs/ts/latest/_data.json # public/docs/ts/latest/cookbook/component-communication.jade # public/docs/ts/latest/cookbook/component-relative-paths.jade # public/docs/ts/latest/glossary.jade # public/docs/ts/latest/guide/_data.json # public/docs/ts/latest/guide/architecture.jade # public/docs/ts/latest/guide/attribute-directives.jade # public/docs/ts/latest/guide/dependency-injection.jade # public/docs/ts/latest/guide/index.jade # public/docs/ts/latest/guide/lifecycle-hooks.jade # public/docs/ts/latest/guide/ngmodule.jade # public/docs/ts/latest/guide/npm-packages.jade # public/docs/ts/latest/guide/security.jade # public/docs/ts/latest/guide/server-communication.jade # public/docs/ts/latest/guide/template-syntax.jade # public/docs/ts/latest/guide/typescript-configuration.jade # public/docs/ts/latest/index.jade # public/docs/ts/latest/quickstart.jade # public/docs/ts/latest/tutorial/_data.json # public/docs/ts/latest/tutorial/toh-pt6.jade # public/features.jade # public/resources/js/directives/live-example.js # tools/plunker-builder/indexHtmlTranslator.js
This commit is contained in:
commit
969da7d321
4
.gitignore
vendored
4
.gitignore
vendored
@ -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
|
||||
|
@ -12,18 +12,17 @@ env:
|
||||
- CHROME_BIN=chromium-browser
|
||||
- LATEST_RELEASE=2.0.0-rc.5
|
||||
- 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 +33,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
|
||||
|
181
gulpfile.js
181
gulpfile.js
@ -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
|
||||
@ -118,22 +120,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';
|
||||
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);
|
||||
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: [${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);
|
||||
|
||||
@ -346,6 +361,7 @@ function runE2eDartTests(appDir, outputFile) {
|
||||
}
|
||||
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) {
|
||||
@ -508,23 +524,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
|
||||
@ -598,8 +633,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 });
|
||||
});
|
||||
|
||||
gulp.task('build-dart-cheatsheet', [], function() {
|
||||
@ -608,8 +645,8 @@ gulp.task('build-dart-cheatsheet', [], function() {
|
||||
|
||||
gulp.task('dartdoc', ['pub upgrade'], function() {
|
||||
const ngRepoPath = ngPathFor('dart');
|
||||
if (argv.fast && fs.existsSync(path.resolve(ngRepoPath, 'docs', 'api'))) {
|
||||
gutil.log('Skipping dartdoc: --fast flag enabled and "docs/api" 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);
|
||||
@ -618,7 +655,7 @@ gulp.task('dartdoc', ['pub upgrade'], function() {
|
||||
renameIfExistsSync(topLevelLibFilePath, tmpPath);
|
||||
gutil.log(`Hiding top-level angular2 library: ${topLevelLibFilePath}`);
|
||||
// Remove dartdoc '--add-crossdart' flag while we are fixing links to API pages.
|
||||
const dartdoc = spawnExt('dartdoc', ['--output', 'docs/api'], { cwd: ngRepoPath});
|
||||
const dartdoc = spawnExt('dartdoc', ['--output', relDartDocApiDir], { cwd: ngRepoPath});
|
||||
return dartdoc.promise.finally(() => {
|
||||
gutil.log(`Restoring top-level angular2 library: ${topLevelLibFilePath}`);
|
||||
renameIfExistsSync(tmpPath, topLevelLibFilePath);
|
||||
@ -682,12 +719,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}`);
|
||||
@ -695,7 +732,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');
|
||||
});
|
||||
@ -704,13 +741,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');
|
||||
@ -806,7 +836,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;
|
||||
@ -856,26 +886,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;
|
||||
@ -974,6 +1018,52 @@ 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);
|
||||
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
|
||||
@ -1073,11 +1163,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);
|
||||
@ -1092,11 +1187,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'",
|
||||
@ -1145,8 +1239,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) {
|
||||
@ -1162,8 +1257,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) {
|
||||
@ -1246,7 +1342,7 @@ function buildApiDocsForDart() {
|
||||
log.level = _dgeniLogLevel;
|
||||
const dabInfo = dab.dartPkgConfigInfo;
|
||||
dabInfo.ngIoDartApiDocPath = path.join(DOCS_PATH, 'dart', vers, 'api');
|
||||
dabInfo.ngDartDocPath = path.join(ngPathFor('dart'), 'docs', '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$/);
|
||||
@ -1461,8 +1557,9 @@ function checkAngularProjectPath(_ngPath) {
|
||||
|
||||
function renameIfExistsSync(oldPath, newPath) {
|
||||
if (fs.existsSync(oldPath)) {
|
||||
fs.renameSync(oldPath, newPath);
|
||||
gutil.log(`Rename: mv ${oldPath} ${newPath}`);
|
||||
fs.renameSync(oldPath, newPath);
|
||||
} else {
|
||||
gutil.log(`renameIfExistsSync cannot find file to rename: ${oldPath}`);
|
||||
gutil.log(`renameIfExistsSync cannot rename, path not found: ${oldPath}`);
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,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": {
|
||||
|
@ -35,5 +35,8 @@ header(class="hero background-sky", style=fixHeroCss ? "height:auto" : "")
|
||||
|
||||
else if current.path[3] == 'api' && current.path[1] == 'dart'
|
||||
block breadcrumbs
|
||||
//- Show cross-language menu for top-level API page (but not entry pages)
|
||||
if ! public.docs[current.path[1]][current.path[2]][current.path[3]][current.path[4]]
|
||||
!= partial("_version-dropdown")
|
||||
else if current.path[0] == "docs"
|
||||
!= partial("_version-dropdown")
|
||||
|
@ -155,64 +155,66 @@ mixin makeJson( filePath, jsonConfig, title, stylePatterns)
|
||||
else
|
||||
!= styleString(jsonExtract, stylePatterns)
|
||||
|
||||
- // Open (and close) an explanation <div>. See QuickStart
|
||||
script.
|
||||
function why(id, backTo) {
|
||||
var id = "#"+id;
|
||||
var el = document.querySelector(id);
|
||||
el.hidden=el.hidden=!el.hidden;
|
||||
if !jade2ng
|
||||
//- Open (and close) an explanation <div>. See QuickStart
|
||||
script.
|
||||
function why(id, backTo) {
|
||||
var id = "#"+id;
|
||||
var el = document.querySelector(id);
|
||||
el.hidden=el.hidden=!el.hidden;
|
||||
|
||||
if (el.hidden && backTo){
|
||||
// the next line is required to work around a bug in WebKit (Chrome / Safari)
|
||||
location.href = "#";
|
||||
location.href = "#" + backTo;
|
||||
if (el.hidden && backTo){
|
||||
// the next line is required to work around a bug in WebKit (Chrome / Safari)
|
||||
location.href = "#";
|
||||
location.href = "#" + backTo;
|
||||
}
|
||||
}
|
||||
}
|
||||
script.
|
||||
function verbose(isVerbose) {
|
||||
isVerbose = !! isVerbose;
|
||||
var el = document.querySelector('button.verbose.off');
|
||||
el.style.display = isVerbose ? 'block' : 'none';
|
||||
var el = document.querySelector('button.verbose.on');
|
||||
el.style.display = isVerbose ? 'none' : 'block';
|
||||
script.
|
||||
function verbose(isVerbose) {
|
||||
isVerbose = !! isVerbose;
|
||||
var el = document.querySelector('button.verbose.off');
|
||||
el.style.display = isVerbose ? 'block' : 'none';
|
||||
var el = document.querySelector('button.verbose.on');
|
||||
el.style.display = isVerbose ? 'none' : 'block';
|
||||
|
||||
CCSStylesheetRuleStyle('main','.l-verbose-section', 'display',
|
||||
isVerbose ? 'block' : 'none');
|
||||
}
|
||||
CCSStylesheetRuleStyle('main','.l-verbose-section', 'display',
|
||||
isVerbose ? 'block' : 'none');
|
||||
}
|
||||
|
||||
script.
|
||||
function CCSStylesheetRuleStyle(stylesheet, selectorText, style, value){
|
||||
/* returns the value of the element style of the rule in the stylesheet
|
||||
* If no value is given, reads the value
|
||||
* If value is given, the value is changed and returned
|
||||
* If '' (empty string) is given, erases the value.
|
||||
* The browser will apply the default one
|
||||
*
|
||||
* string stylesheet: part of the .css name to be recognized, e.g. 'default'
|
||||
* string selectorText: css selector, e.g. '#myId', '.myClass', 'thead td'
|
||||
* string style: camelCase element style, e.g. 'fontSize'
|
||||
* string value optional : the new value
|
||||
*/
|
||||
var CCSstyle = undefined, rules, sheet;
|
||||
for(var m in document.styleSheets){
|
||||
sheet = document.styleSheets[m];
|
||||
if(sheet.href && sheet.href.indexOf(stylesheet) != -1){
|
||||
rules = sheet[document.all ? 'rules' : 'cssRules'];
|
||||
for(var n in rules){
|
||||
console.log(rules[n].selectorText);
|
||||
if(rules[n].selectorText == selectorText){
|
||||
CCSstyle = rules[n].style;
|
||||
break;
|
||||
script.
|
||||
function CCSStylesheetRuleStyle(stylesheet, selectorText, style, value){
|
||||
/* returns the value of the element style of the rule in the stylesheet
|
||||
* If no value is given, reads the value
|
||||
* If value is given, the value is changed and returned
|
||||
* If '' (empty string) is given, erases the value.
|
||||
* The browser will apply the default one
|
||||
*
|
||||
* string stylesheet: part of the .css name to be recognized, e.g. 'default'
|
||||
* string selectorText: css selector, e.g. '#myId', '.myClass', 'thead td'
|
||||
* string style: camelCase element style, e.g. 'fontSize'
|
||||
* string value optional : the new value
|
||||
*/
|
||||
var CCSstyle = undefined, rules, sheet;
|
||||
for(var m in document.styleSheets){
|
||||
sheet = document.styleSheets[m];
|
||||
if(sheet.href && sheet.href.indexOf(stylesheet) != -1){
|
||||
rules = sheet[document.all ? 'rules' : 'cssRules'];
|
||||
for(var n in rules){
|
||||
console.log(rules[n].selectorText);
|
||||
if(rules[n].selectorText == selectorText){
|
||||
CCSstyle = rules[n].style;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if(value == undefined)
|
||||
return CCSstyle[style]
|
||||
else
|
||||
return CCSstyle[style] = value
|
||||
}
|
||||
if(value == undefined)
|
||||
return CCSstyle[style]
|
||||
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')
|
||||
@ -299,7 +301,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;
|
||||
|
@ -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,7 +33,7 @@ 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
|
||||
@ -42,7 +42,7 @@ mixin tree(directory, urlPrefix, name, latest)
|
||||
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'
|
||||
@ -72,4 +72,6 @@ nav.dropdown
|
||||
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")
|
||||
//- 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 2 for Dart")
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
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 |
@ -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 { }
|
||||
|
@ -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);
|
||||
|
@ -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 {}
|
||||
|
@ -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 ]
|
||||
})
|
||||
|
@ -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'; }
|
||||
|
180
public/docs/_examples/cb-form-validation/e2e-spec.ts
Normal file
180
public/docs/_examples/cb-form-validation/e2e-spec.ts
Normal 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');
|
||||
}
|
@ -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 { }
|
@ -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 { }
|
6
public/docs/_examples/cb-form-validation/ts/app/main.ts
Normal file
6
public/docs/_examples/cb-form-validation/ts/app/main.ts
Normal file
@ -0,0 +1,6 @@
|
||||
// #docregion
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
@ -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>
|
@ -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
|
@ -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 { }
|
@ -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
|
||||
|
@ -0,0 +1,9 @@
|
||||
// #docregion
|
||||
export class Hero {
|
||||
constructor(
|
||||
public id: number,
|
||||
public name: string,
|
||||
public power: string,
|
||||
public alterEgo?: string
|
||||
) { }
|
||||
}
|
@ -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 { }
|
@ -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); }
|
||||
}
|
@ -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 { }
|
@ -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>
|
@ -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
|
@ -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>
|
@ -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
|
7
public/docs/_examples/cb-form-validation/ts/forms.css
Normal file
7
public/docs/_examples/cb-form-validation/ts/forms.css
Normal file
@ -0,0 +1,7 @@
|
||||
.ng-valid[required], .ng-valid.required {
|
||||
border-left: 5px solid #42A948; /* green */
|
||||
}
|
||||
|
||||
.ng-invalid:not(form) {
|
||||
border-left: 5px solid #a94442; /* red */
|
||||
}
|
29
public/docs/_examples/cb-form-validation/ts/index.html
Normal file
29
public/docs/_examples/cb-form-validation/ts/index.html
Normal file
@ -0,0 +1,29 @@
|
||||
<html>
|
||||
<head>
|
||||
<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">
|
||||
|
||||
<link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
<link rel="stylesheet" href="forms.css">
|
||||
|
||||
<!-- Polyfill(s) for older browsers -->
|
||||
<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>
|
||||
<script src="node_modules/systemjs/dist/system.src.js"></script>
|
||||
|
||||
<script src="systemjs.config.js"></script>
|
||||
<script>
|
||||
System.import('app').catch(function(err){ console.error(err); });
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<my-app>Loading...</my-app>
|
||||
</body>
|
||||
</html>
|
||||
|
7
public/docs/_examples/cb-form-validation/ts/plnkr.json
Normal file
7
public/docs/_examples/cb-form-validation/ts/plnkr.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"description": "Validation",
|
||||
"files":[
|
||||
"!**/*.d.ts",
|
||||
"!**/*.js"
|
||||
]
|
||||
}
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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() { }
|
||||
|
@ -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
|
||||
|
@ -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 { }
|
||||
|
@ -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';
|
||||
|
@ -7,9 +7,21 @@ import { HeroesComponent } from './heroes/heroes.component';
|
||||
import { HeroListComponent } from './heroes/hero-list.component';
|
||||
import { InjectorComponent } from './injector.component';
|
||||
import { TestComponent } from './test.component';
|
||||
import { ProvidersComponent } from './providers.component';
|
||||
import { APP_CONFIG, HERO_DI_CONFIG } from './app.config';
|
||||
import { UserService } from './user.service';
|
||||
import {
|
||||
ProvidersComponent,
|
||||
Provider1Component,
|
||||
Provider3Component,
|
||||
Provider4Component,
|
||||
Provider5Component,
|
||||
Provider6aComponent,
|
||||
Provider6bComponent,
|
||||
Provider7Component,
|
||||
Provider8Component,
|
||||
Provider9Component,
|
||||
Provider10Component,
|
||||
} from './providers.component';
|
||||
|
||||
// #docregion ngmodule
|
||||
@NgModule({
|
||||
@ -22,7 +34,18 @@ import { UserService } from './user.service';
|
||||
HeroesComponent,
|
||||
HeroListComponent,
|
||||
InjectorComponent,
|
||||
TestComponent
|
||||
TestComponent,
|
||||
ProvidersComponent,
|
||||
Provider1Component,
|
||||
Provider3Component,
|
||||
Provider4Component,
|
||||
Provider5Component,
|
||||
Provider6aComponent,
|
||||
Provider6bComponent,
|
||||
Provider7Component,
|
||||
Provider8Component,
|
||||
Provider9Component,
|
||||
Provider10Component,
|
||||
],
|
||||
// #docregion ngmodule-providers
|
||||
providers: [
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { browserDynamicPlatform } from '@angular/platform-browser-dynamic';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
// #docregion bootstrap
|
||||
browserDynamicPlatform().bootstrapModule(AppModule);
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
// #enddocregion bootstrap
|
||||
|
@ -261,18 +261,6 @@ export class Provider10Component implements OnInit {
|
||||
<div id="p8"><provider-8></provider-8></div>
|
||||
<div id="p9"><provider-9></provider-9></div>
|
||||
<div id="p10"><provider-10></provider-10></div>
|
||||
`,
|
||||
directives: [
|
||||
Provider1Component,
|
||||
Provider3Component,
|
||||
Provider4Component,
|
||||
Provider5Component,
|
||||
Provider6aComponent,
|
||||
Provider6bComponent,
|
||||
Provider7Component,
|
||||
Provider8Component,
|
||||
Provider9Component,
|
||||
Provider10Component,
|
||||
],
|
||||
`
|
||||
})
|
||||
export class ProvidersComponent { }
|
||||
|
@ -1,18 +0,0 @@
|
||||
/* tslint:disable */
|
||||
import { bootstrap } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppCtorComponent } from './app-ctor.component';
|
||||
import { AppComponent as v1 } from './app.component.1';
|
||||
import { AppComponent as v2 } from './app.component.2';
|
||||
import { AppComponent as v3 } from './app.component.3';
|
||||
|
||||
import { AppComponent as final } from './app.component';
|
||||
|
||||
// pick one
|
||||
// bootstrap(v1);
|
||||
// bootstrap(v2);
|
||||
// bootstrap(v3);
|
||||
bootstrap(final);
|
||||
|
||||
// for doc testing
|
||||
bootstrap(AppCtorComponent);
|
@ -1,9 +1,9 @@
|
||||
/* #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 */
|
||||
/* #enddocregion */
|
||||
|
@ -11,7 +11,7 @@
|
||||
<!-- Polyfill(s) for older browsers -->
|
||||
<script src="https://unpkg.com/core-js/client/shim.min.js"></script>
|
||||
|
||||
<script src="https://unpkg.com/zone.js@0.6.12"></script>
|
||||
<script src="https://unpkg.com/zone.js@0.6.17"></script>
|
||||
<script src="https://unpkg.com/reflect-metadata@0.1.3"></script>
|
||||
<script src="https://unpkg.com/systemjs@0.19.27/dist/system.src.js"></script>
|
||||
<script src="https://unpkg.com/typescript@1.8.10/lib/typescript.js"></script>
|
||||
|
17
public/docs/_examples/homepage-tabs/ts/app/app.module.ts
Normal file
17
public/docs/_examples/homepage-tabs/ts/app/app.module.ts
Normal file
@ -0,0 +1,17 @@
|
||||
// #docregion
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
import { DiDemoComponent } from './di_demo';
|
||||
import { UiTabsComponent, UiPaneDirective } from './ui_tabs';
|
||||
|
||||
@NgModule({
|
||||
imports: [ BrowserModule ],
|
||||
declarations: [
|
||||
DiDemoComponent,
|
||||
UiTabsComponent,
|
||||
UiPaneDirective
|
||||
],
|
||||
bootstrap: [ DiDemoComponent ]
|
||||
})
|
||||
export class AppModule { }
|
@ -1,8 +1,6 @@
|
||||
// #docregion
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { UiTabsComponent, UiPaneDirective } from './ui_tabs';
|
||||
|
||||
class Detail {
|
||||
title: string;
|
||||
text: string;
|
||||
@ -26,8 +24,7 @@ class Detail {
|
||||
</ui-tabs>
|
||||
<hr>
|
||||
<button class="btn" (click)="addDetail()">Add Detail</button>
|
||||
`,
|
||||
directives: [UiTabsComponent, UiPaneDirective]
|
||||
`
|
||||
})
|
||||
export class DiDemoComponent {
|
||||
details: Detail[] = [];
|
||||
|
@ -1,6 +1,6 @@
|
||||
// #docregion
|
||||
import { bootstrap } from '@angular/platform-browser-dynamic';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { DiDemoComponent } from './di_demo';
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
bootstrap(DiDemoComponent);
|
||||
platformBrowserDynamic().bootstrapModule(AppModule);
|
||||
|
@ -12,7 +12,7 @@
|
||||
<!-- Polyfill(s) for older browsers -->
|
||||
<script src="https://unpkg.com/core-js/client/shim.min.js"></script>
|
||||
|
||||
<script src="https://unpkg.com/zone.js@0.6.12"></script>
|
||||
<script src="https://unpkg.com/zone.js@0.6.17"></script>
|
||||
<script src="https://unpkg.com/reflect-metadata@0.1.3"></script>
|
||||
<script src="https://unpkg.com/systemjs@0.19.27/dist/system.src.js"></script>
|
||||
<script src="https://unpkg.com/typescript@1.8.10/lib/typescript.js"></script>
|
||||
|
@ -4,13 +4,19 @@ import { BrowserModule } from '@angular/platform-browser';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { TodoAppComponent } from './todo_app';
|
||||
import { TodoListComponent } from './todo_list';
|
||||
import { TodoFormComponent } from './todo_form';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
BrowserModule,
|
||||
FormsModule
|
||||
],
|
||||
declarations: [ TodoAppComponent ],
|
||||
declarations: [
|
||||
TodoAppComponent,
|
||||
TodoListComponent,
|
||||
TodoFormComponent
|
||||
],
|
||||
bootstrap: [ TodoAppComponent ]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
@ -2,8 +2,6 @@
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { Todo } from './todo';
|
||||
import { TodoListComponent } from './todo_list';
|
||||
import { TodoFormComponent } from './todo_form';
|
||||
|
||||
@Component({
|
||||
selector: 'todo-app',
|
||||
@ -14,8 +12,7 @@ import { TodoFormComponent } from './todo_form';
|
||||
|
||||
<todo-list [todos]="todos"></todo-list>
|
||||
<todo-form (newTask)="addTask($event)"></todo-form>`,
|
||||
styles: ['a { cursor: pointer; cursor: hand; }'],
|
||||
directives: [TodoListComponent, TodoFormComponent]
|
||||
styles: ['a { cursor: pointer; cursor: hand; }']
|
||||
})
|
||||
export class TodoAppComponent {
|
||||
todos: Todo[] = [
|
||||
|
@ -12,7 +12,7 @@
|
||||
<!-- Polyfill(s) for older browsers -->
|
||||
<script src="https://unpkg.com/core-js/client/shim.min.js"></script>
|
||||
|
||||
<script src="https://unpkg.com/zone.js@0.6.12"></script>
|
||||
<script src="https://unpkg.com/zone.js@0.6.17"></script>
|
||||
<script src="https://unpkg.com/reflect-metadata@0.1.3"></script>
|
||||
<script src="https://unpkg.com/systemjs@0.19.27/dist/system.src.js"></script>
|
||||
<script src="https://unpkg.com/typescript@1.8.10/lib/typescript.js"></script>
|
||||
|
@ -28,22 +28,18 @@ System.config({
|
||||
});
|
||||
|
||||
System.import('systemjs.config.js')
|
||||
.then(function () {
|
||||
return Promise.all([
|
||||
.then(() => Promise.all([
|
||||
System.import('@angular/core/testing'),
|
||||
System.import('@angular/platform-browser-dynamic/testing')
|
||||
])
|
||||
]))
|
||||
.then((providers) => {
|
||||
var coreTesting = providers[0];
|
||||
var browserTesting = providers[1];
|
||||
coreTesting.TestBed.initTestEnvironment(
|
||||
browserTesting.BrowserDynamicTestingModule,
|
||||
browserTesting.platformBrowserDynamicTesting());
|
||||
})
|
||||
.then(function (providers) {
|
||||
var testing = providers[0];
|
||||
var testingBrowser = providers[1];
|
||||
|
||||
testing.setBaseTestProviders(
|
||||
testingBrowser.TEST_BROWSER_DYNAMIC_PLATFORM_PROVIDERS,
|
||||
testingBrowser.TEST_BROWSER_DYNAMIC_APPLICATION_PROVIDERS);
|
||||
|
||||
})
|
||||
.then(function() {
|
||||
.then(function () {
|
||||
// Finally, load all spec files.
|
||||
// This will run the tests directly.
|
||||
return Promise.all(
|
||||
|
@ -66,8 +66,8 @@ describe('Lifecycle hooks', function () {
|
||||
|
||||
expect(titleEle.getText()).toContain('Windstorm can sing');
|
||||
changeLogEles.count().then(function(count) {
|
||||
// Empirically 5 messages to start
|
||||
expect(count).toBeGreaterThan(4, 'should start with some messages');
|
||||
// 3 messages to start
|
||||
expect(count).toEqual(3, 'should start with 3 messages');
|
||||
logCount = count;
|
||||
// heroNameInputEle.sendKeys('-foo-').then(function () {
|
||||
return sendKeys(heroNameInputEle, '-foo-');
|
||||
@ -82,8 +82,7 @@ describe('Lifecycle hooks', function () {
|
||||
return sendKeys(powerInputEle, '-bar-');
|
||||
}).then(function () {
|
||||
expect(titleEle.getText()).toContain('Windstorm-foo- can sing-bar-');
|
||||
// 7 == 2 previously + length of '-bar-'
|
||||
expect(changeLogEles.count()).toEqual(logCount + 11, 'should add 11 more messages');
|
||||
expect(changeLogEles.count()).toEqual(logCount + 6, 'should add 6 more messages');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* tslint:disable:forin */
|
||||
// #docregion
|
||||
import { Component, DoCheck, Input, OnChanges, SimpleChange, ViewChild } from '@angular/core';
|
||||
import { Component, DoCheck, Input, ViewChild } from '@angular/core';
|
||||
|
||||
class Hero {
|
||||
constructor(public name: string) {}
|
||||
@ -21,7 +21,7 @@ class Hero {
|
||||
'p {background: Yellow; padding: 8px; margin-top: 8px}'
|
||||
]
|
||||
})
|
||||
export class DoCheckComponent implements DoCheck, OnChanges {
|
||||
export class DoCheckComponent implements DoCheck {
|
||||
@Input() hero: Hero;
|
||||
@Input() power: string;
|
||||
|
||||
@ -66,16 +66,6 @@ export class DoCheckComponent implements DoCheck, OnChanges {
|
||||
}
|
||||
// #enddocregion ng-do-check
|
||||
|
||||
// Copied from OnChangesComponent
|
||||
ngOnChanges(changes: {[propertyName: string]: SimpleChange}) {
|
||||
for (let propName in changes) {
|
||||
let chng = changes[propName];
|
||||
let cur = JSON.stringify(chng.currentValue);
|
||||
let prev = JSON.stringify(chng.previousValue);
|
||||
this.changeLog.push(`OnChanges: ${propName}: currentValue = ${cur}, previousValue = ${prev}`);
|
||||
}
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.changeDetected = true;
|
||||
this.changeLog.length = 0;
|
||||
|
@ -6,6 +6,7 @@ describe('NgModule', function () {
|
||||
const gold = 'rgba(255, 215, 0, 1)';
|
||||
const powderblue = 'rgba(176, 224, 230, 1)';
|
||||
const lightgray = 'rgba(211, 211, 211, 1)';
|
||||
const white = 'rgba(0, 0, 0, 0)';
|
||||
|
||||
function getCommonsSectionStruct() {
|
||||
const buttons = element.all(by.css('nav a'));
|
||||
@ -55,7 +56,7 @@ describe('NgModule', function () {
|
||||
}
|
||||
|
||||
// tests
|
||||
function appTitleTests(color: string) {
|
||||
function appTitleTests(color: string, name?: string) {
|
||||
return function() {
|
||||
it('should have a gray header', function() {
|
||||
const commons = getCommonsSectionStruct();
|
||||
@ -64,16 +65,16 @@ describe('NgModule', function () {
|
||||
|
||||
it('should welcome us', function () {
|
||||
const commons = getCommonsSectionStruct();
|
||||
expect(commons.subtitle.getText()).toBe('Welcome, Sam Spade');
|
||||
expect(commons.subtitle.getText()).toBe('Welcome, ' + (name || 'Sherlock Holmes'));
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
function contactTests(color: string) {
|
||||
function contactTests(color: string, name?: string) {
|
||||
return function() {
|
||||
it('shows the contact\'s owner', function() {
|
||||
const contacts = getContactSectionStruct();
|
||||
expect(contacts.header.getText()).toBe('Contact of Sam Spade');
|
||||
expect(contacts.header.getText()).toBe('Contact of ' + (name || 'Sherlock Holmes'));
|
||||
});
|
||||
|
||||
it('can cycle between contacts', function () {
|
||||
@ -114,9 +115,9 @@ describe('NgModule', function () {
|
||||
browser.get('');
|
||||
});
|
||||
|
||||
describe('app-title', appTitleTests(lightgray));
|
||||
describe('app-title', appTitleTests(white, 'Miss Marple'));
|
||||
|
||||
describe('contact', contactTests(lightgray));
|
||||
describe('contact', contactTests(lightgray, 'Miss Marple'));
|
||||
|
||||
describe('crisis center', function () {
|
||||
beforeEach(function () {
|
||||
@ -149,7 +150,7 @@ describe('NgModule', function () {
|
||||
|
||||
it('shows a list of heroes', function() {
|
||||
const heroes = getHeroesSectionStruct();
|
||||
expect(heroes.header.getText()).toBe('Heroes of Sam Spade');
|
||||
expect(heroes.header.getText()).toBe('Heroes of Miss Marple');
|
||||
expect(heroes.title.getText()).toBe('Hero List');
|
||||
expect(heroes.items.count()).toBe(6);
|
||||
expect(heroes.items.get(0).getText()).toBe('11 - Mr. Nice');
|
||||
|
@ -11,8 +11,6 @@ import { UserService } from './user.service';
|
||||
|
||||
/* Feature Modules */
|
||||
import { ContactModule } from './contact/contact.module.3';
|
||||
|
||||
|
||||
import { routing } from './app.routing.3';
|
||||
|
||||
@NgModule({
|
||||
@ -23,9 +21,8 @@ import { routing } from './app.routing.3';
|
||||
routing
|
||||
],
|
||||
// #enddocregion imports
|
||||
|
||||
declarations: [ AppComponent, HighlightDirective, TitleComponent ],
|
||||
providers: [ UserService ],
|
||||
declarations: [ AppComponent, HighlightDirective, TitleComponent ],
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
@ -1,29 +1,40 @@
|
||||
// #docplaster
|
||||
// #docregion
|
||||
// #docregion v4
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
|
||||
/* App Root */
|
||||
import { AppComponent } from './app.component';
|
||||
|
||||
|
||||
|
||||
|
||||
/* Feature Modules */
|
||||
import { ContactModule } from './contact/contact.module';
|
||||
import { SharedModule } from './shared/shared.module';
|
||||
|
||||
import { CoreModule } from './core/core.module';
|
||||
import { routing } from './app.routing';
|
||||
|
||||
@NgModule({
|
||||
// #docregion import-for-root
|
||||
imports: [
|
||||
BrowserModule,
|
||||
ContactModule,
|
||||
routing,
|
||||
SharedModule.forRoot()
|
||||
// #enddocregion v4
|
||||
// #enddocregion
|
||||
// #enddocregion import-for-root
|
||||
/*
|
||||
// #docregion v4
|
||||
CoreModule,
|
||||
// #enddocregion v4
|
||||
*/
|
||||
// #docregion import-for-root
|
||||
// #docregion
|
||||
CoreModule.forRoot({userName: 'Miss Marple'}),
|
||||
// #docregion v4
|
||||
routing
|
||||
],
|
||||
// #enddocregion import-for-root
|
||||
declarations: [ AppComponent ],
|
||||
|
||||
bootstrap: [ AppComponent ]
|
||||
})
|
||||
export class AppModule { }
|
||||
// #enddocregion v4
|
||||
// #enddocregion
|
||||
|
@ -1,11 +1,10 @@
|
||||
import { ModuleWithProviders } from '@angular/core';
|
||||
import { Routes,
|
||||
RouterModule } from '@angular/router';
|
||||
import { ModuleWithProviders } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
export const routes: Routes = [
|
||||
{ path: '', redirectTo: 'contact', pathMatch: 'full'},
|
||||
{ path: 'crisis', loadChildren: 'app/crisis/crisis.module' },
|
||||
{ path: 'heroes', loadChildren: 'app/hero/hero.module.3' }
|
||||
{ path: 'crisis', loadChildren: 'app/crisis/crisis.module#CrisisModule' },
|
||||
{ path: 'heroes', loadChildren: 'app/hero/hero.module.3#HeroModule' }
|
||||
];
|
||||
|
||||
export const routing: ModuleWithProviders = RouterModule.forRoot(routes);
|
||||
|
@ -1,13 +1,12 @@
|
||||
// #docregion
|
||||
import { ModuleWithProviders } from '@angular/core';
|
||||
import { Routes,
|
||||
RouterModule } from '@angular/router';
|
||||
import { ModuleWithProviders } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
export const routes: Routes = [
|
||||
{ path: '', redirectTo: 'contact', pathMatch: 'full'},
|
||||
// #docregion lazy-routes
|
||||
{ path: 'crisis', loadChildren: 'app/crisis/crisis.module' },
|
||||
{ path: 'heroes', loadChildren: 'app/hero/hero.module' }
|
||||
{ path: 'crisis', loadChildren: 'app/crisis/crisis.module#CrisisModule' },
|
||||
{ path: 'heroes', loadChildren: 'app/hero/hero.module#HeroModule' }
|
||||
// #enddocregion lazy-routes
|
||||
];
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
// Exact copy except import UserService from shared
|
||||
// Exact copy except import UserService from core
|
||||
// #docregion
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
import { Contact, ContactService } from './contact.service';
|
||||
import { UserService } from '../shared/user.service';
|
||||
import { UserService } from '../core/user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-contact',
|
||||
|
@ -15,7 +15,6 @@ import { routing } from './contact.routing.3';
|
||||
@NgModule({
|
||||
imports: [ CommonModule, FormsModule, routing ],
|
||||
declarations: [ ContactComponent, HighlightDirective, AwesomePipe ],
|
||||
|
||||
providers: [ ContactService ]
|
||||
})
|
||||
export class ContactModule { }
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { ModuleWithProviders } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
import { ContactComponent } from './contact.component.3';
|
||||
import { ContactComponent } from './contact.component.3';
|
||||
|
||||
export const routing: ModuleWithProviders = RouterModule.forChild([
|
||||
{ path: 'contact', component: ContactComponent}
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { ModuleWithProviders } from '@angular/core';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { RouterModule } from '@angular/router';
|
||||
|
||||
import { ContactComponent } from './contact.component';
|
||||
import { ContactComponent } from './contact.component';
|
||||
|
||||
// #docregion routing
|
||||
export const routing: ModuleWithProviders = RouterModule.forChild([
|
||||
|
48
public/docs/_examples/ngmodule/ts/app/core/core.module.ts
Normal file
48
public/docs/_examples/ngmodule/ts/app/core/core.module.ts
Normal file
@ -0,0 +1,48 @@
|
||||
/* tslint:disable:member-ordering no-unused-variable */
|
||||
// #docplaster
|
||||
// #docregion
|
||||
// #docregion v4
|
||||
import {
|
||||
ModuleWithProviders, NgModule,
|
||||
Optional, SkipSelf } from '@angular/core';
|
||||
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { TitleComponent } from './title.component';
|
||||
import { UserService } from './user.service';
|
||||
// #enddocregion
|
||||
import { UserServiceConfig } from './user.service';
|
||||
|
||||
// #docregion v4
|
||||
@NgModule({
|
||||
imports: [ CommonModule ],
|
||||
declarations: [ TitleComponent ],
|
||||
exports: [ TitleComponent ],
|
||||
providers: [ UserService ]
|
||||
})
|
||||
export class CoreModule {
|
||||
// #enddocregion v4
|
||||
|
||||
// #docregion ctor
|
||||
constructor (@Optional() @SkipSelf() parentModule: CoreModule) {
|
||||
if (parentModule) {
|
||||
throw new Error(
|
||||
'CoreModule is already loaded. Import it in the AppModule only');
|
||||
}
|
||||
}
|
||||
// #enddocregion ctor
|
||||
|
||||
// #docregion for-root
|
||||
static forRoot(config: UserServiceConfig): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: CoreModule,
|
||||
providers: [
|
||||
{provide: UserServiceConfig, useValue: config }
|
||||
]
|
||||
};
|
||||
}
|
||||
// #enddocregion for-root
|
||||
// #docregion v4
|
||||
}
|
||||
// #enddocregion v4
|
||||
// #enddocregion
|
@ -1,4 +1,4 @@
|
||||
<!-- Exact copy from app.component.html -->
|
||||
<!-- Exact copy from earlier app.component.html -->
|
||||
<h1 highlight>{{title}} {{subtitle}}</h1>
|
||||
<p *ngIf="user">
|
||||
<i>Welcome, {{user}}</i>
|
@ -1,10 +1,10 @@
|
||||
// Exact copy of app/title.component.ts except import UserService from shared
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { UserService } from './user.service';
|
||||
import { UserService } from '../core/user.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-title',
|
||||
templateUrl: 'app/shared/title.component.html',
|
||||
templateUrl: 'app/core/title.component.html',
|
||||
})
|
||||
export class TitleComponent {
|
||||
@Input() subtitle = '';
|
32
public/docs/_examples/ngmodule/ts/app/core/user.service.ts
Normal file
32
public/docs/_examples/ngmodule/ts/app/core/user.service.ts
Normal file
@ -0,0 +1,32 @@
|
||||
// Crazy copy of the app/user.service
|
||||
// Proves that UserService is an app-wide singleton and only instantiated once
|
||||
// IFF shared.module follows the `forRoot` pattern
|
||||
//
|
||||
// If it didn't, a new instance of UserService would be created
|
||||
// after each lazy load and the userName would double up.
|
||||
|
||||
import { Injectable, Optional } from '@angular/core';
|
||||
|
||||
let nextId = 1;
|
||||
|
||||
export class UserServiceConfig {
|
||||
userName = 'Philip Marlowe';
|
||||
}
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
id = nextId++;
|
||||
private _userName = 'Sherlock Holmes';
|
||||
|
||||
// #docregion ctor
|
||||
constructor(@Optional() config: UserServiceConfig) {
|
||||
if (config) { this._userName = config.userName; }
|
||||
}
|
||||
// #enddocregion ctor
|
||||
|
||||
get userName() {
|
||||
// Demo: add a suffix if this service has been created more than once
|
||||
const suffix = this.id > 1 ? ` times ${this.id}` : '';
|
||||
return this._userName + suffix;
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
|
@ -11,6 +11,4 @@ import { routing } from './crisis.routing';
|
||||
declarations: [ CrisisDetailComponent, CrisisListComponent ],
|
||||
providers: [ CrisisService ]
|
||||
})
|
||||
// #docregion export-default
|
||||
export default class CrisisModule {}
|
||||
// #enddocregion export-default
|
||||
export class CrisisModule {}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { ModuleWithProviders } from '@angular/core';
|
||||
import { Routes,
|
||||
RouterModule } from '@angular/router';
|
||||
RouterModule } from '@angular/router';
|
||||
|
||||
import { CrisisListComponent } from './crisis-list.component';
|
||||
import { CrisisDetailComponent } from './crisis-detail.component';
|
||||
|
@ -1,8 +1,8 @@
|
||||
// Exact copy except import UserService from shared
|
||||
// Exact copy except import UserService from core
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
import { HeroService } from './hero.service';
|
||||
import { UserService } from '../shared/user.service';
|
||||
import { UserService } from '../core/user.service';
|
||||
|
||||
@Component({
|
||||
template: `
|
||||
|
@ -1,20 +1,25 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { HeroComponent } from './hero.component.3';
|
||||
import { HeroDetailComponent } from './hero-detail.component';
|
||||
import { HeroListComponent } from './hero-list.component';
|
||||
import { HighlightDirective } from './highlight.directive';
|
||||
import { routing } from './hero.routing.3';
|
||||
import { HeroComponent } from './hero.component.3';
|
||||
import { HeroDetailComponent } from './hero-detail.component';
|
||||
import { HeroListComponent } from './hero-list.component';
|
||||
import { HighlightDirective } from './highlight.directive';
|
||||
import { routing } from './hero.routing.3';
|
||||
|
||||
// TODO: Remove in RC 6
|
||||
import { HeroService } from './hero.service';
|
||||
|
||||
// #docregion class
|
||||
@NgModule({
|
||||
imports: [ CommonModule, FormsModule, routing ],
|
||||
// TODO: Remove in RC 6
|
||||
providers: [ HeroService ],
|
||||
declarations: [
|
||||
HeroComponent, HeroDetailComponent, HeroListComponent,
|
||||
HighlightDirective
|
||||
]
|
||||
})
|
||||
export default class HeroModule { }
|
||||
export class HeroModule { }
|
||||
// #enddocregion class
|
||||
|
@ -1,23 +1,21 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
import { SharedModule } from '../shared/shared.module';
|
||||
|
||||
import { HeroComponent } from './hero.component';
|
||||
import { HeroDetailComponent } from './hero-detail.component';
|
||||
import { HeroListComponent } from './hero-list.component';
|
||||
import { routing } from './hero.routing';
|
||||
import { HeroComponent } from './hero.component';
|
||||
import { HeroDetailComponent } from './hero-detail.component';
|
||||
import { HeroListComponent } from './hero-list.component';
|
||||
import { routing } from './hero.routing';
|
||||
|
||||
/*
|
||||
* TODO: Remove THE HeroService class and provider after
|
||||
* https://github.com/angular/angular/pull/10579 lands
|
||||
*/
|
||||
// TODO: Remove THE HeroService class in RC 6
|
||||
import { HeroService } from './hero.service';
|
||||
|
||||
@NgModule({
|
||||
imports: [ SharedModule, routing ],
|
||||
// TODO: Remove in RC 6
|
||||
providers: [ HeroService ],
|
||||
declarations: [
|
||||
HeroComponent, HeroDetailComponent, HeroListComponent,
|
||||
]
|
||||
})
|
||||
export default class HeroModule { }
|
||||
export class HeroModule { }
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { ModuleWithProviders } from '@angular/core';
|
||||
import { Routes,
|
||||
RouterModule } from '@angular/router';
|
||||
RouterModule } from '@angular/router';
|
||||
|
||||
import { HeroComponent } from './hero.component.3';
|
||||
import { HeroListComponent } from './hero-list.component';
|
||||
import { HeroDetailComponent } from './hero-detail.component';
|
||||
import { HeroComponent } from './hero.component.3';
|
||||
import { HeroListComponent } from './hero-list.component';
|
||||
import { HeroDetailComponent } from './hero-detail.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '',
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { ModuleWithProviders } from '@angular/core';
|
||||
import { Routes,
|
||||
RouterModule } from '@angular/router';
|
||||
RouterModule } from '@angular/router';
|
||||
|
||||
import { HeroComponent } from './hero.component';
|
||||
import { HeroListComponent } from './hero-list.component';
|
||||
import { HeroDetailComponent } from './hero-detail.component';
|
||||
import { HeroComponent } from './hero.component';
|
||||
import { HeroListComponent } from './hero-list.component';
|
||||
import { HeroDetailComponent } from './hero-detail.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '',
|
||||
|
@ -1,40 +1,18 @@
|
||||
// #docregion
|
||||
import { NgModule,
|
||||
ModuleWithProviders } from '@angular/core';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
|
||||
import { AwesomePipe } from './awesome.pipe';
|
||||
import { HighlightDirective } from './highlight.directive';
|
||||
import { TitleComponent } from './title.component';
|
||||
import { UserService } from './user.service';
|
||||
|
||||
// #docregion shared-module
|
||||
// #docregion module
|
||||
@NgModule({
|
||||
imports: [ CommonModule ],
|
||||
declarations: [ AwesomePipe, HighlightDirective, TitleComponent ],
|
||||
exports: [ AwesomePipe, HighlightDirective, TitleComponent,
|
||||
declarations: [ AwesomePipe, HighlightDirective ],
|
||||
exports: [ AwesomePipe, HighlightDirective,
|
||||
CommonModule, FormsModule ]
|
||||
})
|
||||
export class SharedModule {
|
||||
|
||||
// #docregion for-root
|
||||
static forRoot(): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: SharedModule,
|
||||
providers: [ UserService ]
|
||||
};
|
||||
}
|
||||
// #enddocregion for-root
|
||||
}
|
||||
|
||||
// #enddocregion shared-module
|
||||
export class SharedModule { }
|
||||
// #enddocregion module
|
||||
// #enddocregion
|
||||
|
||||
// #docregion shared-root-module
|
||||
@NgModule({
|
||||
exports: [ SharedModule ],
|
||||
providers: [ UserService ]
|
||||
})
|
||||
export class SharedRootModule { }
|
||||
// #enddocregion shared-root-module
|
||||
|
@ -1,20 +0,0 @@
|
||||
// Crazy copy of the app/user.service
|
||||
// Proves that UserService is an app-wide singleton and only instantiated once
|
||||
// IFF shared.module follows the `forRoot` pattern
|
||||
//
|
||||
// If it didn't, a new instance of UserService would be created
|
||||
// after each lazy load and the userName would double up.
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
@Injectable()
|
||||
export class UserService {
|
||||
|
||||
static userName = '';
|
||||
|
||||
constructor() {
|
||||
UserService.userName += UserService.userName || 'Sam Spade';
|
||||
}
|
||||
|
||||
get userName() { return UserService.userName; }
|
||||
}
|
@ -4,5 +4,5 @@ import { Injectable } from '@angular/core';
|
||||
@Injectable()
|
||||
/** Dummy version of an authenticated user service */
|
||||
export class UserService {
|
||||
userName = 'Sam Spade';
|
||||
userName = 'Sherlock Holmes';
|
||||
}
|
||||
|
@ -9,11 +9,12 @@
|
||||
"app/title.component.ts",
|
||||
"app/user.service.ts",
|
||||
|
||||
"app/contact/*.css",
|
||||
"app/contact/*.html",
|
||||
"app/contact/*.ts",
|
||||
"!app/contact/contact.component.ts",
|
||||
"!app/contact/contact.module.ts",
|
||||
"app/contact/awesome.pipe.ts",
|
||||
"app/contact/contact.component.css",
|
||||
"app/contact/contact.component.html",
|
||||
"app/contact/contact.component.3.ts",
|
||||
"app/contact/contact.service.ts",
|
||||
"app/contact/highlight.directive.ts",
|
||||
|
||||
"styles.css",
|
||||
"index.1b.html"
|
||||
|
@ -9,12 +9,14 @@
|
||||
"app/title.component.ts",
|
||||
"app/user.service.ts",
|
||||
|
||||
"app/contact/*.css",
|
||||
"app/contact/*.html",
|
||||
"app/contact/*.ts",
|
||||
"!app/contact/contact.component.ts",
|
||||
"!app/contact/contact.module.ts",
|
||||
"!app/contact/contact.module.3.ts",
|
||||
"app/contact/contact.component.css",
|
||||
"app/contact/contact.component.html",
|
||||
"app/contact/contact.service.ts",
|
||||
|
||||
"app/contact/awesome.pipe.ts",
|
||||
"app/contact/contact.component.3.ts",
|
||||
"app/contact/contact.module.2.ts",
|
||||
"app/contact/highlight.directive.ts",
|
||||
|
||||
"styles.css",
|
||||
"index.2.html"
|
||||
|
@ -8,19 +8,25 @@
|
||||
|
||||
"app/contact/contact.component.css",
|
||||
"app/contact/contact.component.html",
|
||||
"app/contact/contact.service.ts",
|
||||
|
||||
"app/contact/contact.component.ts",
|
||||
"app/contact/contact.module.ts",
|
||||
"app/contact/contact.routing.ts",
|
||||
"app/contact/contact.service.ts",
|
||||
|
||||
"app/crisis/*.ts",
|
||||
|
||||
"app/hero/*.ts",
|
||||
"app/hero/hero-detail.component.ts",
|
||||
"app/hero/hero-list.component.ts",
|
||||
"app/hero/hero.service.ts",
|
||||
|
||||
"!app/hero/hero.component.3.ts",
|
||||
"!app/hero/hero.module.3.ts",
|
||||
"!app/hero/hero.routing.3.ts",
|
||||
"!app/hero/highlight.directive.ts",
|
||||
"app/hero/hero.component.ts",
|
||||
"app/hero/hero.module.ts",
|
||||
"app/hero/hero.routing.ts",
|
||||
|
||||
"app/core/*.css",
|
||||
"app/core/*.html",
|
||||
"app/core/*.ts",
|
||||
|
||||
"app/shared/*.css",
|
||||
"app/shared/*.html",
|
||||
|
@ -11,21 +11,26 @@
|
||||
"app/title.component.ts",
|
||||
"app/user.service.ts",
|
||||
|
||||
"app/contact/*.css",
|
||||
"app/contact/*.html",
|
||||
"app/contact/*.ts",
|
||||
"app/contact/contact.component.css",
|
||||
"app/contact/contact.component.html",
|
||||
"app/contact/contact.service.ts",
|
||||
|
||||
"!app/contact/contact.component.ts",
|
||||
"!app/contact/contact.module.ts",
|
||||
"!app/contact/contact.routing.ts",
|
||||
"app/contact/awesome.pipe.ts",
|
||||
"app/contact/contact.component.3.ts",
|
||||
"app/contact/contact.module.3.ts",
|
||||
"app/contact/contact.routing.3.ts",
|
||||
"app/contact/highlight.directive.ts",
|
||||
|
||||
"app/crisis/*.ts",
|
||||
|
||||
"app/hero/*.ts",
|
||||
"app/hero/hero-detail.component.ts",
|
||||
"app/hero/hero-list.component.ts",
|
||||
"app/hero/hero.service.ts",
|
||||
|
||||
"!app/hero/hero.component.ts",
|
||||
"!app/hero/hero.module.ts",
|
||||
"!app/hero/hero.routing.ts",
|
||||
"app/hero/hero.component.3.ts",
|
||||
"app/hero/hero.module.3.ts",
|
||||
"app/hero/hero.routing.3.ts",
|
||||
"app/hero/highlight.directive.ts",
|
||||
|
||||
"styles.css",
|
||||
"index.3.html"
|
||||
|
@ -25,29 +25,29 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@angular/common": "2.0.0-rc.5",
|
||||
"@angular/compiler": "2.0.0-rc.5",
|
||||
"@angular/core": "2.0.0-rc.5",
|
||||
"@angular/forms": "0.3.0",
|
||||
"@angular/http": "2.0.0-rc.5",
|
||||
"@angular/platform-browser": "2.0.0-rc.5",
|
||||
"@angular/platform-browser-dynamic": "2.0.0-rc.5",
|
||||
"@angular/router": "3.0.0-rc.1",
|
||||
"@angular/router-deprecated": "2.0.0-rc.2",
|
||||
"@angular/upgrade": "2.0.0-rc.5",
|
||||
"angular2-in-memory-web-api": "0.0.17",
|
||||
"@angular/common": "2.0.0-rc.6",
|
||||
"@angular/compiler": "2.0.0-rc.6",
|
||||
"@angular/compiler-cli": "0.6.0",
|
||||
"@angular/core": "2.0.0-rc.6",
|
||||
"@angular/forms": "2.0.0-rc.6",
|
||||
"@angular/http": "2.0.0-rc.6",
|
||||
"@angular/platform-browser": "2.0.0-rc.6",
|
||||
"@angular/platform-browser-dynamic": "2.0.0-rc.6",
|
||||
"@angular/router": "3.0.0-rc.2",
|
||||
"@angular/upgrade": "2.0.0-rc.6",
|
||||
"angular2-in-memory-web-api": "0.0.18",
|
||||
"bootstrap": "^3.3.6",
|
||||
"core-js": "^2.4.0",
|
||||
"core-js": "^2.4.1",
|
||||
"reflect-metadata": "^0.1.3",
|
||||
"rxjs": "5.0.0-beta.6",
|
||||
"rxjs": "5.0.0-beta.11",
|
||||
"systemjs": "0.19.27",
|
||||
"zone.js": "^0.6.12"
|
||||
"zone.js": "^0.6.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"angular-cli": "^1.0.0-beta.5",
|
||||
"angular2-template-loader": "^0.4.0",
|
||||
"canonical-path": "0.0.2",
|
||||
"concurrently": "^2.1.0",
|
||||
"concurrently": "^2.2.0",
|
||||
"css-loader": "^0.23.1",
|
||||
"extract-text-webpack-plugin": "^1.0.1",
|
||||
"file-loader": "^0.8.5",
|
||||
@ -55,15 +55,15 @@
|
||||
"html-webpack-plugin": "^2.16.1",
|
||||
"http-server": "^0.9.0",
|
||||
"jasmine-core": "^2.4.1",
|
||||
"karma": "^0.13.22",
|
||||
"karma-chrome-launcher": "^1.0.1",
|
||||
"karma-cli": "^1.0.0",
|
||||
"karma-htmlfile-reporter": "^0.3.1",
|
||||
"karma": "^1.2.0",
|
||||
"karma-chrome-launcher": "^2.0.0",
|
||||
"karma-cli": "^1.0.1",
|
||||
"karma-htmlfile-reporter": "^0.3.4",
|
||||
"karma-jasmine": "^1.0.2",
|
||||
"karma-phantomjs-launcher": "^1.0.0",
|
||||
"karma-phantomjs-launcher": "^1.0.2",
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-webpack": "^1.7.0",
|
||||
"lite-server": "^2.2.0",
|
||||
"karma-webpack": "^1.8.0",
|
||||
"lite-server": "^2.2.2",
|
||||
"lodash": "^4.13.1",
|
||||
"null-loader": "^0.1.1",
|
||||
"phantomjs-prebuilt": "^2.1.7",
|
||||
@ -73,9 +73,9 @@
|
||||
"style-loader": "^0.13.1",
|
||||
"ts-loader": "^0.8.2",
|
||||
"ts-node": "^0.7.3",
|
||||
"tslint": "^3.13.0",
|
||||
"tslint": "^3.15.1",
|
||||
"typescript": "^1.8.10",
|
||||
"typings": "^1.0.4",
|
||||
"typings": "^1.3.2",
|
||||
"webpack": "^1.13.0",
|
||||
"webpack-dev-server": "^1.14.1",
|
||||
"webpack-merge": "^0.14.0"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user