How can I make basic initialization of my data in app. For example if user logged in and press F5 I need to request current user data from server before all queries starts like get user order etc. In Angular 1 we have .run() directive for this case. How can I solve this problem?
There are several ways to do that:
You could execute some requests before bootstrapping your Angular2 application. Such first requests could rely what you save into the local / session storage.
var injector = Injector.resolveAndCreate([HTTP_PROVIDERS]);
var http = injector.get(Http);
http.get('/userdetails').map(res => res.json())
.subscribe(data => {
bootstrap(AppComponent, [
HTTP_PROVIDERS
provide('userDetails', { useValue: data })
]);
});
See this question for more details:
How to bootstrap an Angular 2 application asynchronously
You could extend the HTTP request to transparently get these data when requests are actually executed. This would be a lazy approach.
#Injectable()
export class CustomHttp extends Http {
constructor(backend: ConnectionBackend, defaultOptions: RequestOptions, userDetailsService: UserDetailsService) {
super(backend, defaultOptions);
}
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
console.log('request...');
return this.userDetailsService.getUserDetails().flatMap((userDetails) => {
return super.request(url, options);
});
}
get(url: string, options?: RequestOptionsArgs): Observable<Response> {
console.log('get...');
return this.userDetailsService.getUserDetails().flatMap((userDetails) => {
return super.get(url, options);
});
}
}
implement the UserDetailsDetails this way:
export class UserDetailsService {
constructor(private http:Http) {
}
getUserDetails() {
if (this.userDetails) {
return Observable.of(this.userDetails);
} else {
return this.http.get(...)
.map(...)
.do(data => {
this.userDetails = data;
// Store in local storage or session storage
});
}
}
and register this CustomHttp class this way:
bootstrap(AppComponent, [HTTP_PROVIDERS,
UserDetailsService,
new Provider(Http, {
useFactory: (backend: XHRBackend,
defaultOptions: RequestOptions,
userDetailsService: UserDetailsService) => new CustomHttp(backend, defaultOptions, userDetailsService),
deps: [XHRBackend, RequestOptions, UserDetailsService]
})
]);
See these questions for more details:
Angular 2 - How to get Observable.throw globally
Cache custom component content in ionic 2
Things could also be done at the level of the router outlet if you use routing. It's possible to implement a custom router-outlet that checks security / user details when a route is activated. I think that it's a little further from your need...
See this question for more details:
Angular 2 Cancelling Route Navigation on UnAuthenticate
You could fetch the current user data before you call Angular2's bootstrap(...)
You could also fire an event (using an Observable for example) to notify other that the logged-in user is now known and initiate further requests only after this event was received.
Related
I am new to Angular and following this tutorial to create a MailChimp submission form. I have replaced the list information & id and the tutorial with my own. On submission of the form, I want to redirect to a Thank You page, which was not shown in the tutorial.
When I submit user email to the list, I get a 200 response back from the server on my POST request.
However, I have two problems.
#1 The redirect does not navigate to the '/thanks' route. I'm not sure if this is the actual way this function should be used for navigation. I thought it would work similar to React's this.history.push. I got the basic idea for this function from this Stack Overflow question
subscribe-form-component.ts
export class SubscribeFormComponent implements OnInit {
subscribeData: any = <any>{};
constructor(
private subscribeService: SubscribeService,
private router: Router
) {}
ngOnInit() {}
onSuccess() {
this.router.navigate(['/thanks']);
}
subscribe(subscribeForm: NgForm) {
if (subscribeForm.invalid) {
return;
}
this.subscribeService.subscribeToList(this.subscribeData).subscribe({
complete: () => {this.subscribeData},
next: () => {this.onSuccess},
error: (err) => {
console.log('err', err);
},
});
}
}
However, in the console log console.log('err', err), though the submit form returns a 200 response from the sever, I did notice a JSONP error:
Error: JSONP injected script did not invoke callback.
message: "Http failure response for https://xxxxxxx.us11.list-manage.com/subscribe/post?u=afd1f3490xxxxxxxx7883fb&id=035xxxx952&f_id=009fa6e0f0&EMAIL=xxxxxx#icloud.com&c_afd1f34907923e052b17883fb_009fa6e0f0=&c=ng_jsonp_callback_0: 0 JSONP Error"
name: "HttpErrorResponse"
ok: false
status: 0
statusText: "JSONP Error"
url: "https://xxxxxx.us11.list-manage.com/subscribe/post?u=afd1f349xxxxxxx7883fb&id=035b97f952&f_id=009xxxxf0&EMAIL=xxxxx#icloud.com&c_afd1f34907923e052b17883fb_009fa6e0f0=&c=ng_jsonp_call
If my onSuccess navigation route function/syntax is correct, I'm assuming that the reason it is not redirecting is because of this error in the console.
subscribe.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpParams } from '#angular/common/http';
import { Router } from '#angular/router';
#Injectable({
providedIn: 'root'
})
export class SubscribeService {
mailChimpEndpoint = 'https://xxxxxx.us11.list-manage.com/subscribe/post?u=afd1f3490xxxxxxxxxb&id=035b9xxxx52&f_id=009faxxxf0';
constructor(
private http: HttpClient,
private router: Router
) { }
subscribeToList(data: any) {
const params = new HttpParams()
.set('EMAIL', data.email)
.set('afd1f3490xxxxxxxxxxb_009fa6e0f0', '');
const mailChimpUrl = `${this.mailChimpEndpoint}&${params.toString()}`;
return this.http.jsonp(mailChimpUrl, 'c')
}
}
How do I fix this JSON P error and correctly redirect after submission?
By default, JSONP will cause the error that you are seeing when using the Angular HttpClient.
There is a HttpClientJsonpModule that can be used instead of the HttpClientModule, and it does support JSONP.
Documentation is at https://angular.io/api/common/http/HttpClientJsonpModule
I want to read a response from a get http request, my server is in Javascript and the part of the where I send a response is:
app.get('/getReport',function(req,res) {
try {
const data=fs.readFileSync('./report.txt', 'utf8')
res.end(data)
}
catch (err) {
res.end("File not found")
}
})
If if I use Postman I can see the content of the report file.
I want to read this text on my Angular front-end so I create this function in my home.service.ts:
public getReport(){
return this.http.get<any>(this.url+'/getReport').subscribe(data => {
this.value = data;})
}
It doesn't work. what can I do to read my content correctly?
Check your setup. You have to import some modules before get http requests:
#NgModule({
imports: [
BrowserModule,
// import HttpClientModule after BrowserModule.
HttpClientModule,
],...
In order to recive any response, you have to start a communication with your API/server subscribing to the 'getReport' method.
HOW CAN YOU DO THAT?
You have that method in your home.service.ts.
Inject that service in the component where you want to load your report (i.e 'home-component'):
// NOTE: Fit all the paths to your specific system
...
import { HomeService } from '../services/home.service';
...
#Component({
selector: 'app-home-component',
templateUrl: './home-component.html',
styleUrls: ['./home-component.scss'],
})
export class HomeComponent {
public report;
constructor(
...
private homeService: HomeService,
...
) {}
Subscribe to the observable 'getReport' method of homeService, and get the desired data.
For instance, change the constructor like this:
constructor(
...
private homeService: HomeService,
...
) {
this.homeService.getReport
.subscribe((_response) => {
console.log(_response);
this.report = _response;
alert(this.report);
});
}
I'm working with Paypal API that after confirming the purchase it redirects to the url you want, I put the url that I wish would be "localhost:4200/shop/order".
however whenever paypal returns the url, they add the token and payerid at the end url
"localhost:4200/shop/order?token=8YS089366D9655&PayerID=ASDVD4BLMH",
however when it comes back to my angular application, i have an error saying that the page cannot be found.
I have tried several ways to configure the route, but all attempts have failed.
idk if Angular dont accept "?" and "&" in route.
const shopRoutingConfig:Routes = [
{
path:'',component:ShopAppComponent,
children:[
{path:'purchase',component:PurchaseComponent},
{
path:'order/:token/:payerid', //fail in url returned from paypal
component:OrderComponent
}
]
}
]
#NgModule({
imports:[
RouterModule.forChild(shopRoutingConfig)
],
exports:[RouterModule],
})
export class ShopRoutingModule{}
my order component:
export class OrderComponent implements OnInit
{
constructor(private route:ActivatedRoute) {
}
ngOnInit(): void {
debugger
const routeParams = this.route.snapshot.paramMap;
var tokenText = routeParams.get('token')
var userId = routeParams.get('PayerID')
}
}
the only way that worked , is if i edit url manually to
"localhost:4200/shop/order/8DC695025P9917207"
"localhost:4200/shop/order?token=8YS089366D9655&PayerID=ASDVD4BLMH" token and PayerId is query params, but you have described your route as order/:token/:payerId, which is Route params.
so it would have been worked if redirection URL would be
"localhost:4200/shop/order/8YS089366D9655/ASDVD4BLMH".
Since redirection URL is returning with queryParams, it would be better to set your route as
path:'order/', component: yourComponent
and in component.ts
constructor() {
this.route.queryParams.subscribe(params => {
this.tokenText = params.token:
this.userId = params.payerId
})
}
http request is not executed
#HostListener('window:beforeunload')
async ngOnDestroy() {
await this.microSitioService.cancelarTransaccion(this.tarjetaCreditoService.seguimientoEtapa).then(() => {});
}
I need to execute an http request when the on destroy is executed
EDIT: Revised Answer
Ok, this is the format for when you want to make certain onDestroy is called - and also stop navigation away, using $event and preventDefault. I've also added how you can return a message to the browser to describe why nav was halted. You can use this to ensure that the http request is working as intended.
#HostListener('window:beforeunload', ['$event'])
async ngOnDestroy($event) {
if (this.componentSub) {
// handle unsubscriptions
this.componentSub.unsubscribe();
}
await this.microSitioService
.cancelarTransaccion(this.tarjetaCreditoService.seguimientoEtapa)
.then(() => {});
$event.preventDefault();
$event.returnValue = 'A message.';
}
Side Note: Have you included onDestroy as an implements on the class definition?
import { Component, OnDestroy, HostListener } from '#angular/core';
class MyComponent implements onDestroy {
If you are looking for an event that executes when the angular app is destroyed, you can use the PlatformRef which has an OnDestroy() callback
in main.ts
function doSomethingOnAppDestory() {
console.log('test');
}
platformBrowserDynamic().bootstrapModule(AppModule).then(ref => {
// Ensure Angular destroys itself on hot reloads.
if (window['ngRef']) {
window['ngRef'].destroy();
}
window['ngRef'] = ref;
ref.onDestroy(doSomethingOnAppDestory);
// Otherwise, log the boot error
}).catch(err => console.error(err));
See the stackblitz demo
First of all, sorry if my english isn't perfect, I'm french.
I'm creating a mobil app with Ionic 3 / angular 4.
My data are stored in a local JSON file in "assets/data" and I'm accessing it with a Provider.
I have a homePage with formular with data value for my 'selector/option input' and I request my provider which returns data by filter/sort etc ...
Everything works but ... it's kind of ugly.
For now, I'm actually using a button at the top of my form to initialize my Provider because I'm calling the 'http.get' method in my Provider constructor (Yeah ... I know it's kind of bad).
I'm using this temporary solution while waiting to find a way to initialize my Provider on the splash screen or in 'ionViewDidLoad' Event ...
my Provider constructor :
#Injectable()
export class DataBaseProvider {
capaciteUrl = './assets/data/capacite.json';
mixageUrl = "./assets/data/mixage.json";
mixageData: any;
capaciteData: any;
constructor(public http: Http) {
console.log('dataBase init');
this.http.get(this.capaciteUrl)
.map(res => res.json())
.subscribe( data => this.capaciteData = data.data);
this.http.get(this.mixageUrl)
.map(res => res.json())
.subscribe( data => this.mixageData = data.data);
}
my 'initializer' function in my homePage.ts ( called by button )
init() {
this.dataBase.getDataSelector()
.then(data => {
this.mixage = data['mixage'];
this.capacite = data['capacite'];
this.firstIngredient = this.secondIngredient = data['ingredient'];
})
}
A part of my form :
<ion-select [(ngModel)]="mixageSelector" okText="Select">
<ion-option *ngFor="let mix of mixage" [value]="mix.id"> {{mix.name}} </ion-option>
</ion-select>
Where can I call the Http.get method or How can I rewrite my module to call Http method at loading/splashScreen of my application ? ( I also try to call my getDataSelector() in an ionViewDidLoadEvent() but nothing changes ... )