Parsing XML in typescript - node.js

Using Typescript 2.0 (tsc version 2.0.3).
I have unsuccessfully attempted to use the xml2js node library inside an angular2/typescript application (see https://www.npmjs.com/package/xml2js). Seems clear I am not familiar enough with the way the SystemJS sets up the library for consumption.
To install the xml2js library I did the following:
npm install --save xml2js
npm install --save #types/xml2js
Here are the relevant files:
tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false,
"outDir" : "build"
}
}
systemjs.config.js
/**
* System configuration for Angular samples
* Adjust as necessary for your application needs.
*/
(function (global) {
System.config({
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app: 'build',
// angular bundles
'#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-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/forms': 'npm:#angular/forms/bundles/forms.umd.js',
'#angular/upgrade': 'npm:#angular/upgrade/bundles/upgrade.umd.js',
// other libraries
'rxjs': 'npm:rxjs',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
'lodash' : 'npm:lodash',
'xml2js' : 'npm:xml2js'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './main.js',
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
},
lodash: {
main : 'index.js',
defaultExtension: 'js'
},
xml2js: {
defaultExtension: 'js'
}
}
});
})(this);
The consuming file:
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/Rx';
import * as _ from 'lodash';
import * as xml2js from 'xml2js';
#Injectable()
export class CatalogService {
constructor (private http:Http) {
}
getCatalog() {
//return Promise.resolve(['This', 'That']);
var xml = "<root>Hello xml2js!</root>"
xml2js.parseString(xml, function (err, result) {
alert(result);
});
alert(_.indexOf([1, 2, 1, 2], 2));
}
}
index.html file
<html>
<head>
<title>Angular QuickStart</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="styles.css">
<!-- 1. Load libraries -->
<!-- Polyfill 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>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<!-- 3. Display the application -->
<body>
<dsa-app>Loading DSA App...</dsa-app>
</body>
</html>
With that setup, I do get an error as follows:
zone.js:1382 GET http://localhost:3000/node_modules/xml2js/ 404 (Not Found)
The lodash library loads fine, so I am pretty sure the issue here has to do with the way the xml2js library is defined more than my setup.
Closest solution I have seen for this is a bit dated for Angular 2.0, but I put it here for reference: Use JS library xml2js with Angular 2
Although the question specifically addresses using that library, any other ideas on how to parse/convert xml into something manageable inside TypeScript would also come in handy.
Update:
As suggested I started adding "main" definitions to my systemjs configuration. However, I though part of this was that the dependencies would be loaded/figured out from the node content.
Thus modifying the system.config.js to have:
xml2js: {
main: 'lib/xml2js.js',
defaultExtension: 'js'
},
Move the issue to where now I get 404 entries for sax and xmlbuilder.
Thus, I added the following too:
sax: {
main: 'lib/sax.js',
defaultExtension: 'js'
},
xmlbuilder: {
main: 'lib/index.js',
defaultExtension: 'js'
}
Which address the sax and xmlbuilder, but then more errors popup.
I thought the whole idea with using the SystemJS and the tsconfig would be that these would be figured out from the node modules, adding all the tree dependencies on the packages seems to defeat the purpose.

I think the issue here is in your systemjs config - you haven't defined main for xml2js. Because of that systemjs doesn't know which file to load, so tries to load the NPM directory directly for some reason (loading /node_modules/xml2js as a file, which clearly isn't going to work). Note that your lodash config does specify 'index.js', presumably leading to /node_modules/lodash/index.js being loaded when you import lodash, which is why that works.
If you specify a 'main' for xml2js in your systemjs config that pointing to lib/xml2js.js then systemjs should be able to find it correctly.

As noted by #tim-perry, the issue here was the way the package was defined.
A further issue in my work is that I was making wrong assumptions about what SystemJS would do for me. I need to look into a different tool (starting with JSPM) that would do the tree walk when loading the base module. In my example, lodash was working because it is self contained. However, xml2js had a lot of dependencies, that had a lot of dependencies, that had a lot of dependencies ... thus applying the solution of adding the package definition for each dependency took care of the issue albeit in a very cumbersome way.
Again, thanks to #tim-perry and #artem who helped with this.

Related

Using bootbox in RequireJS app

I have a sample app.js file with:
requirejs.config({
"baseUrl": "js/lib",
"paths": {
"jquery": "jquery",
"app": "../app",
"bootstrap": "bootstrap/js/bootstrap.bundle",
"bootbox": "bootbox.min"
},
"shim": {
"bootstrap": {
"deps": ["jquery"],
"exports": 'bootbox'
},
"main": { "deps": ["jquery","bootstrap"] },
"bootbox": {
"deps": ["jquery","bootstrap"],
"exports": 'bootbox'
},
}
});
require(['jquery','bootstrap','bootbox'], function($){
$(function(jquery) {
bootbox.alert("bla")
});
});
When I run my page, I can see the correct JS files being grabbed:
...yet my code fails:
bootbox.alert("bla")
Gives:
ReferenceError: bootbox is not defined
I must be missing something simple (again, apologies if this is a newbie error - I'm still trying to get my head around this library)
Don't use shim with Bootbox. If you look at the source code of Bootbox, you'll see it calls define, which registers it as a proper AMD module. The shim option is only for code which is not a proper AMD module.
Now, the define in Bootbox does this:
define(["jquery"], factory);
It sets a dependency on jQuery, but that is wrong, because in fact Bootbox also depends on Bootstrap being present. So we need to fix this. The following shows how you can fix it. You can use a map configuration option so that when Bootbox requires jQuery, it gets Bootstrap. And you set a shim for Bootstrap so that, in addition to having a dependency on jQuery, its module value is the same as jQuery ($).
Without the map setup, there's no guarantee that Bootstrap will load before Bootbox and you'll be facing a race condition: sometimes it'll work, sometimes not.
requirejs.config({
baseUrl: ".",
paths: {
jquery: "//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min",
bootstrap: "//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min",
bootbox: "//github.com/makeusabrew/bootbox/releases/download/v4.4.0/bootbox.min"
},
shim: {
"bootstrap": {
"deps": ["jquery"],
// We set bootstrap up so that when we require it, the value with get is just $.
// This enables the map below.
"exports": "$"
},
},
map: {
// When bootbox requires jquery, give it bootstrap instead. This makes it so that
// bootstrap is **necessarily** loaded before bootbox.
bootbox: {
jquery: "bootstrap",
},
}
});
require(["jquery", "bootbox"], function($, bootbox) {
$(function(jquery) {
bootbox.alert("bla");
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.5/require.min.js"></script>
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />

Navigation Error in angular2

I have updated the angular packages version from 2.4.10 to 4.0.0 after updating i am getting the following errors while navigating.
ERROR Error: Uncaught (in promise): Error: Found the synthetic property #transformPlaceholder. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application.
Error: Found the synthetic property #transformPlaceholder. Please include either "BrowserAnimationsModule" or "NoopAnimationsModule" in your application
And i changed the webpack.common.js configuration. see the below code
new webpack.ContextReplacementPlugin(
// The (\\|\/) piece accounts for path separators in *nix and Windows
/angular(\\|\/)core(\\|\/)#angular/,
helpers.root('./src'), // location of your src
{} // a map of your routes
),
I have fixed the issue. I added a new package: #angular/animations.
import { BrowserAnimationsModule } from '#angular/platform-browser/animations';
And I imported the module:
#NgModule({
imports: [
BrowserAnimationsModule
]
})
It's a change from 4.0.0-rc.1.
In their words, "We have pulled Animations into their own package. This means that if you don’t use Animations, this extra code will not end up in your production bundles. This also allows you to more easily find documentation and to take better advantage of autocompletion. If you do need animations, libraries like Material will automatically import the module (once you install it via NPM), or you can add it yourself to your main NgModule."
npm install #angular/animations --save
Inside AppModule >> import {BrowserAnimationsModule} from '#angular/platform-browser/animations'
Add it to imports.
#NgModule({
imports: [
BrowserAnimationsModule
]
})
That depends on whether you want to use Angular animations or not
In case you do not want to use it (i.e. it will reduce the production bundle size) then import the NoopAnimationsModule :
import { NoopAnimationsModule } from '#angular/platform-browser/animations';
imports: [
NoopAnimationsModule
// ...
]
One can run into a problem with
import {BrowserAnimationsModule} from '#angular/platform-browser/animations';
You can get this error message:
node_modules/#angular/platform-browser‌​/bundles/platform-br‌​owser.umd.js/animati‌​ons 404 (Not Found)
To fix it, if you are using systemjs.config.js then you need to have this line it it:
'#angular/platform-browser/animations': 'npm:#angular/platform-browser/bundles/platform-browser-animations.umd.js',
Here is example contents of systemjs.config.js that fixes the problem:
/**
* System configuration for Angular samples
* Adjust as necessary for your application needs.
*/
(function (global) {
System.config({
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app: 'app',
// angular bundles
'#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-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/animations': 'npm:#angular/animations/bundles/animations.umd.js',
'#angular/animations/browser': 'npm:#angular/animations/bundles/animations-browser.umd.js',
'#angular/platform-browser/animations': 'npm:#angular/platform-browser/bundles/platform-browser-animations.umd.js',
// other libraries
'rxjs': 'npm:rxjs',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
'primeng': 'npm:primeng'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './main.js',
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
},
primeng: {
defaultExtension: 'js'
}
}
});
})(this);
Note: The references to primeng are not necessary unless you are using it. I happen to be giving it a try. (Not a recommendation)
Don't forget to add the following line in your System.config.js file. If you are going to use animations in your angular project then you need to include this lines in your angular repo.
'#angular/animations': 'npm:#angular/animations/bundles/animations.umd.js',
'#angular/animations/browser': 'npm:#angular/animations/bundles/animations-browser.umd.js',
#angular/platform-browser/animations': 'npm:#angular/platform-browser/bundles/platform-browser-animations.umd.js',

Import node module to typescript/systemjs

I am trying to use the react blueprint library, so I npm install it and then I tried to import it like:
import { Spinner } from "#blueprintjs/core"
I am getting system.src.js:1051 GET http://localhost:8888/#blueprintjs/core 404 (Not Found)
I thought that it has to do with the typings and since there is a tsfile on the module I tried
/// <reference path="../node_modules/#blueprintjs/core/dist/index.d.ts" />
or
/// <reference path="node_modules/#blueprintjs/core/dist/index.d.ts" />
I am still getting the same error. I am new to Typescript, how can I consume a node module like this?
You need to configure SystemJS so it can find and load all necessary modules in the browser. See this answer for general explanation. Here is complete minimal example that creates blueprint spinner:
install prerequisites
npm i #blueprintjs/core
npm i react
npm i react-dom
npm i react-addons-css-transition-group
npm i #types/react
npm i #types/react-dom
npm i #types/dom4
npm i typescript
npm i systemjs
example code in test.tsx
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Spinner } from "#blueprintjs/core";
const mySpinner = <Spinner/>;
ReactDOM.render(mySpinner, document.body);
example web page
<!doctype html>
<html>
<head>
<link href="node_modules/#blueprintjs/core/dist/blueprint.css" rel="stylesheet" />
<script src="node_modules/systemjs/dist/system.src.js"></script>
<script>
window.process = { env: {}};
System.config({
map: {
'react': 'node_modules/react',
'react-dom': 'node_modules/react-dom',
'react-addons-css-transition-group': 'node_modules/react-addons-css-transition-group/index.js',
'fbjs': 'node_modules/fbjs',
'tether': 'node_modules/tether/dist/js/tether.js',
'dom4': 'node_modules/dom4/build/dom4.max.js',
'#blueprintjs/core': 'node_modules/#blueprintjs/core/dist',
'classnames': 'node_modules/classnames/index.js',
'object-assign': 'node_modules/object-assign/index.js',
'pure-render-decorator': 'node_modules/pure-render-decorator/index.js'
},
packages: {
'react': { main: 'lib/React.js' },
'react-dom': { main: 'lib/ReactDOM.js' },
'fbjs': {},
'#blueprintjs/core': { main: 'index.js' },
'#blueprintjs/core/common': { main: 'index.js' },
'#blueprintjs/core/components': { main: 'index.js' }
}
});
System.import('./test.js').then(function(t) {
}).catch(function(e) {
console.error(e);
});
</script>
</head>
<body>
</body>
</html>
Note: It looks like SystemJS is unable to load react and react-dom using their bundles provided in node_modules/react/dist/react.js and node_modules/react-dom/dist/react-dom.js. It can however load everything from individual source files from node_modules/react/lib and node_modules/react-dom/lib, provided that you define process variable in the browser.

"ng2-CKEditor" node module is not working with typescript[Angular2]

I am trying to configure CKEditor in my angular2 application.
I am using node as my backend platform and i am using ng2-CKEditor npm module.
Below are my code in respective files.
index.html::
<html>
<head>
<title>Angular 2 QuickStart</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="app/images/myblog.ico" rel="icon" type="image/x-icon" />
<link rel="stylesheet" href="app/css/app.css">
<!-- 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="//cdn.ckeditor.com/4.5.6/standard/ckeditor.js"></script>
<!-- 2. Configure SystemJS -->
<script src="systemjs.config.js"></script>
<script>
System.import('app').catch(function(err){ console.error(err); });
</script>
</head>
<!-- 3. Display the application -->
<body>
<my-app>Loading...</my-app>
</body>
</html>
systemjs.config.ts::
/**
* System configuration for Angular 2 samples
* Adjust as necessary for your application needs.
*/
(function (global) {
System.config({
paths: {
// paths serve as alias
'npm:': 'node_modules/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app: 'app',
// angular bundles
'#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-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/forms': 'npm:#angular/forms/bundles/forms.umd.js',
'ng2-ckeditor': 'app/utils/ckeditor/ckeditor.js',
// other libraries
'rxjs': 'npm:rxjs',
'angular2-in-memory-web-api': 'npm:angular2-in-memory-web-api',
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './js/main',
defaultExtension: 'js'
},
rxjs: {
defaultExtension: 'js'
},
'angular2-in-memory-web-api': {
main: './index.js',
defaultExtension: 'js'
}
}
});
})(this);
main.ts::
import {NgModule} from '#angular/core';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
import { AppModule } from './app.module';
import {FormsModule} from '#angular/forms';
import {CKEditorModule} from 'ng2-ckeditor';
const platform = platformBrowserDynamic();
#NgModule({
imports: [
CKEditorModule
],
declarations: [
AppModule,
],
bootstrap: [AppModule]
})
export class AppMain { }
platform.bootstrapModule(AppModule);
app.component.ts::
import { Component } from '#angular/core';
#Component({
selector: 'my-app',
//templateUrl: 'app/templates/write-blog.html'
template: `
<ckeditor [(ngModel)]="content" debounce="500">
<p>Hello <strong>world</strong></p>
</ckeditor>
<div [innerHTML]="content"></div>`
})
export class AppComponent {
constructor(){
//this.content = '<p>Hello <strong>World !</strong></p>'
}
}
app.module.ts
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import {FormsModule} from '#angular/forms';
import {CKEditorModule} from 'ng2-CKEditor'
import { AppComponent } from './app.component';
#NgModule({
imports: [ BrowserModule, FormsModule, CKEditorModule],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }
Error::
zone.js:344 Unhandled Promise rejection: Template parse errors:
Can't bind to 'ngModel' since it isn't a known property of 'ckeditor'. ("
][(ngModel)]="content" debounce="500">
Hello world
"): AppComponent#1:14
'ckeditor' is not a known element:
1. If 'ckeditor' is an Angular component, then verify that it is part of this module.
2. If 'ckeditor' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '#NgModule.schema' of this component to suppress this message. ("
[ERROR ->]
Hello world
; Task: Promise.then ; Value: Error: Template parse errors:(…) Error: Template parse errors:
Can't bind to 'ngModel' since it isn't a known property of 'ckeditor'. ("
][(ngModel)]="content" debounce="500">
Hello world
"): AppComponent#1:14
'ckeditor' is not a known element:
1. If 'ckeditor' is an Angular component, then verify that it is part of this module.
2. If 'ckeditor' is a Web Component then add "CUSTOM_ELEMENTS_SCHEMA" to the '#NgModule.schema' of this component to suppress this message. ("
[ERROR ->]
Hello world
http://localhost:3000/node_modules/#angular/compiler/bundles/compiler.umd.js:8530:21)
at RuntimeCompiler._compileTemplate (http://localhost:3000/node_modules/#angular/compiler/bundles/compiler.umd.js:16905:53)
at eval (http://localhost:3000/node_modules/#angular/compiler/bundles/compiler.umd.js:16828:85)
at Set.forEach (native)
at compile (http://localhost:3000/node_modules/#angular/compiler/bundles/compiler.umd.js:16828:49)
at ZoneDelegate.invoke (http://localhost:3000/node_modules/zone.js/dist/zone.js:192:28)
at Zone.run (http://localhost:3000/node_modules/zone.js/dist/zone.js:85:43)
at http://localhost:3000/node_modules/zone.js/dist/zone.js:451:57
at ZoneDelegate.invokeTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:225:37)
at Zone.runTask (http://localhost:3000/node_modules/zone.js/dist/zone.js:125:47)consoleError # zone.js:344_loop_1 # zone.js:371drainMicroTaskQueue # zone.js:375ZoneTask.invoke # zone.js:297
zone.js:346 Error: Uncaught (in promise): Error: Template parse errors:(…)consoleError # zone.js:346_loop_1 # zone.js:371drainMicroTaskQueue # zone.js:375ZoneTask.invoke # zone.js:297
As i am new to angular2 with typescript and basically for MEAN stack, please help.
I check other post for the same issue but did not help to resolve my issue.
You need to add FormsModule to your module's imports in order to use ngModel directive because it is part of FormsModule:
#NgModule({
imports: [
CKEditorModule,
FormsModule
]
Your code is also very messy, you should check out official Angular 2 quickstart app to see how your code should be structured.

Loading hyperagent with require.js

I've used bower to install hyperagent, and it pulled down some dependencies, I'm just not sure how to properly initialise it now.
As far as I call tell, it doesn't support AMD loading, so I'm trying to use a shim config. I've tried a few things, looking something like this:
<script src="{{ path('root') }}bower/requirejs/require.js"></script>
<script>
require.config({
"baseUrl": "{{ url('root') }}/bower/",
paths: {
"vue": 'vue/dist/vue.min',
"hyperagent": 'hyperagent/dist/hyperagent',
"jquery": "jquery/jquery.min",
"uri": "uri.js/src/URI.min"
},
shim: {
'hyperagent': {
'deps': ['jquery', 'uri'],
'exports': 'Hyperagent'
}
}
});
</script>
When I later do
require(['vue', 'hyperagent'], function(Vue, Hyperagent) { ... });
Hyperagent is undefined.
Am I way off the mark? (Oh, and the mustaches are twig, this is a Symfony project)
Thanks to Ben Weiner for this one. Taken from here.
I installed hyperagent and URIjs via bower and for now I'm just setting window.URI as a global before requiring hyperagent. Here's the relevant part of my require.js config:
require.config({
paths: {
'hyperagent': '../bower_components/hyperagent/dist/amd/hyperagent',
'URIjs': '../bower_components/uri.js/src',
}
});
To use it I just define an amd module that returns a configured hyperagent eg configured_hyperagent.js:
define(function(require) {
window.URI = require('URIjs/URI');
window.URITemplate = require('URIjs/URITemplate');
Hyperagent = require('hyperagent');
// Hyperagent.configure() etc..
return Hyperagent;
});

Resources