I have a use case to migrate a large angularjs application and I want to start by doing this process in a small application first. So for that reason, I've took the tour of heroes angularjs webapp and I started to add angular to it ( by creating a new project with the angular-cli ) and then adding the NgUpgrade module.
The problem that I have now is that the angularjs webapp runs pretty well inside the angular 8 application but the components that belong to angular 8 they are not rendered.
I have the impression that my angular components are not bootstrapped since I've bootsraped manually angularjs but I'm not sure ... when I add explicitly the bootstrap property inside the #NgModules it works only for the angular components but not for angularjs (it makes sense ). So I was thinking maybe I have to upgrade the angularjs components or downgrade the newest angular components but I don't think so.
Here you will find the git repository with the code. Below more information related to my project:
angular version: 8.2.8
angularJS version: 1.6.10
angular-cli: 8.3.6
Project structure
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Common</title>
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" type="image/x-icon" href="favicon.ico">
</head>
<body>
<app-root></app-root>
<hero-list></hero-list>
</body>
</html>
index.ts ( angularjs root module)
// initialize root module and make it exportable to be able to bootstrap it
// inside angular
export const heroAppModule = angular.module('heroApp', [
'ngMaterial',
'perfect_scrollbar',
'ngJsTree',
'ngTagsInput',
'ui.router',
'heroApp.underscore'
]).config(['$stateProvider', function ($stateProvider) {
var heroState = {
name: 'hero',
url: '/hero',
template: '<hero-list></hero-list>'
};
$stateProvider.state(heroState);
}]);
/** start: REQUIRE ZONE for angularjs
* Add angularjs files since they aren't yet fully ES6 modules
* we use requirejs as module loader
*/
require('./editable-field/editable-field');
require('./hero-detail/hero-detail');
require('./hero-list/hero-list');
require('./underscore/underscore.module');
require('./underscore/underscore.service');
/**
* end: REQUIRE ZONE for angularjs
*/
app.module.ts ( bootstraping angularjs with NgUpgrade )
import * as angular from 'angular';
import { UpgradeModule, setAngularJSGlobal } from '#angular/upgrade/static';
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { heroAppModule } from './../ngjs/index';
import { HelloworldComponent } from './helloworld/helloworld.component';
#NgModule({
declarations: [ HelloworldComponent ],
imports: [
BrowserModule,
UpgradeModule
] // ,
// bootstrap: [HelloworldComponent]
})
export class AppModule {
constructor(private upgrade: UpgradeModule) { }
ngDoBootstrap() {
setAngularJSGlobal(angular);
this.upgrade.bootstrap(document.body, [heroAppModule.name], { strictDi: true });
}
}
main.ts
import 'zone.js/dist/zone'; // Included with Angular CLI.
import { enableProdMode } from '#angular/core';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app/ngx/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.error(err));
hero list component (angularjs)
declare var angular: angular.IAngularStatic;
(function () {
'use strict';
angular.module('heroApp').component('heroList', {
template: require('html-loader!./hero-list.html'),
controller: HeroListController,
controllerAs: 'vm'
});
HeroListController.$inject = ['$scope', '$element', '$attrs'];
function HeroListController($scope, $element, $attrs) {
var vm = this;
vm.list = [
{
name: 'Superman',
location: 'The sky'
},
{
name: 'Batman',
location: 'Baticueva'
}
];
vm.updateHero = function (hero, prop, value) {
hero[prop] = value;
};
vm.deleteHero = function (hero) {
var idx = vm.list.indexOf(hero);
if (idx >= 0) {
vm.list.splice(idx, 1);
}
};
}
})();
app-root component ( file name: helloworld.component)
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './helloworld.component.html',
styleUrls: ['./helloworld.component.scss']
})
export class HelloworldComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
app-root template
<p>helloworld works!</p>
angular.json ( angular-cli file )
{
"$schema": "./node_modules/#angular/cli/lib/config/schema.json",
"version": 1,
"newProjectRoot": "projects",
"projects": {
"common": {
"projectType": "application",
"schematics": {
"#schematics/angular:component": {
"style": "scss"
}
},
"root": "",
"sourceRoot": "src",
"prefix": "app",
"architect": {
"build": {
"builder": "#angular-devkit/build-angular:browser",
"options": {
"outputPath": "dist/common",
"index": "src/index.html",
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"aot": false,
"assets": [
"src/favicon.ico",
"src/assets" ],
"styles": [
"bower_components/jstree/dist/themes/default/style.min.css",
"bower_components/ng-tags-input/ng-tags-input.bootstrap.min.css",
"bower_components/utatti-perfect-scrollbar/css/perfect-scrollbar.css",
"bower_components/angular-material/angular-material.css",
"src/styles.scss"
],
"scripts": [
"bower_components/jquery/dist/jquery.js",
"bower_components/angular/angular.js",
"bower_components/angular-material/angular-material.js",
"bower_components/angular-animate/angular-animate.js",
"bower_components/angular-aria/angular-aria.js",
"bower_components/jstree/dist/jstree.js",
"bower_components/ng-js-tree/dist/ngJsTree.js",
"bower_components/ng-tags-input/ng-tags-input.js",
"bower_components/utatti-perfect-scrollbar/dist/perfect-scrollbar.js",
"bower_components/angular-perfect-scrollbar/src/angular-perfect-scrollbar.js",
"node_modules/#uirouter/angularjs/release/angular-ui-router.min.js",
"node_modules/underscore/underscore.js"
]
},
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"aot": true,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"budgets": [
{
"type": "initial",
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "6kb",
"maximumError": "10kb"
}
]
}
}
},
"serve": {
"builder": "#angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "common:build"
},
"configurations": {
"production": {
"browserTarget": "common:build:production"
}
}
},
"extract-i18n": {
"builder": "#angular-devkit/build-angular:extract-i18n",
"options": {
"browserTarget": "common:build"
}
},
"test": {
"builder": "#angular-devkit/build-angular:karma",
"options": {
"main": "src/test.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"src/styles.scss"
],
"scripts": []
}
},
"lint": {
"builder": "#angular-devkit/build-angular:tslint",
"options": {
"tsConfig": [
"tsconfig.app.json",
"tsconfig.spec.json",
"e2e/tsconfig.json"
],
"exclude": [
"**/node_modules/**"
]
}
},
"e2e": {
"builder": "#angular-devkit/build-angular:protractor",
"options": {
"protractorConfig": "e2e/protractor.conf.js",
"devServerTarget": "common:serve"
},
"configurations": {
"production": {
"devServerTarget": "common:serve:production"
}
}
}
}
}},
"defaultProject": "common"
}
Result...
Finally I've figured out that the solution that I need will never use both components of each framework side by side at the root of my application. Instead, I've used the following pattern as the angular documentation says:
Once you're running a hybrid app, you can start the gradual process of upgrading code. One of the more common patterns for doing that is to use an Angular component in an AngularJS context. This could be a completely new component or one that was previously AngularJS but has been rewritten for Angular.
So as my old application is written in angularjs this framework will contain always my root application and also will be the wrapper of all my future features. So If someday I decide to write a new component in Angular 8 this component will live inside angularjs and it will be downgraded to be able to make it work.
Isolate your Angular 1 code and Angular 8 code
<body>
<app-root></app-root>
<div ng-controller="MyController">
<hero-list></hero-list>
</div>
</body>
I had a similar issue, even though in my index.html I had this:
<body>
<app-root></app-root>
</body>
I found that with the setup of the Angular docs for ngUpgrade, the top-level component needs to be the one from Angular.js, not the one from Angular:
<body>
<hero-list></hero-list>
</body>
Related
I've been reading a bit about it but I don't know how to configure correctly to convert my reactjs website to PWA
I've created a workbox-config.js file at the root of my project, and a manifest.json file at the top of my App.js, but I don't know what else to do
The content of the workbox-config.js file is:
module.exports = {
"globDirectory": "dist/",
"globPatterns": [
"**/*.{html,js,css,svg,png,jpg,jpeg,gif,webp}"
],
"swDest": "dist/sw.js",
"clientsClaim": true,
"skipWaiting": true,
"navigateFallback": "/index.html",
"navigateFallbackWhitelist": [/^\/(about|contact)$/],
"runtimeCaching": [
{
"urlPattern": /^https:\/\/fonts\.googleapis\.com/,
"handler": "StaleWhileRevalidate"
},
{
"urlPattern": /^https:\/\/my-api\.com/,
"handler": "NetworkFirst",
"options": {
"cacheName": "api-cache",
"networkTimeoutSeconds": 10
}
}
]
};
I'm doing a test app with Ionic2 / Cordova / Typescript / Angular.
I'm using tslint 5.6.0.
I'm using the following module:
https://www.npmjs.com/package/tslint
Focusing on just one file...
when linting the following file:
import { NgModule, ErrorHandler } from "#angular/core";
import { BrowserModule } from "#angular/platform-browser";
import { IonicApp, IonicModule, IonicErrorHandler } from "ionic-angular";
import { MyApp } from "./app.component";
import { AboutPage } from "../pages/about/about";
import { ContactPage } from "../pages/contact/contact";
import { HomePage } from "../pages/home/home";
import { TabsPage } from "../pages/tabs/tabs";
import { StatusBar } from "#ionic-native/status-bar";
import { SplashScreen } from "#ionic-native/splash-screen";
#NgModule( {
declarations: [
MyApp,
AboutPage,
ContactPage,
HomePage,
TabsPage,
],
imports: [
BrowserModule,
IonicModule.forRoot( MyApp ),
],
bootstrap: [ IonicApp ],
entryComponents: [
MyApp,
AboutPage,
ContactPage,
HomePage,
TabsPage,
],
providers: [
StatusBar,
SplashScreen,
{ provide: ErrorHandler, useClass: IonicErrorHandler },
],
})
export class AppModule { }
I get:
The key 'bootstrap' is not sorted alphabetically
RuleFailurePosition { position: 790, lineAndCharacter: { line: 25, character: 4 } }
RuleFailurePosition { position: 799, lineAndCharacter: { line: 25, character: 13 } }
I'm using the following options:
{
"extends": "tslint:recommended",
"rules": {
"no-duplicate-variable": true,
"max-line-length": {
"options": [120]
},
"ordered-imports": false,
"new-parens": true,
"no-arg": true,
"no-bitwise": true,
"no-conditional-assignment": true,
"no-consecutive-blank-lines": false,
"no-console": {
"options": [
"debug",
"info",
"log",
"time",
"timeEnd",
"trace"
]
}
},
"jsRules": {
"max-line-length": {
"options": [120]
}
}
}
What option do I need to configure on TSLint to prevent showing up this error?
The rule failing here seems to be object-literal-sort-keys.
You should be able to disable it in the rules section of your config file by adding:
"object-literal-sort-keys": false
You can find all the tslint rules here.
For anyone coming here who is doing a migration to TypeScript from javascript, or who simply has a mixed codebase of javascript + typescriptm you may to define this rule inside 'jsRules' as well, i.e. to get rid of this error, when you having console statements defined inside javascript (not typescript files).
//tslint.json
{
"extends": ["tslint:recommended", "tslint-react", "tslint-config-prettier"],
"rules": {
"object-literal-sort-keys": false //Disable for typescript
},
"jsRules": {
"object-literal-sort-keys": false //Disable for javascript
}
}
I want to use the Materialize CSS Framework in my project.
I set up a project the Angular CLI using ng new BLABLA
After that I've followed the steps in this guide.
However, if I use ng serve to start the project, I get this error in the browser:
TypeError: undefined is not an object (evaluating 'jQuery.easing.swing')
my angular-cli.json
{
"project": {
"version": "1.0.0-beta.15",
"name": "blabla"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": "assets",
"index": "index.html",
"main": "main.ts",
"test": "test.ts",
"tsconfig": "tsconfig.json",
"prefix": "app",
"mobile": false,
"styles": [
"styles.css"
],
"scripts": [
"../node_modules/jquery/dist/jquery.js",
"../node_modules/materialize-css/dist/js/materialize.js"
],
"environments": {
"source": "environments/environment.ts",
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"addons": [],
"packages": [],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "css",
"prefixInterfaces": false
}
}
app.module.ts
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { FormsModule } from '#angular/forms';
import { HttpModule } from '#angular/http';
import { MaterializeModule } from 'angular2-materialize';
import "materialize-css";
import { AppComponent } from './app.component';
#NgModule({
declarations: [ AppComponent ],
imports: [
BrowserModule,
FormsModule,
HttpModule,
MaterializeModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
what you need to do is as follow:
add to your global css file this line:
#import "../node_modules/materialize-css/dist/css/materialize.css";
and remove this line
import "materialize-css";
from app.module.ts
also make sure you installed the correct jquery version better if you run this in any case:
npm install jquery#^2.2.4 --save
doing it worked for me. [good luck]
I also found that if you run npm rebuild after making the entries in the apps[0].scripts and apps[0].styles properties of angular-cli.json everthing works, and you don't have to add the #import to the styles.css.
I found this information on Mike Lynch's site http://mikelynchgames.com/software-development/setting-up-and-using-angular-2-cli/
Alternatively if you want to use original sass and not the DIST version of materialzie css because you might want override colors and other variables you can use this...
Import materialize css in your main styles.sass file like this.
// override fonts path to prevent build errors (or use resolve-url loader)
$roboto-font-path: "../node_modules/materialize-css/fonts/roboto/"
// optionally override color variables eg: ...
$primary-color: color("materialize-purple");
#import "~materialize-css/sass/materialize"
I am trying to build an angular 2 application using typescript in visual studio 2015 application. I am using angular release candidate 1.
I am getting the following error message in the console of my browser while running the application.
index.html:24 Error: Error: XHR error (404 Not Found) loading http://localhost:3622/app.js(…)
I cannot understand why it is trying to look for app.js file. I have set index.html as the start page.
As seen in the code below , I am trying to display data in the datatable. Is there any issue with how I have setup the systemjs.js file or with the system.import statement in index.html file
Please find my folder structure
Index.html
<!DOCTYPE html>
<html>
<head>
<title>Angular 2 Application</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://code.jquery.com/jquery-2.2.0.min.js"></script>
<!-- 1. Load libraries -->
<!-- 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="node_modules/primeui/primeui-ng-all.min.js"></script>
<!-- 2. Configure SystemJS -->
<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>
Systemjs.config.js
(function (global) {
// map tells the System loader where to look for things
var map = {
'app': 'app', // 'dist',
'rxjs': 'node_modules/rxjs',
'angular2-in-memory-web-api': 'node_modules/angular2-in-memory-web-api',
'#angular': 'node_modules/#angular',
'primeng': 'node_modules/primeng'
};
// packages tells the System loader how to load when no filename and/or no extension
var packages = {
'.': { main: 'main.js', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { defaultExtension: 'js' },
};
var packageNames = [
'#angular/common',
'#angular/compiler',
'#angular/core',
'#angular/http',
'#angular/platform-browser',
'#angular/platform-browser-dynamic',
'#angular/router',
'#angular/testing',
'#angular/upgrade',
'#angular/router-deprecated'
];
// 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' };
});
var config = {
map: map,
packages: packages
}
// filterSystemConfig - index.html's chance to modify config before we register it.
if (global.filterSystemConfig) { global.filterSystemConfig(config); }
System.config(config);
})(this);
main.ts
import { bootstrap } from '#angular/platform-browser-dynamic';
// Our main component
import { AppComponent } from './app/app.component';
bootstrap(AppComponent, []).catch(err => console.error(err));
app.component.ts
import { Component } from '#angular/core';
import { RiskListComponent } from './components/risks/risk-list.component';
import { DataTable, Column } from 'primeng/primeng';
#Component({
selector: 'my-app',
providers: [],
template: `
<div>
<h1>{{pageTitle}}</h1>
<rm-risks> </rm-risks>
</div>
` ,
directives: [RiskListComponent, DataTable, Column]
})
export class AppComponent {
pageTitle: string = 'Test UK Trader';
}
risk-list.component.ts
import { Component } from '#angular/core'
import { DataTable, Column } from 'primeng/primeng';
#Component({
selector: 'rm-risks',
directives: [DataTable, Column],
templateUrl: '/app/risks/risk-list.component.html'
})
export class RiskListComponent {
pageTitle: string = 'Risk List';
risks: any[] = [
{
"riskId": 1,
"reference": "HISC9308336",
"insuredName": "SA 84161",
"inceptionDate": "March 19, 2016",
"riskType": "Quote",
"status": "Indication",
"grossPremium": "100",
"allocatedTo": "Broker User",
"allocatedCompany": "Broker"
},
{
"riskId": 2,
"reference": "HISC9308340",
"insuredName": "Upper Loi",
"inceptionDate": "April 25, 2016",
"riskType": "Quote",
"status": "Indication",
"grossPremium": "312.22",
"allocatedTo": "Andy Marples",
"allocatedCompany": "Broker"
}
];
}
risk-list.component.html
<h3 class="first">{{pageTitle}}</h3>
<p-dataTable [value]="risks" [rows]="10" [paginator]="true" [pageLinks]="3" [rowsPerPageOptions]="[5,10,20]">
<p-column field="reference" header="Reference"></p-column>
<p-column field="insuredName" header="Insured Name"></p-column>
<p-column field="inceptionDate" header="Inception Date"></p-column>
<p-column field="riskType" header="Risk Type"></p-column>
<p-column field="status" header="Status"></p-column>
<p-column field="grossPremium" header="Gross Premium"></p-column>
<p-column field="allocatedTo" header="Allocated To"></p-column>
<p-column field="allocatedCompany" header="Allocated Company"></p-column>
</p-dataTable>
tsconfig.js
{
"compileOnSave": false,
"compilerOptions": {
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "commonjs",
"moduleResolution": "node",
"noEmitOnError": true,
"noImplicitAny": false,
"outDir": "../dist/",
"rootDir": ".",
"sourceMap": true,
"target": "es6",
"inlineSources": true
},
"exclude": [
"node_modules",
"typings",
"typings/main",
"typings/main.d.ts"
]
}
I would move the main.ts file under the app folder and import it this way:
<script>
System.import('app/main').catch(function (err) { console.error(err); });
</script>
You also need to have this configuration for SystemJS:
var packages = {
'app': { main: 'main.js', defaultExtension: 'js' },
'rxjs': { defaultExtension: 'js' },
'angular2-in-memory-web-api': { defaultExtension: 'js' },
};
Im facing a problem when I try to use browserify, angularjs and restangular.
When I try to require the npm or bower module, for example require('restangular), browserify returns empty object. This happens when i require any bower or npm modules. When I try to require any local file, everything is working fine.
file structure:
bower_components/
src/
-client
-app
app.js
backend
backend.module.js
-test
test.module.ls
test.js
node_modules/
app.js
(function() {
'use strict';
require('angular');
var rest = require('restangular');
console.log(rest);
module.exports = angular
.module('app', [
require('restangular').name,
require('./test/test.module').name,
]);
})();
package.json
"browserify": {
"transform": [
"browserify-shim"
]
},
"browser": {
"restangular": "./bower_components/restangular/dist/restangular.js"
},
"browserify-shim": {
"restangular": "restangular"
}
gulpfile.js
gulp.task('browserify', function() {
gulp.src(['./src/client/app/app.js'])
.pipe(plugins.browserify({
insertGlobals: true,
debug: true
}))
.pipe(plugins.concat('bundled.js'))
.pipe(gulp.dest('./src/client/js'))
});
Can you help me?
Thanks in advance.
Just modify your "browser" part in package.json:
"browserify-shim": {
"angular": {
"exports": "angular"
},
"restangular": {
"depends": [
"angular"
],
"exports": "restangular"
}
}
Hope it will work.
Try modifying your package.json file with this snippet.
"browser": {
"restangular": "./bower_components/restangular/dist/restangular.js"
},
"browserify-shim": {
"restangular": {
"depends": [
"angular",
"lodash:_"
],
"exports": "null"
}
}
Solution courtesy of #newtricks from this discussion