I'm going to preface this question by saying that I'm fairly new to Angular 2 and Angular in general, so the odds are that this question is going to have a really easy answer. Anyway, here it is. I've been trying to a create a website, and my issue is that Angular won't insert my components. It stays at the part where it says Loading... and won't load in my things, even when they're simple HTML. I'll provide what I'm pretty sure are the pertinent files, but if you need anything more, don't hesitate to ask.
Here's systemjs.config.js:
(function (global) {
System.config({
transpiler: 'ts',
typescriptOptions: {
// Copy of compiler options in standard tsconfig.json
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es2015", "dom"],
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
},
meta: {
'typescript': {
"exports": "ts"
}
},
paths: {
// paths serve as alias
'npm:': 'https://unpkg.com/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
'app': 'app',
// angular bundles
'#angular/animations': 'npm:#angular/animations/bundles/animations.umd.js',
'#angular/animations/browser': 'npm:#angular/animations/bundles/animations-browser.umd.js',
'#angular/core': 'npm:#angular/core/bundles/core.umd.js',
'#angular/common': 'npm:#angular/common/bundles/common.umd.js',
'#angular/compiler': 'npm:#angular/compiler/bundles/compiler.umd.js',
'#angular/platform-browser': 'npm:#angular/platform-browser/bundles/platform-browser.umd.js',
'#angular/platform-browser/animations': 'npm:#angular/platform-browser/bundles/platform-browser-animations.umd.js',
'#angular/platform-browser-dynamic': 'npm:#angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'#angular/http': 'npm:#angular/http/bundles/http.umd.js',
'#angular/router': 'npm:#angular/router/bundles/router.umd.js',
'#angular/router/upgrade': 'npm:#angular/router/bundles/router-upgrade.umd.js',
'#angular/forms': 'npm:#angular/forms/bundles/forms.umd.js',
'#angular/upgrade': 'npm:#angular/upgrade/bundles/upgrade.umd.js',
'#angular/upgrade/static': 'npm:#angular/upgrade/bundles/upgrade-static.umd.js',
// other libraries
'rxjs': 'npm:rxjs#5.0.1',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
'ts': 'npm:plugin-typescript#5.2.7/lib/plugin.js',
'typescript': 'npm:typescript#2.2.1/lib/typescript.js',
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './src/bootstrap.ts',
defaultExtension: 'ts',
meta: {
'./*.ts': {
loader: 'systemjs-angular-loader.js'
}
}
},
rxjs: {
defaultExtension: 'js'
}
}
});
})(this);
systemjs-angular-loader.js:
var templateUrlRegex = /templateUrl\s*:(\s*['"`](.*?)['"`]\s*)/gm;
var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g;
var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g;
module.exports.translate = function (load) {
if (load.source.indexOf('moduleId') != -1) return load;
var url = document.createElement('a');
url.href = load.address;
var basePathParts = url.pathname.split('/');
basePathParts.pop();
var basePath = basePathParts.join('/');
var baseHref = document.createElement('a');
baseHref.href = this.baseURL;
baseHref = baseHref.pathname;
if (!baseHref.startsWith('/base/')) { // it is not karma
basePath = basePath.replace(baseHref, '');
}
load.source = load.source
.replace(templateUrlRegex, function (match, quote, url) {
let resolvedUrl = url;
if (url.startsWith('.')) {
resolvedUrl = basePath + url.substr(1);
}
return 'templateUrl: "' + resolvedUrl + '"';
})
.replace(stylesRegex, function (match, relativeUrls) {
var urls = [];
while ((match = stringRegex.exec(relativeUrls)) !== null) {
if (match[2].startsWith('.')) {
urls.push('"' + basePath + match[2].substr(1) + '"');
} else {
urls.push('"' + match[2] + '"');
}
}
return "styleUrls: [" + urls.join(', ') + "]";
});
return load;
};
index.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Website</title>
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/css/app.css" />
<base href="/">
</head>
<body>
<abi-app>Loading...</abi-app>
</body>
<!-- Libraries imports -->
<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>
<!-- Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
//bootstrap the Angular2 application
System.import('app').catch(console.log.bind(console));
</script>
<script src="http://localhost:35729/livereload.js"></script>
</html>
gulpfile.js:
var gulp = require('gulp');
var connect = require('gulp-connect');
var PATHS = {
src: 'src/**/*.ts',
html: 'src/**/*.html',
css: 'src/**/*.css'
};
gulp.task('clean', function (done) {
var del = require('del');
del(['dist'], done);
});
gulp.task('ts2js', function () {
var typescript = require('gulp-typescript');
var sourcemaps = require('gulp-sourcemaps');
var tsResult = gulp.src(PATHS.src)
.pipe(sourcemaps.init())
.pipe(typescript({
noImplicitAny: true,
module: 'system',
target: 'ES5',
moduleResolution: 'node',
emitDecoratorMetadata: true,
experimentalDecorators: true
}));
return tsResult.js
.pipe(sourcemaps.write())
.pipe(gulp.dest('dist'))
.pipe(connect.reload());
});
gulp.task('play', ['ts2js'], function () {
var http = require('http');
var open = require('open');
var watch = require('gulp-watch');
var port = 9000,
app;
connect.server({
root: __dirname,
port: port,
livereload: true,
fallback: 'index.html'
});
open('http://localhost:' + port + '/index.html');
gulp.watch(PATHS.src, ['ts2js']);
watch(PATHS.html).pipe(connect.reload());
watch(PATHS.css).pipe(connect.reload());
});
bootstrap.ts:
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './components/app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
app.module.ts:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { RouterModule } from '#angular/router';
import { HttpModule } from '#angular/http';
import { Home } from './home';
import { Gallery } from './gallery';
import { AppRoutingModule } from './app-routing.module';
import { NavigationMenuComponent } from './navigation-menu/navigation-menu.component';
import { ABIComponent } from './app.component';
import { HomeModule } from './home/home.module';
#NgModule({
imports: [BrowserModule, HttpModule, HomeModule, AppRoutingModule],
declarations: [ABIComponent, NavigationMenuComponent ],
bootstrap: [ABIComponent ]
})
export class AppModule { }
app.component.ts:
import {Component} from '#angular/core';
import { Router } from '#angular/router';
import { NavigationMenuComponent } from './navigation-menu/navigation-menu.component';
#Component({
selector: 'abi-app',
template: `<div>
<h1>Hello World!</h1>
</div>`
})
export class ABIComponent {
}
If you're interested in what the tree is of this project:
/src
--components
--- app
---- app.component.ts
---- app.module.ts
-- bootstrap.ts
/gulpfile.js
/index.html
/systemjs-angular-loader.js
/systemjs.config.js
Use #angular/cli instead of using webpack:-
https://cli.angular.io/
Related
I have a very simple project I'm using to test out webpack. When running against my code, I get 2 output files, 0.bundle.js and bundle.js.
How do I prevent this and get webpack to only output a single js file?
Folder Structure
>- dist
>- node_modules
v- src
v- libs
BlackTriangle.js
app.js
index.html
main.js
package.json
webpack.config.js
webpack.config.js
var path = require("path"),
webpack = require("webpack");
module.exports = {
entry: "./src/main.js",
devtool: "source-map",
resolve: {
extensions: [ ".js", ],
modules: [ "node_modules", ],
alias: {
"BlackTriangle" : "./libs/BlackTriangle",
},
},
output: {
path: path.join(__dirname, "dist"),
filename: "main.js",
},
module: {
rules: [
{
test: /\.js$/,
loader: "babel-loader",
options: {
presets: ["es2015"],
},
},
],
},
};
index.html
<!DOCTYPE html>
<html>
<head>
<base href="/">
<meta charset="utf-8">
<title>Webpack Black Triangle</title>
<link rel="stylesheet" type="text/css" href="main.css">
<script type="text/javascript" data-main="main" src="node_modules/requirejs/require.js"></script>
</head>
<body>
<div id="triangle" class="BlackTriangle">
<div class="BlackTriangle-inner"></div>
</div>
</body>
</html>
main.js
// Configure requirejs to work with external libraries
require.config({
//
baseUrl: "",
paths: {
"BlackTriangle" : "libs/BlackTriangle",
},
});
(function() {
"use strict";
// Call the main function when the page load has completed
if (document.readyState == "complete") {
main();
}
else if (window.addEventListener) {
window.addEventListener("load", main, false);
} else if (window.attachEvent) {
window.attachEvent("onload", main);
}
else
{
var oldOnload = window.onload;
window.onload = function() {
oldOnload();
main();
};
}
function main() {
require([ './app' ], function(app) {
app.init();
});
}
})();
app.js
define((require) => {
'use strict';
return {
init: () => {
const BlackTriangle = require("BlackTriangle");
const triangle = new BlackTriangle('#triangle');
window.setInterval(
() => {
triangle.rotate(1);
triangle.render();
},
20
);
},
};
});
BlackTriangle.js
define((require) => {
const blackTriangle = function(selector) {
this.angle = 0;
this.innerEl = document.querySelector(selector).querySelector('.BlackTriangle-inner');
};
blackTriangle.prototype.rotate = function(amount) {
this.angle = (this.angle + amount) % 360;
};
blackTriangle.prototype.render = function() {
this.innerEl.style.transform = `rotate(${this.angle}deg)`;
};
return blackTriangle;
});
You can force webpack to create only one chunk by using LimitChunkCountPlugin plugin:
plugins: [
new webpack.optimize.LimitChunkCountPlugin({
maxChunks: 1, // disable creating additional chunks
})
],
Using define instead of require fix the problem on my project (thanks #GetFuzzy)
Before:
require(["jquery"], function($) {
...
});
After:
define(["jquery"], function($) {
...
});
I am trying to build my project as a Self-Executing Bundle (SFX) with Gulp and SystemJS-Builder. When I run my gulp task, I keep getting the error, "window is not defined." I researched the issue and could not find a solution.
Here is my gulp build file
var gulp = require('gulp');
var path = require('path');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');
var Builder = require('systemjs-builder');
gulp.task('bundle:js', function () {
var builder = new Builder('MyApplication/application/source', 'MyApplication/application/source/config.js');
return builder.buildStatic('MyApplication/application/source/app.js', 'MyApplication/application/js/Site.min.js', {
format: "amd"
});
});
Here is my SystemJS configuration:
(function () {
window.define = System.amdDefine;
window.require = window.requirejs = System.amdRequire;
var kendoVersion = "2016.3.914";
var map = {
text: "../Scripts/text.js",
app: "app.js",
main: "main.js",
aes: "../../../Scripts/aes.js",
jquery: "../../../Scripts/kendo/" + kendoVersion + "/jquery.min.js",
kendo: "vendor/kendo/kendo.js",
DataTables: "../../../Scripts/DataTables/datatables.js",
k: "../../../Scripts/kendo/" + kendoVersion + "/",
bootstrap: "../../../Scripts/bootstrap.js",
lodash: "../../../Scripts/lodash.js",
moment: "../../../Scripts/moment.js",
ajaxSetup: "security/ajaxSetup.js",
q: "../../../Scripts/q.js",
toastr: "../../../Scripts/toastr.js",
wizards: "viewmodels/shared",
'kendo.core.min': "../../../Scripts/kendo/" + kendoVersion + "/kendo.core.min.js"
};
var paths = {
'kendo.*': "../../../Scripts/kendo/" + kendoVersion + "/kendo.*.js",
jquery: "../../../Scripts/kendo/" + kendoVersion + "/jquery.min.js",
bootstrap: "../../../Scripts/bootstrap.js"
};
var meta = {
app: { deps: ["kendo", "jquery"] },
main: { deps: ["jquery"] },
jquery: { exports: ["jQuery", "$"], format: "global" },
kendo: { deps: ["jquery"] },
bootstrap: { deps: ["jquery"] },
'kendo.core.min': { deps: ["jquery"] },
DataTables: { deps: ["jquery"], exports: "$.fn.DataTable" },
toastr: { deps: ["jquery"] }
};
var packages = {
pages: {
main: 'views/*.html',
format: 'amd',
defaultExtension: 'html'
}
};
var config = {
baseURL: "application/source",
defaultJSExtensions: true,
packages: packages,
map: map,
paths: paths,
meta: meta
};
System.config(config);
System.import("main");
})(this);
I load SystemJS in my index page. Here is my Index.cshtml page
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>My Application</title>
<meta name="description" content=""/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
#Styles.Render("~/application/css/site.min.css")
<script src="#Url.Content("~/Scripts/modernizr-2.8.3.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/localStoragePolyFill.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/system.js")" type="text/javascript"></script>
</head>
<body>
#Html.AntiForgeryToken()
<div id="applicationHost" class="page-wrap">
<!-- The application is rendered here -->
</div>
<script src="#Url.Content("~/application/source/config.js")" type="text/javascript"></script>
</body>
</html>
I believe the issue is this line of code in the config
window.define = System.amdDefine;
window.require = window.requirejs = System.amdRequire;
Where does the above line of code go if not in the config?
I have fixed the issue by splitting out the configuration and startup. I previously had the configuration and startup in the same file. My configuration file has configuration only, I have a separate startup file that actually starts the application.
Index.cshtml
#using System.Web.Optimization;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>My Application</title>
<meta name="description" content=""/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"/>
#Styles.Render("~/application/css/site.min.css")
<script src="#Url.Content("~/Scripts/modernizr-2.8.3.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/localStoragePolyFill.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/system.js")" type="text/javascript"></script>
</head>
<body>
#Html.AntiForgeryToken()
<div id="applicationHost" class="page-wrap">
<!-- The application is rendered here -->
</div>
<script src="#Url.Content("~/application/source/startup.js")" type="text/javascript"></script>
</body>
</html>
Startup.js
// make sure we can load AMD files
window.define = System.amdDefine;
window.require = window.requirejs = System.amdRequire;
// fire startup
window.require(["application/source/config.js"], function () {
// start app once config is done loading
System.import("main");
});
config.js
System.config({
baseURL: "application/source",
defaultJSExtensions: true,
packages:{
pages: {
main: 'views/*.html',
format: 'amd',
defaultExtension: 'html'
}
},
map: {
text: "../Scripts/text.js",
app: "app.js",
main: "main.js",
aes: "../../../Scripts/aes.js",
jquery: "../../../Scripts/kendo/2016.3.914/jquery.min.js",
kendo: "vendor/kendo/kendo.js",
DataTables: "../../../Scripts/DataTables/datatables.js",
k: "../../../Scripts/kendo/2016.3.914/",
bootstrap: "../../../Scripts/bootstrap.js",
lodash: "../../../Scripts/lodash.js",
moment: "../../../Scripts/moment.js",
ajaxSetup: "security/ajaxSetup.js",
q: "../../../Scripts/q.js",
toastr: "../../../Scripts/toastr.js",
wizards: "viewmodels/shared",
'kendo.core.min': "../../../Scripts/kendo/2016.3.914/kendo.core.min.js"
},
paths: {
'kendo.*': "../../../Scripts/kendo/2016.3.914/kendo.*.js",
jquery: "../../../Scripts/kendo/2016.3.914/jquery.min.js",
bootstrap: "../../../Scripts/bootstrap.js"
},
meta: {
app: { deps: ["kendo", "jquery"] },
main: { deps: ["jquery"] },
jquery: { exports: ["jQuery", "$"], format: "global" },
kendo: { deps: ["jquery"] },
bootstrap: { deps: ["jquery"] },
'kendo.core.min': { deps: ["jquery"] },
DataTables: { deps: ["jquery"], exports: "$.fn.DataTable" },
toastr: { deps: ["jquery"] }
}
});
I am not sure that this is the correct solution, but it did solve the "window not defined" issue.
I have created my application using systemjs...everything works fine. Now i would like to create a bundle file, but for some reason my application is requesting my module as a separate http request? I thought it should all be included in my bundle.js file? Not sure if i have set something up incorrectly?
My application is stored in the wwwroot/app folder of my application root (asp.net 5 project).
I use gulp to convert my .ts file in .js and put them into wwwroot/dist/app.
I then gulp to convert all these .js files into my bundle.js which is then stored in wwwroot/dist/bundle.js
Now when i execute the page, my bundle.js file is loaded, the .html files are requested (as expected), but a request is made for public.module? I have a feeling it is something to do with this line in the app.routing.ts file loadChildren: 'app/public.module' where the module is loaded dynamically..
I have checked my bundle.js file and no reference of PublicModule is included? Why?
systemjs.config.js
(function(global) {
// map tells the System loader where to look for things
var map = {
'app': 'app', // 'dist',
'#angular': 'node_modules/#angular',
'rxjs': 'node_modules/rxjs',
'angular2-tree-component': 'node_modules/angular2-tree-component',
'lodash': 'node_modules/lodash',
'ng2-bootstrap': 'node_modules/ng2-bootstrap',
'ng2-ckeditor': 'node_modules/ng2-ckeditor',
'ng2-file-upload': 'node_modules/ng2-file-upload',
'ng2-dnd': 'node_modules/ng2-dnd'
};
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'main.js', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'angular2-tree-component' : { main: 'dist/angular2-tree-component.js', defaultExtension: 'js' },
'lodash' : { main: 'lodash.js', defaultExtension: 'js' },
'ng2-bootstrap' : { defaultExtension: 'js' },
'ng2-ckeditor' : { main: 'lib/CKEditor.js', defaultExtension: 'js' },
'ng2-file-upload' : { main: 'ng2-file-upload.js', defaultExtension: 'js' },
'ng2-dnd': { main: 'index.js', defaultExtension: 'js'}
};
var ngPackageNames = [
'common',
'compiler',
'core',
'forms',
'http',
'platform-browser',
'platform-browser-dynamic',
'router',
'upgrade'
];
// Individual files (~300 requests):
function packIndex(pkgName) {
packages['#angular/' + pkgName] = { main: 'index.js', defaultExtension: 'js' };
}
// Bundled (~40 requests):
function packUmd(pkgName) {
packages['#angular/' + pkgName] = { main: 'bundles/' + pkgName + '.umd.js', defaultExtension: 'js' };
}
// Most environments should use UMD; some (Karma) need the individual index files
var setPackageConfig = System.packageWithIndex ? packIndex : packUmd;
// Add package entries for angular packages
ngPackageNames.forEach(setPackageConfig);
System.config({
defaultJSExtensions: true,
map: map,
packages: packages
});
})(this);
gulpfile.js
var gulp = require('gulp'),
path = require('path'),
Builder = require('systemjs-builder'),
ts = require('gulp-typescript'),
sourcemaps = require('gulp-sourcemaps'),
sass = require('gulp-sass'),
rename = require('gulp-rename'),
concat = require('gulp-concat'),
cleanCSS = require('gulp-clean-css');
var tsProject = ts.createProject('tsconfig.json');
// copy library files
gulp.task('copy:libs', function() {
gulp.src([
'node_modules/core-js/client/shim.min.js',
'node_modules/zone.js/dist/zone.js',
'node_modules/reflect-metadata/Reflect.js',
'node_modules/systemjs/dist/system.src.js',
'node_modules/ckeditor/ckeditor.js'
]).pipe(gulp.dest('wwwroot/dist/lib'));
return gulp.src('node_modules/font-awesome/**/*', { base: 'node_modules' })
.pipe(gulp.dest('wwwroot/dist/lib'));
});
/** first transpile your ts files */
gulp.task('ts', function() {
return gulp.src('wwwroot/app/**/*.ts')
.pipe(sourcemaps.init({
loadMaps: true
}))
.pipe(ts(tsProject))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('wwwroot/dist/app'));
});
/** then bundle */
gulp.task('bundle', ['ts'], function() {
// optional constructor options
// sets the baseURL and loads the configuration file
var builder = new Builder('', 'systemjs.config.js');
/*
the parameters of the below buildStatic() method are:
- your transcompiled application boot file (the one wich would contain the bootstrap(MyApp, [PROVIDERS]) function - in my case 'dist/app/boot.js'
- the output (file into which it would output the bundled code)
- options {}
*/
return builder.buildStatic('wwwroot/dist/app/*.js', 'wwwroot/dist/bundle.js', { minify: false, sourceMaps: true})
.then(function() {
console.log('Build complete');
})
.catch(function(err) {
console.log('Build error');
console.log(err);
});
});
// create css file
gulp.task('css', function () {
return gulp.src('wwwroot/sass/app.scss')
.pipe(sass())
.pipe(concat('app.css'))
.pipe(gulp.dest('wwwroot/dist/css'))
.pipe(cleanCSS())
.pipe(rename('app.min.css'))
.pipe(gulp.dest('wwwroot/dist/css'));
});
/** this runs the above in order. uses gulp4 */
gulp.task('build', ['ts', 'bundle', 'copy:libs']);
index.html
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
<link rel="shortcut icon" type="image/x-icon" href="#Html.Raw(ViewBag.BaseUrl)favicon.ico" />
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,600,700" rel="stylesheet" type="text/css" />
<link href="~/dist/css/app.min.css" rel="stylesheet" type="text/css" />
<link href="~/dist/lib/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
<!-- 1. Load libraries -->
<script src="~/dist/lib/ckeditor.js"></script>
<!-- Polyfill(s) for older browsers -->
<script src="~/dist/lib/shim.min.js"></script>
<script src="~/dist/lib/zone.js"></script>
<script src="~/dist/lib/reflect.js"></script>
<script src="~/dist/lib/system.src.js"></script>
</head>
<!-- 3. Display the application -->
<body>
<my-app>Loading...</my-app>
<script src="~/dist/bundle.js"></script>
</body>
</html>
main.ts
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { CollapseModule } from 'ng2-bootstrap/components/collapse';
import { routing } from './app.routing';
import { AppComponent } from './app.component';
import { PublicComponent } from './public.component';
import { ProtectedComponent } from './protected.component';
#NgModule({
imports: [ BrowserModule, FormsModule, HttpModule, routing, CollapseModule ],
declarations: [ AppComponent, PublicComponent, ProtectedComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
app.routing.ts
import { Routes, RouterModule } from '#angular/router';
// public
import { PublicComponent } from './public.component';
import { ProtectedComponent } from './protected.component';
const appRoutes: Routes = [
{
path: '',
component: PublicComponent,
loadChildren: 'app/public.module'
},
{
path: 'admin',
component: ProtectedComponent,
loadChildren: 'app/protected.module'
}
];
export const routing = RouterModule.forRoot(appRoutes);
This looks clearly a bug in systemjs-builder.
https://github.com/systemjs/builder/issues/728
The workaround is adding '.js' in all import statement.
e.g.
import { AppModule } from './app.module';
needs to be
import { AppModule } from './app.module.js';
It worked for me with this solution.
The problem is that in routing i have to click twice to trigger ngOnInit code.
The weird thing is, if I have two routes: A and B, and I clicked on A first, it will trigger the constructor only, and if I clicked on B after it, it will trigger A's onInit before calling B's constructor.
using angular 2.0.0-rc.4 and routes 3.0.0-beta.2
error displayed on page load:
vendors.js:2291 Unhandled promise rejection Error: Cannot match any routes: ''
at Observable._subscribe (http://localhost:54037/js/app.js:19280:28)
at Observable.subscribe (http://localhost:54037/js/app.js:56291:60)
at Observable._subscribe (http://localhost:54037/js/app.js:56328:26)
at MergeMapOperator.call (http://localhost:54037/js/app.js:26178:21)
at Observable.subscribe (http://localhost:54037/js/app.js:56291:36)
at Observable._subscribe (http://localhost:54037/js/app.js:56328:26)
at MergeMapOperator.call (http://localhost:54037/js/app.js:26178:21)
at Observable.subscribe (http://localhost:54037/js/app.js:56291:36)
at Observable._subscribe (http://localhost:54037/js/app.js:56328:26)
at MapOperator.call (http://localhost:54037/js/app.js:56831:21)
gulp file
/// <binding Clean='default, clean, resources' />
/*
This file in the main entry point for defining Gulp tasks and using Gulp plugins.
Click here to learn more. http://go.microsoft.com/fwlink/?LinkId=518007
*/
var gulp = require('gulp');
var sourcemaps = require('gulp-sourcemaps');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var typescript = require('gulp-typescript');
var systemjsBuilder = require('systemjs-builder');
const del = require("del");
// Compile TypeScript app to JS
gulp.task('compile:ts', function () {
return gulp
.src([
"appTS/**/*.ts",
"typings/*.d.ts"
])
.pipe(sourcemaps.init())
.pipe(typescript({
"module": "system",
"moduleResolution": "node",
"outDir": "app",
"target": "ES5"
}))
.pipe(sourcemaps.write('.'))
.pipe(gulp.dest('app'));
});
// Generate systemjs-based bundle (app/app.js)
gulp.task('bundle:app', function () {
var builder = new systemjsBuilder('./', './system.config.js');
return builder.buildStatic('app', 'wwwroot/js/app.js');
});
// Copy and bundle dependencies into one file (vendor/vendors.js)
// system.config.js can also bundled for convenience
gulp.task('bundle:vendor', function () {
return gulp.src([
'node_modules/core-js/client/shim.min.js',
'node_modules/systemjs/dist/system-polyfills.js',
'node_modules/reflect-metadata/Reflect.js',
'node_modules/zone.js/dist/zone.js',
'node_modules/systemjs/dist/system.js',
'system.config.js'
])
.pipe(concat('vendors.js'))
.pipe(gulp.dest('build'));
});
// Copy dependencies loaded through SystemJS into dir from node_modules
gulp.task('copy:vendor', function () {
return gulp.src([
'node_modules/rxjs/bundles/Rx.js',
'node_modules/#angular/**/*'
])
.pipe(gulp.dest('build'));
});
gulp.task('vendor', ['bundle:vendor', 'copy:vendor']);
gulp.task('app', ['compile:ts', 'bundle:app']);
// Bundle dependencies and app into one file (app.bundle.js)
gulp.task('bundle', ['vendor', 'app'], function () {
return gulp.src([
'build/app.js',
'build/vendors.js'
])
.pipe(concat('app.bundle.js'))
.pipe(gulp.dest('wwwroot/js/app'));
});
/**
* Copy all resources that are not TypeScript files into build directory.
*/
gulp.task("resources", () => {
return gulp.src(["Scripts/app/**/*", "!**/*.ts"])
.pipe(gulp.dest("wwwroot/app"));
});
/**
* Remove build directory.
*/
gulp.task('clean', (cb) => {
return del(["build"], cb);
});
gulp.task('default', ['bundle']);
app.routes
import { provideRouter, RouterConfig } from '#angular/router';
import { MediaItemFormComponent } from './media-item-form.component';
import { MediaItemListComponent } from './media-item-list.component';
export const routes: RouterConfig = [
{ path: 'list', component: MediaItemListComponent },
{ path: 'add', component: MediaItemFormComponent }
];
export const APP_ROUTER_PROVIDERS = [
provideRouter(routes)
];
list component
import {Component, Inject, OnInit } from '#angular/core';
import 'rxjs/Rx';
import {MediaItemComponent} from './media-item.component';
import {CategoryListPipe} from './category-list.pipe';
import {MediaItemService} from './media-item.service';
#Component({
selector: 'media-item-list',
directives: [MediaItemComponent],
pipes: [CategoryListPipe],
providers: [MediaItemService],
templateUrl: 'app/media-item-list.component.html',
styleUrls: ['app/media-item-list.component.css']
})
export class MediaItemListComponent implements OnInit {
mediaItems;
constructor(private mediaItemService: MediaItemService) {
console.log("constructor MediaItemList");
}
ngOnInit() {
console.log("ngOnInit MediaItemList");
this.getMediaItem();
}
onMediaItemDeleted(mediaItem) {
this.mediaItemService.delete(mediaItem)
.subscribe(() => {
this.getMediaItem();
});
}
getMediaItem() {
this.mediaItemService.get().subscribe(mediaitems => {
this.mediaItems = mediaitems;
},
function (error) { console.log("Error happened" + error) },
function () {
}
);
}
}
system.js
// map tells the System loader where to look for things
var map = {
'app': 'Scripts/app',
'rxjs': 'node_modules/rxjs',
'#angular': 'node_modules/#angular'
};
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'app': { main: 'main', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
};
var packageNames = [
'#angular/common',
'#angular/compiler',
'#angular/core',
'#angular/forms',
'#angular/http',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
'#angular/router',
'#angular/testing',
'#angular/upgrade',
];
// add package entries for angular packages in the form '#angular/common': { main: 'index.js', defaultExtension: 'js' }
packageNames.forEach(function (pkgName) {
packages[pkgName] = { main: 'index.js', defaultExtension: 'js' };
});
System.config({
map: map,
packages: packages
});
index.html
<html>
<head>
<title>MeWL</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<base href="/" />
<link href="resets.css" rel="stylesheet">
<script src="js/vendors.js"></script>
<script src="js/app.js"></script>
<style>
body {
margin: 0px;
padding: 0px;
background-color: #32435b;
}
</style>
</head>
<body>
<media-tracker-app>Loading...</media-tracker-app>
</body>
</html>
Update:
I'll include html of list and the component nested inside if it helps
<media-item
*ngFor="let mediaItem of mediaItems"
[mediaItemToWatch] ="mediaItem"
(deleted)="onMediaItemDeleted($event)"
[ngClass]="{'medium-movies': mediaItem.medium === 'Movies', 'medium- series' : mediaItem.medium === 'Series'}" ></media-item>
MediaItem html:
<h2>{{mediaItem.name }}</h2>
<div>{{mediaItem.category}}</div>
<div>{{mediaItem.year}}</div>
<div class="tools">
<a class="delete" (click)="onDelete()">
remove
</a>
<a class="details">
watch
</a>
</div>
Media Item ts:
import {Component, Input, Output, EventEmitter} from '#angular/core';
import {FavoriteDirective} from './favorite.directive';
#Component({
selector: 'media-item',
directives: [FavoriteDirective],
templateUrl: 'app/media-item.component.html',
styleUrls: ['app/media-item.component.css']
})
export class MediaItemComponent {
#Input('mediaItemToWatch') mediaItem;
#Output('deleted') delete = new EventEmitter();
onDelete() {
this.delete.emit(this.mediaItem);
}
}
It seems
vendors.js:2291 Unhandled promise rejection Error: Cannot match any routes: ''
causes change detection to not run
To avoid this error add a route for the '' path like
{ path: '', redirectTo: '/list', pathMatch: 'full' }
or
{ path: '', component: DummyComponent, pathMatch: 'full' }
I think better answer is to add "onSameUrlNavigation" option on
RouterModule.forRoot(
appRoutes,
{
useHash: false,
anchorScrolling: "enabled",
onSameUrlNavigation: "reload",
enableTracing: true,
scrollPositionRestoration: "enabled"
})
I saw in this post that you can use SystemJS to load external javascript files into my components in Angular 2.
In my index.html :
<script>
System.config({
packages: {
"frontOfficeA2/src": {
format: 'register',
defaultExtension: 'js'
},
"angular2-jwt": {
"defaultExtension": "js"
},
"ng2-bootstrap": {
"defaultExtension": "js"
},
"system": {
"defaultExtension": "js"
}
},
map: {
"angular2-jwt": "lib/angular2-jwt",
"ng2-bootstrap": "lib/ng2-bootstrap",
"moment": 'lib/moment/moment.js',
"system": 'lib/systemjs/dist/system.src.js'
}
});
System.import('frontOfficeA2/src/app.js').then(null, console.error.bind(console));
</script>
And my component :
import {Component} from 'angular2/core';
import { DATEPICKER_DIRECTIVES } from 'ng2-bootstrap/ng2-bootstrap';
import { System } from 'system';
#Component({
selector: 'main',
templateUrl: 'app/components/main/main.html',
styleUrls: ['app/components/main/main.css'],
providers: [],
directives: [DATEPICKER_DIRECTIVES],
pipes: []
})
export class Main {
date: Date = new Date();
constructor() {
System.import('path/to/your/file').then(refToLoadedScript => {
refToLoadedScript.someFunction();
});
}
}
Finally, when I start my app :
frontOfficeA2/src/app/components/main/main.ts(3,24): error TS2307: Cannot find module 'system'.
If somebody have an idea of what am I doing wrong .. :)
Thanks :)
In fact, SystemJS is used under the hood when you import things. It's because you configured your TypeScript compiler to use it. See the tsconfig.json file:
{
"compilerOptions": {
"target": "ES5",
"module": "system", <---------------
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false
},
"exclude": [
"node_modules"
]
}
If you have a look at compiled JS files (these JS files are actually executed in the browser), you will see this:
System.register(['angular2/platform/browser', 'angular2/http', './app.component'], function(exports_1) {
var browser_1, http_1, app_component_1;
return {
setters:[
function (browser_1_1) {
browser_1 = browser_1_1;
},
function (http_1_1) {
http_1 = http_1_1;
},
function (app_component_1_1) {
app_component_1 = app_component_1_1;
}],
execute: function() {
browser_1.bootstrap(app_component_1.AppComponent, [http_1.HTTP_PROVIDERS]).then(function (componentRef) {
console.log(componentRef.injector);
});
}
}
});
for a TypeScript file like this:
import {bootstrap} from 'angular2/platform/browser';
import {HTTP_PROVIDERS} from 'angular2/http';
import {AppComponent} from './app.component';
bootstrap(AppComponent, [ HTTP_PROVIDERS ]).then((componentRef) => {
console.log(componentRef.injector);
});
You can use systemjs to do your external dependency loading.
npm i systemjs --save-dev
npm i #types/systemjs --save-dev
You'll need to update your tsconfig.app.json file (tsconfig.json file for older versions of Angular).
"types": ["systemjs"]
Now you'll be able to import
System.import("your-url").then(response => response.methodCall());
If you have an import map specified
<script type="systemjs-importmap">
{
"imports": {
"import-name": "external-code-url",
}
}
</script>
You can instead call this code
System.import("import-name").then(response => responce.methodCall());