My first angular app does not work as expected - html

I started to play around with Angular, I downloaded all the relevant stuff, but I'm getting the following output (I should see some name instead of {{ name }}):
Here is app.component.html:
<input type="text" [(ngModel)]="name">
<p>{{ name }}</p>
Here is app.component.ts:
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.styl']
})
export class AppComponent {
name = 'ddd';
}
Here is app.component.spec.ts:
import { TestBed, async } from '#angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'my-first-app'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('my-first-app');
});
it('should render title in a h1 tag', () => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('Welcome to my-first-app!');
});
});

Couple of things you can check:
Debugging starts from Browser's console tab. Check if you've an error. If yes then click on that error. Angular doc will guide you what mistakes you've made.
Check if you have imported FormsModule in you app.module.ts file.
Alternatively, You can verify if you've a successful started the initial project like this also (this will also confirm that you've error with FormsModule):
In app.component.html file
<input (keyup)="onKey($event)">
<p>{{values}}</p>
In app.component.ts file
values = '';
onKey(event: any) { // without type info
this.values += event.target.value + ' | ';
}
Write something and check if this works. If yes then you've error with FormsModule and not with Angular project.
Note: just to verify in start you can disable the test cases.

A very good start is using the cli to initialize your project.
The Angular CLI makes it easy to create an application that already
works, right out of the box. It already follows our best practices!
First
npm install -g #angular/cli
Then
ng new my-dream-app
Then
cd my-dream-app
Finally
ng serve

Related

How to call Firebase Cloud Functions from Angular and AngularFire?

I'm trying to understand the AngularFireFunctions documentation. I made a new Angular project and a new Firestore database, installed AngularFire and Firebase, hooked up the Firebase credentials to environments.ts, and initialized firebase-functions, firebase-admin, and firestore.
I fixed a bug in functions/package.json. The initialization program creates this line:
"main": "lib/index.js",
which should be
"main": "src/index.ts",
My directory structure looks like this:
myproject
+- .firebaserc # Hidden file that helps you quickly switch between
| # projects with `firebase use`
|
+- firebase.json # Describes properties for your project
|
+- functions/ # Directory containing all your functions code
|
+- node_modules/ # directory where your dependencies (declared in # package.json) are installed
|
+- package-lock.json
|
+- src/
|
+- index.js # main source file for your Cloud Functions code
|
+- tsconfig.json # if you chose TypeScript
|
+- package.json # npm package file describing your Cloud Functions code
I spun up a new Angular project and set up app.module.ts exactly as the AngularFireFunctions documentation recommends:
import { BrowserModule } from '#angular/platform-browser';
import { NgModule } from '#angular/core';
import { AppComponent } from './app.component';
import { AngularFireModule } from '#angular/fire/compat';
import { AngularFireFunctionsModule, USE_EMULATOR } from '#angular/fire/compat/functions';
import { environment } from '../environments/environment';
#NgModule({
imports: [
BrowserModule,
AngularFireModule.initializeApp(environment.firebase),
AngularFireFunctionsModule
],
declarations: [ AppComponent ],
bootstrap: [ AppComponent ],
providers: [
{ provide: USE_EMULATOR, useValue: ['localhost', 5001] }
]
})
export class AppModule {}
I made a button in my HTML view to call the Firebase Cloud Function:
<div>
<button mat-raised-button color="basic" (click)='callMe()'>Call me!</button>
</div>
I imported firebase-functions and firebase-admin into index.ts as the documentation recommends. Then I uncommented the default function that comes with index.ts and added a console.log.
// The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
const functions = require('firebase-functions');
// The Firebase Admin SDK to access Firestore.
const admin = require('firebase-admin');
admin.initializeApp();
export const helloWorld = functions.https.onRequest((request, response) => {
console.log("Hello world!")
functions.logger.info("Hello logs!", {structuredData: true});
response.send("Hello from Firebase!");
});
Finally we get to app.component.ts. I don't understand the provided code in the documentation and it throws errors so I wrote my own controller:
import { Component } from '#angular/core';
import { AngularFireFunctions } from '#angular/fire/compat/functions';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private fns: AngularFireFunctions) {}
callMe() {
console.log("Calling...");
this.fns.httpsCallable('helloWorld');
}
}
When I run firebase emulators:start I see an error message:
functions: Failed to load function definition from source: FirebaseError: Failed to load function definition from source: Failed to generate manifest from function source: SyntaxError: Unexpected token 'export'
It's objecting to these lines in app.module.ts and app.component.ts:
export class AppModule {}
export class AppComponent {}
Those aren't errors and the emulator recovers and starts up.
✔ All emulators ready! It is now safe to connect your app. │
│ i View Emulator UI at http://localhost:4000
I click the button in my HTML view, see Calling... in the console log, and nothing happens in the emulator log. I was expecting to see Hello world in the emulator logs. Why doesn't my Angular app call the Firebase Cloud Function?
This does not define a callable function: functions.https.onRequest. It instead defines a regular HTTP function, which you can invoke with something like fetch.
Callable Cloud Functions are defined with functions.https.onCall. To implement a callable function, have a look at the documentation on writing a callable Cloud Function.
In addition this code does not invoke the function yet, but instead merely looks it up:
this.fns.httpsCallable('helloWorld');
To invoke it, you'll need to invoke it with some extra parenthesis, or store it in a variable and then invoke it as shown in the docs.
const callable = fns.httpsCallable('my-fn-name');
this.data$ = callable({ name: 'some-data' });
I've written a tutorial that answers this question. Here's the app.module.ts:
import { NgModule } from '#angular/core';
import { BrowserModule } from '#angular/platform-browser';
import { AppComponent } from './app.component';
import { environment } from '../environments/environment';
// AngularFire 7
// import { initializeApp, provideFirebaseApp } from '#angular/fire/app';
// import { provideFirestore, getFirestore } from '#angular/fire/firestore';
// import { provideFunctions, getFunctions, connectFunctionsEmulator } from '#angular/fire/functions'; // https://firebase.google.com/docs/emulator-suite/connect_functions#instrument_your_app_to_talk_to_the_emulators
// AngularFire 6
import { AngularFireModule } from '#angular/fire/compat';
import { AngularFireFunctionsModule } from '#angular/fire/compat/functions';
import { USE_EMULATOR } from '#angular/fire/compat/functions'; // comment out to run in the cloud
#NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
// AngularFire 7
// provideFirebaseApp(() => initializeApp(environment.firebase)),
// provideFirestore(() => getFirestore()),
// provideFunctions(() => getFunctions()),
// AngularFire 6
AngularFireModule.initializeApp(environment.firebase),
AngularFireFunctionsModule
],
providers: [
{ provide: USE_EMULATOR, useValue: ['localhost', 5001] } // comment out to run in the cloud
],
bootstrap: [AppComponent]
})
export class AppModule { }
This uses AngularFire 6. I haven't been able to get AngularFire 7 to work with callable functions.
This runs the functions in the emulator. To run your functions in the cloud comment out two lines.
Here's app.component.ts:
import { Component } from '#angular/core';
// AngularFire 7
// import { getApp } from '#angular/fire/app';
// import { provideFunctions, getFunctions, connectFunctionsEmulator, httpsCallable } from '#angular/fire/functions'; // https://firebase.google.com/docs/emulator-suite/connect_functions#instrument_your_app_to_talk_to_the_emulators
// import { Firestore, doc, getDoc, getDocs, collection, updateDoc } from '#angular/fire/firestore';
// AngularFire 6
import { AngularFireFunctions } from '#angular/fire/compat/functions';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
})
export class AppComponent {
data$: any;
constructor(private functions: AngularFireFunctions) {
const callable = this.functions.httpsCallable('executeOnPageLoad');
this.data$ = callable({ name: 'Charles Babbage' });
}
callMe() {
console.log("Calling...");
const callable = this.functions.httpsCallable('callMe');
this.data$ = callable({ name: 'Ada Lovelace' });
};
}
Again this AngularFire 6. The variable data$ handles the data returned from the cloud function.
httpsCallable takes one parameter, the name of the function.
callable executes the function and takes one parameter, an object holding the data to send to the function.
The HTML view:
<div>
<button mat-raised-button color="basic" (click)='callMe()'>Call me!</button>
</div>
{{ data$ | async }}
The view show a button for the user the click and the data returned from the function.
And the index.js cloud functions:
// The Cloud Functions for Firebase SDK to create Cloud Functions and set up triggers.
const functions = require('firebase-functions');
// The Firebase Admin SDK to access Firestore.
const admin = require('firebase-admin');
admin.initializeApp();
// executes on page load
exports.executeOnPageLoad = functions.https.onCall((data, context) => {
console.log("The page is loaded!")
console.log(data);
console.log(data.name);
// console.log(context);
return 22
});
// executes on user input
exports.callMe = functions.https.onCall((data, context) => {
console.log("Thanks for calling!")
console.log(data);
console.log(data.name);
// console.log(context);
return 57
});
Each functions uses https.onCall((data, context) => {} to make it a callable function, i.e., callable from Angular. data is the data sent from Angular. context is metadata about the execution of the function. Each function returns data, which is displayed in the HTML view.
To run the functions use the emulator:
firebase emulators:start --only functions

How to make a connection between ionic 4 client app and express server?

I'm trying to make a connection between a server and client app using ionic 4, node.js and express. Of course I will need to insert the data into the data base using Mysql, but once I can receive data from client app to server api the rest should not be that difficult. How to make communication between ionic 4 app and express js server?
Most of the tutorial I found online are either focus on the server side or client side. The once touching both are either quit complex for a beginner or using prior versions of technologies. Ionic 3 for exemple or so.
I have been working on this for a couple of days now. Please notice that I'm a beginner with those technology therefore I'm trying just something simple. The purpose here is to bring communication.
What I did so far:
- I create the client project:
- Imported HttpClientModule in the app.module.ts file
- I created services folder and added a service user using the command:
ionic g service services/user
-I imported HttpCLient in services/user.service.ts file
-I have my home page where I created a simple login form with a button and declare the [(ngModel)]s variables in home.page.ts and the function...
In the other hand, I created the server app in a different folder.
I kept everything simple because the purpose here is to understand and make the connection work. So please while helping try to keep the code simple and remind with the technologies mentioned above as possible.
here something to help you see how the project is organized:
//Client app:
//home.page.ts
import { Component } from '#angular/core';
import { UserService } from '../services/user.service';
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
login: string;
pwd: any;
constructor(private service: UserService) {
}
confirmer() {
const logins = {
"user": this.login,
"pwd": this.pwd
}
this.service.confirm(logins);
}
}
//home.page.html
<ion-content>
Hello
<ion-input type="text" [(ngModel)]="login"></ion-input>
<ion-input type="password" [(ngModel)]="pwd"></ion-input>
<ion-button (click)="confirmer()">Confirmer</ion-button>
</ion-content>
//app.module.ts
import { HttpClientModule } from '#angular/common/http';
#NgModule({
declarations: [AppComponent],
entryComponents: [],
imports: [BrowserModule, HttpClientModule, IonicModule.forRoot(), AppRoutingModule],
providers: [
StatusBar,
SplashScreen,
{ provide: RouteReuseStrategy, useClass: IonicRouteStrategy }
],
bootstrap: [AppComponent]
})
export class AppModule {}
//user.service.ts
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class UserService {
user: string;
pwd: any;
constructor(private httpClient: HttpClient) { }
confirm(user) {
return this.httpClient.post('127.0.0.1:300/login', user);
}
}
//Server side:
//app.js
const express = require('express');
const mysql = require('mysql');
const app = express();
app.listen(3000, function (req, res) {
console.log('listening...');
});
app.post('/login', function (req, res) {
console.log("Got a POST request for /login page");
res.send('Hello POST');
console.log('Post request...');
})
I'm getting no error at all. These guys seem to work well on their own. There's definitely something that I didn't understand. Please keep the answers as simple possible as I'm not using error handling, storage or whatever. I just want the server to get login and password when user click on "confirmer" button. Thanks ahead of time.
It was cors issue. Though I adjusted a little the entire code, I had to execute this command on the server side: npm install --save body-parser cors del express method-override morgan and added this code: const bodyParser = require('body-parser'); const logger = require('morgan'); const methodOverride = require('method-override') const cors = require('cors'); app.use(logger('dev')); app.use(bodyParser.json()); app.use(methodOverride()); app.use(cors()); Hope it helps someone in the future –

Vue.js: Failed to generate render function

I try to run a simple Vue.js, but I constantly receive the following error:
[Vue warn]: It seems you are using the standalone build of Vue.js in
an environment with Content Security Policy that prohibits
unsafe-eval. The template compiler cannot work in this environment.
Consider relaxing the policy to allow unsafe-eval or pre-compiling
your templates into render functions.
main.js:3180 [Vue warn]: Failed to generate render function:
EvalError: Refused to evaluate a string as JavaScript because
'unsafe-eval' is not an allowed source of script in the following
Content Security Policy directive: "default-src 'self'". in
with(this){return _c('div',{attrs:{"id":"app"}})}
(found in )
Yet, I can't understand what is causing this error. I don't seem to use any dynamic templates and everything should be pre-compiled. Here is the code of my application:
import Vue from 'vue'
import VueRouter from 'vue-router'
const Home = Vue.component('home-component', {
render() {
return <div>
<router-link to="/users">Users</router-link>
<router-link to="/about">About</router-link>
</div>
}
})
const Users = Vue.component('users-component', {
render() {
return <p>Users</p>
}
})
const NotFound = Vue.component('not-found-component', {
render() {
return <p>Not Found</p>
}
})
const routes = [
{ path: '/', component: Home },
{ path: '/users', component: Users }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')
And here is how I process JavaScript files in my gulpfile:
const paths = {
main: 'web/javascript/src/main.js',
allJs: 'web/javascript/**/*.{js,vue}',
resultJs: 'public/assets/javascript/main.js',
};
gulp.task('scripts', function() {
return browserify(paths.main)
.transform(babelify, { presets: ['es2015'], plugins: ["transform-runtime"] })
.transform(vueify)
.bundle()
.pipe(fs.createWriteStream(paths.resultJs))
}
There are seem to be many similar questions on StackOverflow, but none of them helped me.
The broweser is throwing Content Security Policy (CSP) error, to get around this issue you should consider switching to the runtime-only build, which is fully CSP-compliant.
https://v2.vuejs.org/v2/guide/installation.html#CSP-environments
Also, You have return incorrectly written. It should return jsx in pair of paranthesis (). The code below should help
import Vue from 'vue'
import VueRouter from 'vue-router'
const Home = Vue.component('home-component', {
render(h) {
return(
<div>
<router-link to="/users">Users</router-link>
<router-link to="/about">About</router-link>
</div>
)
}
})
const Users = Vue.component('users-component', {
render(h) {
return(
<p>Users</p>
)
}
})
const NotFound = Vue.component('not-found-component', {
render(h) {
return(
<p>Not Found</p>
)
}
})
const routes = [
{ path: '/', component: Home },
{ path: '/users', component: Users }
]
const router = new VueRouter({
routes
})
const app = new Vue({
router
}).$mount('#app')

Why won't tests for angular components pass when I have a css file attached?

I'm trying to test a component in Angular 4 that has an external template and a css file. I'm using an asynchronous beforeEach to compile the component using TestBed but it doesn't work unless I remove the content of the css file and remove classes and id's from the html tags. Why is this happening?
Here is the spec:
import { TestBed, async } from '#angular/core/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
AppComponent
],
}).compileComponents();
}));
it('should create the app', async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app).toBeTruthy();
}));
it(`should have as title 'app works!'`, async(() => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.debugElement.componentInstance;
expect(app.title).toEqual('app works!');
}));
it('should render title in a h1 tag', async(() => {
const fixture = TestBed.createComponent(AppComponent);
fixture.detectChanges();
const compiled = fixture.debugElement.nativeElement;
expect(compiled.querySelector('h1').textContent).toContain('appworks!');
}));
});
Here is the component :
import { Component } from '#angular/core';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'app works!';
}
Here is the html page :
<h1>
{{title}}
</h1
>
Here is the css file :
h1 {
color: #369;
font-family: Arial, Helvetica, sans-serif;
font-size: 250%;
}
This is a screenshot of the error in the console
The same error appears for each test.
Any help would be greatly appreciated. I've been blocked for a couple of days.

Ensure json configuration is loaded in Angular2 [duplicate]

Is there a way to pass arguments rendered on the backend to angular2 bootstrap method? I want to set http header for all requests using BaseRequestOptions with value provided from the backend. My main.ts file looks like this:
import { bootstrap } from '#angular/platform-browser-dynamic';
import { AppComponent } from "./app.component.ts";
bootstrap(AppComponent);
I found how to pass this arguments to root component (https://stackoverflow.com/a/35553650/3455681), but i need it when I'm fireing bootstrap method... Any ideas?
edit:
webpack.config.js content:
module.exports = {
entry: {
app: "./Scripts/app/main.ts"
},
output: {
filename: "./Scripts/build/[name].js"
},
resolve: {
extensions: ["", ".ts", ".js"]
},
module: {
loaders: [
{
test: /\.ts$/,
loader: 'ts-loader'
}
]
}
};
update2
Plunker example
update AoT
To work with AoT the factory closure needs to be moved out
function loadContext(context: ContextService) {
return () => context.load();
}
#NgModule({
...
providers: [ ..., ContextService, { provide: APP_INITIALIZER, useFactory: loadContext, deps: [ContextService], multi: true } ],
See also https://github.com/angular/angular/issues/11262
update an RC.6 and 2.0.0 final example
function configServiceFactory (config: ConfigService) {
return () => config.load();
}
#NgModule({
declarations: [AppComponent],
imports: [BrowserModule,
routes,
FormsModule,
HttpModule],
providers: [AuthService,
Title,
appRoutingProviders,
ConfigService,
{ provide: APP_INITIALIZER,
useFactory: configServiceFactory
deps: [ConfigService],
multi: true }
],
bootstrap: [AppComponent]
})
export class AppModule { }
If there is no need to wait for the initialization to complete, the constructor of `class AppModule {} can also be used:
class AppModule {
constructor(/*inject required dependencies */) {...}
}
hint (cyclic dependency)
For example injecting the router can cause cyclic dependencies.
To work around, inject the Injector and get the dependency by
this.myDep = injector.get(MyDependency);
instead of injecting MyDependency directly like:
#Injectable()
export class ConfigService {
private router:Router;
constructor(/*private router:Router*/ injector:Injector) {
setTimeout(() => this.router = injector.get(Router));
}
}
update
This should work the same in RC.5 but instead add the provider to providers: [...] of the root module instead of bootstrap(...)
(not tested myself yet).
update
An interesting approach to do it entirely inside Angular is explained here https://github.com/angular/angular/issues/9047#issuecomment-224075188
You can use APP_INITIALIZER which will execute a function when the
app is initialized and delay what it provides if the function returns
a promise. This means the app can be initializing without quite so
much latency and you can also use the existing services and framework
features.
As an example, suppose you have a multi-tenanted solution where the
site info relies on the domain name it's being served from. This can
be [name].letterpress.com or a custom domain which is matched on the
full hostname. We can hide the fact that this is behind a promise by
using APP_INITIALIZER.
In bootstrap:
{provide: APP_INITIALIZER, useFactory: (sites:SitesService) => () => sites.load(), deps:[SitesService, HTTP_PROVIDERS], multi: true}),
sites.service.ts:
#Injectable()
export class SitesService {
public current:Site;
constructor(private http:Http, private config:Config) { }
load():Promise<Site> {
var url:string;
var pos = location.hostname.lastIndexOf(this.config.rootDomain);
var url = (pos === -1)
? this.config.apiEndpoint + '/sites?host=' + location.hostname
: this.config.apiEndpoint + '/sites/' + location.hostname.substr(0, pos);
var promise = this.http.get(url).map(res => res.json()).toPromise();
promise.then(site => this.current = site);
return promise;
}
NOTE: config is just a custom config class. rootDomain would be
'.letterpress.com' for this example and would allow things like
aptaincodeman.letterpress.com.
Any components and other services can now have Site injected into
them and use the .current property which will be a concrete
populated object with no need to wait on any promise within the app.
This approach seemed to cut the startup latency which was otherwise
quite noticeable if you were waiting for the large Angular bundle to
load and then another http request before the bootstrap even began.
original
You can pass it using Angulars dependency injection:
var headers = ... // get the headers from the server
bootstrap(AppComponent, [{provide: 'headers', useValue: headers})]);
class SomeComponentOrService {
constructor(#Inject('headers') private headers) {}
}
or provide prepared BaseRequestOptions directly like
class MyRequestOptions extends BaseRequestOptions {
constructor (private headers) {
super();
}
}
var values = ... // get the headers from the server
var headers = new MyRequestOptions(values);
bootstrap(AppComponent, [{provide: BaseRequestOptions, useValue: headers})]);
In Angular2 final release, the APP_INITIALIZER provider can be used to achieve what you want.
I wrote a Gist with a complete example: https://gist.github.com/fernandohu/122e88c3bcd210bbe41c608c36306db9
The gist example is reading from JSON files but can be easily changed to read from a REST endpoint.
What you need, is basically:
a) Set up APP_INITIALIZER in your existent module file:
import { APP_INITIALIZER } from '#angular/core';
import { BackendRequestClass } from './backend.request';
import { HttpModule } from '#angular/http';
...
#NgModule({
imports: [
...
HttpModule
],
...
providers: [
...
...
BackendRequestClass,
{ provide: APP_INITIALIZER, useFactory: (config: BackendRequestClass) => () => config.load(), deps: [BackendRequestClass], multi: true }
],
...
});
These lines will call the load() method from BackendRequestClass class before your application is started.
Make sure you set "HttpModule" in "imports" section if you want to make http calls to the backend using angular2 built in library.
b) Create a class and name the file "backend.request.ts":
import { Inject, Injectable } from '#angular/core';
import { Http } from '#angular/http';
import { Observable } from 'rxjs/Rx';
#Injectable()
export class BackendRequestClass {
private result: Object = null;
constructor(private http: Http) {
}
public getResult() {
return this.result;
}
public load() {
return new Promise((resolve, reject) => {
this.http.get('http://address/of/your/backend/endpoint').map( res => res.json() ).catch((error: any):any => {
reject(false);
return Observable.throw(error.json().error || 'Server error');
}).subscribe( (callResult) => {
this.result = callResult;
resolve(true);
});
});
}
}
c) To read the contents of the backend call, you just need to inject the BackendRequestClass into any class of you choice and call getResult(). Example:
import { BackendRequestClass } from './backend.request';
export class AnyClass {
constructor(private backendRequest: BackendRequestClass) {
// note that BackendRequestClass is injected into a private property of AnyClass
}
anyMethod() {
this.backendRequest.getResult(); // This should return the data you want
}
}
Let me know if this solves your problem.
Instead of having your entry point calling bootstrap itself, you could create and export a function that does the work:
export function doBootstrap(data: any) {
platformBrowserDynamic([{provide: Params, useValue: new Params(data)}])
.bootstrapModule(AppModule)
.catch(err => console.error(err));
}
You could also place this function on the global object, depending on your setup (webpack/SystemJS). It also is AOT-compatible.
This has the added benefit to delay the bootstrap, whenit makes sense. For instance, when you retrieve this user data as an AJAX call after the user fills out a form. Just call the exported bootstrap function with this data.
The only way to do that is to provide these values when defining your providers:
bootstrap(AppComponent, [
provide(RequestOptions, { useFactory: () => {
return new CustomRequestOptions(/* parameters here */);
});
]);
Then you can use these parameters in your CustomRequestOptions class:
export class AppRequestOptions extends BaseRequestOptions {
constructor(parameters) {
this.parameters = parameters;
}
}
If you get these parameters from an AJAX request, you need to bootstrap asynchronously this way:
var appProviders = [ HTTP_PROVIDERS ]
var app = platform(BROWSER_PROVIDERS)
.application([BROWSER_APP_PROVIDERS, appProviders]);
var http = app.injector.get(Http);
http.get('http://.../some path').flatMap((parameters) => {
return app.bootstrap(appComponentType, [
provide(RequestOptions, { useFactory: () => {
return new CustomRequestOptions(/* parameters here */);
}})
]);
}).toPromise();
See this question:
angular2 bootstrap with data from ajax call(s)
Edit
Since you have your data in the HTML you could use the following.
You can import a function and call it with parameters.
Here is a sample of the main module that bootstraps your application:
import {bootstrap} from '...';
import {provide} from '...';
import {AppComponent} from '...';
export function main(params) {
bootstrap(AppComponent, [
provide(RequestOptions, { useFactory: () => {
return new CustomRequestOptions(params);
});
]);
}
Then you can import it from your HTML main page like this:
<script>
var params = {"token": "#User.Token", "xxx": "#User.Yyy"};
System.import('app/main').then((module) => {
module.main(params);
});
</script>
See this question: Pass Constant Values to Angular from _layout.cshtml.

Categories