Facing difficulty while importing dependency in Angular2 - angularjs

Basically I have created a sample application by referring to Angular2 quickstart tutorial. For further digging I've created ./services/dataService.ts service file like below.
import {Injectable} from 'angular2/core';
#Injectable()
export class DataService {
items: Array<number>;
constructor() {
this.items = [1, 2, 3, 4];
}
getItems() {
return this.items;
}
}
I had "outDir": "../wwwroot/app", option mentioned in tsconfig which transpile app.ts & dataService.ts to below path.
--wwwroot
|app
|--app.js
|--services
|-- dataService.js
MyAppComponent
import {Component, View, Inject, forwardRef} from 'angular2/core';
import {NgFor} from 'angular2/common';
import {bootstrap} from 'angular2/platform/browser';
import {DataService} from './services/dataService';
#Component({
'selector': 'my-app',
template: `
<div *ngFor="#item of items">
{{item}}
</div>
`,
directives: [NgFor],
providers: [DataService]
})
export class MyAppComponent {
items: Array<number>;
constructor(service: DataService) {
this.items = service.getItems();
}
}
bootstrap(MyAppComponent)
Code gets compiled with no-error, but after application Ran I got
below error, http://localhost:8413/app/services/dataService.
Failed to load resource: the server responded with a status of 404 (Not Found)
I used below code from index.html to load app files on page.
System.config({ packages: { src: { defaultExtension: 'js' } } });
System.import('app/app.js').then(null, console.error.bind(console));
My question is how could I import the dataService.js, why does is give 404 error still its there in a place? I Researched alot on this problem, but didn't find anything helpful. Any help would appreciated.
Edit
Added .tsconfig to directly get rectify when there is issue
{
"compilerOptions": {
"noImplicitAny": false,
"noEmitOnError": true,
"module": "commonjs",
"removeComments": false,
"sourceMap": true,
"target": "es5",
"outDir": "../wwwroot/app",
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"exclude": [
"node_modules",
"wwwroot"
]
}

The problem was with configuration of System, previously I was having below code to load component.
System.config({ packages: { src: { defaultExtension: 'js' } } });
System.import('app/app.js').then(null, console.error.bind(console));
Basically System.config settings tells that packages would be belongs to src folder and the files defaultExtension is js. So I changed my packages's src to app as I was having app folder, not src.
Other than that I changed System.import('app/app.js') to System.import('app/app') as default extensions of files is js, so I don't need to bother about it. So my component loading script changed to below.
System.config({ packages: { app: { defaultExtension: 'js' } } });
System.import('app/app').then(null, console.error.bind(console));

Related

import {angular} from 'angular' is not working in AngularJS(1.5)

AngularJS - 1.5
TypeScript - 1.8.10
WebPack - 1.15.0
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": true
},
"exclude": [
"node_modules",
"typings",
"dist"
],
"compileOnSave": false,
"buildOnSave": false,
"atom": { "rewriteTsconfig": false }
}
I am getting ERROR in ./src/main/frontend/app/leftmenu/index.ts
(1,21): error TS2307: Cannot find module 'angular'. while i do a npm run build
index.ts
import {angular} from 'angular';
import {MenuService} from './menuService';
import {LeftMenuController} from './leftmenu';
angular.module('tat')
.service('MenuService', MenuService)
.component('leftMenu',{
template : require('./leftmenu.html'),
controller : LeftMenuController,
controllerAs : 'lm'
});
Please tell me how do I make the angular module visible to my index.ts
Note :: The angular module is present inside the node_modules.
You should import AngularJS as a default module. Also suggest to export as default your services and components as angular modules. This let you manage all your stuff as ES6 modules.
import angular from 'angular';
import MenuServiceMod from './menuService';
import LeftMenuComponentMod from './leftmenu';
export default angular.module('tat', [
MenuServiceMod,
LeftMenuComponentMod
]);
// component leftmenu.js
const compConfig = {
template : require('./leftmenu.html'),
controller : LeftMenuController,
controllerAs : 'lm'
};
function LeftMenuController() {
// component logic
}
let compMod = angular.module('LeftMenuMod', []).component('leftMenu', compConfig);
export default compMod = compMod.name;
// service menuService.js
class MenuService {
// service logic
}
let svcMod = angular.module('MenuServiceMod', []).service('MenuService', MenuService);
export default svcMod = svcMod.name;

Why is “declare var angular” necessary when using Typescript with AngularJS?

I have a functional AngularJS 1.7 application where all my code is written in TypeScript. But something's always bothered me.
In my app.module.ts file, I have this bit of ugliness:
declare var angular;
in order for the
this.app = angular.module('app'...
to transpile and run.
Things I've tried:
1) Replacing declare var angular; with
import angular from "angular";
transpiles just fine, but then the browser complains
Uncaught (in promise) TypeError: angular_1.default.module is not a function
2) Replacing declare var angular; with
import * as angular from "angular";
also transpiles fine, but the browser gives a similar error:
Uncaught (in promise) TypeError: angular.module is not a function
3) Replacing declare var angular; with
import ng from "angular";
and then using ng.angular.module or ng.module doesn't transpile at all.
I'm sure I've tried some other things, but the only way I've ever been able to get things to work is with that declare var angular;
It all works fine, but that sure smells bad to me. Why do I have to do that? What am I doing wrong? Is there a better way to do it?
Details:
Visual Studio 2017/2019
TypeScript 3.3
SystemJS (not RequireJS)
AngularJS 1.7.8
#types/angular 1.6.54
package.json
"devDependencies": {
"#types/angular": "^1.6.54",
...
},
"dependencies": {
"angular": "~1.7.8",
...
}
tsconfig.json
{
"compileOnSave": true,
"compilerOptions": {
"baseUrl": ".",
"paths": {
"*": [ "node_modules/types/*", "node_modules/*" ],
},
"module": "system",
"target": "es6",
"sourceMap": true,
"lib": [ "es6", "dom" ],
"allowSyntheticDefaultImports": true,
"outFile": "./app/everything.js",
"moduleResolution": "node",
"types": [
"angular",
"jquery"
]
},
"include": ["app/**/*"],
"exclude": ["node_modules", "lib"],
"strict": true
}
app.module.ts
declare var angular;
...
export class App {
app: ng.IModule;
constructor() {
this.app = angular.module('app', [
...
]);
}
public run() {
this.app.run([
...
]);
...
}
index.html
...
<script src="lib/systemjs/system.js"></script>
<script src="lib/angular/angular.min.js" type="text/javascript"></script>
...
<script src="app/everything.js" type="text/javascript"></script>
<script>
System.config({
map: {
"angular": "lib/angular",
...
},
packages: {
"angular": { main: "angular.min.js", defaultExtension: "js" },
...
}
});
System.import("app.module")
.then(function (app) {
let a = new app.App();
a.run();
angular.element(function () {
angular.bootstrap(document, ['app']);
});
});
</script>
Your Typescript types, #types/angular, look for the angular variable to attach their types to.
Normally, you'd have imported angular like this: import angular from "angular" and the types would be applied to the angular variable you just created, and all would work just fine.
However, you are already loading Angular globally in your HTML <script>. In this case, you don't want to import angular from "angular" because then you will have loaded Angular more than once, and things might break.
By writing declare var angular you are simply telling Typescript to trust you that it exists, even though it hasn't seen it be imported into the scope of this file.
This means
Typescript won't complain about Angular being undefined.
#types/angular will attach to your variable angular.
When you get to runtime, assuming angular does really exist on window, then it will work.
This is a problem that will be required while you are moving to bundlers like Webpack or SystemJS. Once you remove the global Angular from index.html <script>, you can import into your TS files and delete the declare var.

Extend TypeScript 2.5.2 Component Props definition in a separate definition file

I have downloaded a NPM package called react-bootstrap-table with type definitions.
https://www.npmjs.com/package/react-bootstrap-table
https://www.npmjs.com/package/#types/react-bootstrap-table
Unfortunately the types are outdated and a prop called strictSearch is missing from BootstrapTable definitions that I need. I can of course update the definitions in node_modules but we are a team working on this project and we are not committing the node_modules folder.
I have read the thread here but I can't get it working anyway:
How do I extend a TypeScript class definition in a separate definition file?
How can I get it working?
If I add a new folder called for example "react-bootstrap-table-ex" everything looks good but of course I have no corresponding module for that.
Module not found: Error: Can't resolve 'react-bootstrap-table-ex'
If I rename my folder to react-bootstrap-table the types are only loaded from my new index.d.ts file and I cant reference the original definitions. I then tried to set the path for the original definitions manually but again the Module not found error occurs.
Module not found: Error: Can't resolve '../../../node_modules/#types/react-bootstrap-table'
Code:
import { ComponentClass, Props } from "react";
import { BootstrapTableProps, BootstrapTable } from '../../node_modules/#types/react-bootstrap-table';
export interface BootstrapTableExProps extends BootstrapTableProps {
strictSearch?: boolean;
}
export interface BootstrapTableEx extends ComponentClass<BootstrapTableExProps> {
}
declare const BootstrapTableEx: BootstrapTableEx;
Use Module Augmentation to extend existing typings. Create .ts file with the following code
import { BootstrapTableProps, BootstrapTable } from 'react-bootstrap-table';
declare module "react-bootstrap-table" {
export interface BootstrapTableExProps extends BootstrapTableProps {
strictSearch?: boolean;
}
export interface BootstrapTableEx extends ComponentClass<BootstrapTableExProps> {
}
}
New typings will be available in the entire project.
You can find more info here https://www.typescriptlang.org/docs/handbook/declaration-merging.html under Module Augmentation section.
Update:
Thanks to #niba I solved it like this, file Typings\react-bootstrap-table-ex\index.d.ts
import { BootstrapTable } from 'react-bootstrap-table';
declare module "react-bootstrap-table" {
export interface BootstrapTableProps {
strictSearch?: boolean;
}
}
Original:
Solved it by copying index.d.ts from node_modules\#types\react-bootstrap-table into Typings\react-bootstrap-table and edit the file there.
My tsconfig.json below for reference:
{
"compilerOptions": {
//baseUrl and paths needed for custom typings
"baseUrl": ".",
"paths": {
"*": [ "./Typings/*" ]
},
//We use webpack bundle instead
"outDir": "./Scripts/NotUsed",
"sourceMap": true,
"noImplicitAny": true,
"noImplicitThis": true,
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
//"experimentalDecorators": true,
"module": "commonjs",
"target": "es5",
"jsx": "react",
"lib": [ "es5", "es6", "dom" ]
},
"exclude": [
"node_modules",
"wwwroot"
]
}

systemjs-builder: Angular 2 Component Relative Paths cause 404 errors

This is a cross post to https://github.com/systemjs/builder/issues/611
I'm trying to bundle my Angular 2 rc 1 app with systemjs-builder 0.15.16 buildStatic method. An angular component has a view as well as one or more stylesheets external to the script. They are referred to within the #Component metadata in one of two ways
Using absolute paths:
#Component({
templateUrl: 'app/some.component.html',
styleUrls: ['app/some.component.css']
})
Using the now recommended relative paths:
#Component({
moduleId: module.id,
templateUrl: 'some.component.html',
styleUrls: ['some.component.css']
})
My app uses relative paths, and things have been working fine. Today I decided to use systemjs-builder's buildStatic. The resulting file throws 404 errors whenever there is a relative path because the browser is fetching localhost/some.component.html instead of localhost/app/some.component.html. Below is the relevant part of my gulpfile.js
var appDev = 'dev/';
var appProd = 'app/';
var typescript = require('gulp-typescript');
var tsProject = typescript.createProject('tsconfig.json');
var Builder = require('systemjs-builder');
var sourcemaps = require('gulp-sourcemaps');
gulp.task('build-ts', function () {
return gulp.src(appDev + '**/*.ts')
.pipe(sourcemaps.init())
.pipe(typescript(tsProject))
.pipe(sourcemaps.write())
.pipe(gulp.dest(appProd));
});
gulp.task('bundle',['build-ts'], function() {
var builder = new Builder('', './systemjs.config.js');
return builder
.buildStatic(appProd + '/main.js', appProd + '/bundle.js', { minify: false, sourceMaps: true})
.then(function() {
console.log('Build complete');
})
.catch(function(err) {
console.log('Build error');
console.log(err);
});
});
With relative paths, if I run just the build-ts gulp task and browse the "regular" way, things work. If I run the bundle gulp task and try to browse the app using the bundle.js file, the 404 errors occur wherever the app tries to load external templates and stylesheets. I've tried to be explicit about the relative nature of the paths by changing templateUrl: 'some.component.html' to templateUrl: './some.component.html' to no effect. Hard-coding absolute paths everywhere seems like a bad idea. What am I missing?
After a couple of days I got a helpful response from a systemjs member on github.
What did the trick: in the configuration object for systemjs-builder's buildStatic method, set encodeNames to false. So the line...
.buildStatic(
appProd + '/main.js',
appProd + '/bundle.js',
{ minify: false, sourceMaps: true}
)
became...
.buildStatic(
appProd + '/main.js',
appProd + '/bundle.js',
{ minify: false, sourceMaps: true, encodeNames:false}
)
Additional Info
tsconfig.json
{
"compilerOptions": {
"target": "ES5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false,
"outDir": "./app"
},
"filesGlob": [
"./dev/**/*.ts",
"!./node_modules/**/*.ts"
],
"exclude": [
"node_modules",
"typings"
]
}

Using an external HTML template in AngularJS 1.5 component with Webpack and Typescript

I am trying to load an external html file into my Angular component:
import { LoginController } from './login.controller';
import './login.scss';
import './login.html';
class LoginComponent implements ng.IComponentOptions {
public template: string;
public controller: Function;
public bindings : any;
constructor(){
this.controller = LoginController;
this.bindings = {
username: '#',
password: '#'
};
this.template = //login.html referred to here
}
}
export { LoginComponent };
I am using typescript with the following tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"sourceMap": true
},
"exclude": [
"typings/main.d.ts",
"typings/main",
"node_modules"
]
}
And am trying to load with the html-loader.
I am not sure how to reference the imported HTML in the component itself?
The webpack build is valid.
Solved it myself.
I had to add the typescript definition in my typings.json for require.
typings install --save --global require
Works like a charm now :)

Resources