Angular 2 - How to pass URL parameters? - javascript

I have created a single page mortgage calculator application in Angular 2, which acts like a learning playground for me (trying to get more accustomed to technology stack currently used at work)... It's running at http://www.mortgagecalculator123.com if you want to look at it. I've made it open source with a Fork Me link right on the page if you want to look at it.
Anyhow, what I want to do, is to be able to pass variables to my app, straight from the URL, so they can be consumed by my Angular 2 app. Something like this: http://www.mortgagecalculator123.com/?var1=ABC&var2=DEF
I've tried following, in my app.component.ts, I've added following:
import { Router, ActivatedRoute, Params } from '#angular/router';
AppComponent {
private var1: string;
private var2: string;
constructor(
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
this.route.params.forEach((params: Params) => {
this.var1 = params['var1'];
this.var2 = params['var2'];
});
console.log(this.var1, this.var2);
}
...
}
But this won't work, when I run npm start, I get following error:
aot/app/app.component.ngfactory.ts(45,30): error TS2346: Supplied parameters do not match any signature of call target.
Thank you, any help would be much appreciated.

I created a pull request with the query params working. I will try to explain everything I did.
The reason why the previous answers doesn't work is because you aren't using the router at all. You created a massive app component without routes. To fix that we need to start using the route module, I also advise you to read these two tutorials: Routing and Routing & Navigation.
First we need to change your index.html, add this to your <head>:
<base href="/">
See here why it's important to add that.
Then since you are using your AppComponent to show everything we need to create a new component, which we will call RootComponent. On your index.html change <my-app> to <root>; it will look like this:
<root>Loading...</root>
Now inside your app folder we need to create two files the first one will be root.component.ts which will look like this:
import { Component } from '#angular/core';
#Component({
selector: 'root',
template: `<router-outlet></router-outlet>`,
})
export class RootComponent {
constructor() { }
}
Look that we have the <router-outlet></router-outlet> as a template, Angular will inject our components based on the route.
We still need to create one more file, which will be main.route.ts, this is what it looks like:
import { Routes, RouterModule } from '#angular/router';
import { AppComponent } from './app.component';
export const mainRoutes: Routes = [
{ path: '', component: AppComponent }
];
export const mainRoutingProviders: any[] = [];
export const routing = RouterModule.forRoot(mainRoutes);
In this file we are saying that for our base route, we want to render our AppComponent
We have created our new files, now we need to tell our App Module about them, in your app.module.ts so we import the new files and declare the new component. We also need to change our boostrap component:
import {NgModule} from '#angular/core';
import {BrowserModule} from '#angular/platform-browser';
import {FormsModule, ReactiveFormsModule} from "#angular/forms";
import {AppComponent} from './app.component';
import {RootComponent} from './root.component'; // we import our new RootComponent
import {ChartModule} from 'primeng/primeng';
import {TooltipModule} from 'primeng/primeng';
import { routing, mainRoutingProviders } from './main.routes'; // We also import our Routes
#NgModule({
imports: [
BrowserModule,
ChartModule,
FormsModule,
mainRoutingProviders, // we also need to import our route provider into the module
ReactiveFormsModule,
routing, // and also import our routes declarations
TooltipModule
],
declarations: [AppComponent, RootComponent], // we declare our new RootCpmponent
bootstrap: [RootComponent] // Notice that we are now using our RootComponent to bootstrap our app
})
export class AppModule {
}
Now with all this in place we can now finally start passing parameters to our app, on your AppComponent import the Router, ActivatedRoute and the Params from #angular/router so your AppComponent will look something like this:
import { Component, OnDestroy, OnInit } from '#angular/core';
import { Router, ActivatedRoute, Params } from '#angular/router';
import { Subscription } from 'rxjs/Subscription';
export class AppComponent implements OnInit, OnDestroy {
private var1: string;
private var2: string;
private sub: Subscription;
constructor(
private route: ActivatedRoute,
private router: Router
) {}
ngOnInit() {
// assign the subscription to a variable so we can unsubscribe to prevent memory leaks
this.sub = this.route.queryParams.subscribe((params: Params) => {
this.var1 = params['var1'];
this.var2 = params['var2'];
console.log(this.var1, this.var2);
});
}
ngOnDestroy() {
this.sub.unsubscribe();
}
...
}
You can see the pull request here

It seems you are dealing with Queryparams . So to access them, you can try below code,
this.var1= this.route
.queryParams
.map(params => params['var1']);

Related

How do i add properly create a component to my Jhipster + Angular project with a workin routerlink?

SO i generated a new application on jhipster and i have wanted to create a front side FAQ page for my web portal, i created it as an entity and it generated all the CRUD components (detail, delete, edit). This of course in the jhipster template looks like an admin/user view table with buttons to view, edit or delete. I want to make the FAQ public to visitors of the website without needing to have an account...
So i generated a component 'faq-page' like the documentation says: https://www.jhipster.tech/using-angular/ only problem is the routerlink does not redirect me to '/faq' instead it redirects me to the 404 page. I created the 'faq-page' component based on the existing 'home' like below snippets:
faq-page.component.html (just has some texts for now)
faq-page.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'jhi-faq-page',
templateUrl: './faq-page.component.html',
styleUrls: ['./faq-page.component.scss']
})
export class FaqPageComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}
faq-page.module.ts
import { NgModule } from '#angular/core';
import { RouterModule } from '#angular/router';
import { TestAppSharedModule } from 'app/shared/shared.module';
import { FAQ_PAGE_ROUTE } from './faq-page.route';
import { FaqPageComponent } from './faq-page.component'
#NgModule({
imports: [RouterModule.forChild([FAQ_PAGE_ROUTE]), TestAppSharedModule ],
declarations: [FaqPageComponent]
})
export class FaqModule { }
faq-page.route.ts
import { Route } from '#angular/router';
import { FaqPageComponent } from './faq-page.component';
export const FAQ_PAGE_ROUTE: Route = {
path: 'faq',
component: FaqPageComponent,
data: {
authorities: [],
pageTitle: 'faq-page.title'
}
};
Check your app-routing.module.ts and make sure the ...LAYOUT_ROUTES, line comes last!
ng generate will add your new component at the end, which will let the catch-all 404 page (contained in LAYOUT_ROUTES) match before your new page.
This needs to be printed somewhere in large friendly letters.

Sharing data with component of another module in Angular

just began to work with Angular 8.
I'm currently experimenting with creating an user interface for an complex project.
The Top Navigation Bar should represent the current mode the user is in. (Like Backend Operations, or Support System, ... which could represent optionally a different Modul).
I'm trying to implement everything in its own module as they could be developed by independent teams (in the future). So I moved everything on the design to the app component. (Layout) while the services that are shared between modules reside in an shared module.
This is the part that would reflect one first shared service property:
template:
<nav class="topBar navbar default-layout col-lg-12 p-0 fixed-top d-flex flex-row {{ getLocation() }}">
...
</nav>
component.ts
...
constructor(private frameworkService:FrameworkService) {
this.fms = frameworkService;
...
}
public getLocation(){
return this.fms.getLocation();
}
ngOnInit() {
}
}
shared modules:
import {NgModule} from '#angular/core';
import {CommonModule} from '#angular/common';
import {FrameworkService} from "./services/framework/framework.service";
#NgModule({
declarations: [],
imports: [
CommonModule
],
providers: [
FrameworkService
]
})
export class SharedModule {
}
framework.service.ts
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class FrameworkService {
private _location:string = '';
getLocation(): string {
console.log('getter');
console.log(this._location);
return this._location;
}
setLocation(value: string) {
this._location = value;
console.log('setter');
console.log(value);
console.log(this._location);
}
constructor() {
this._location = 'bg-backend';
}
}
in an module I'm trying to call it like this:
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { BackendRoutingModule } from './backend-routing.module';
import {MainComponent} from "./main/main.component";
import {SharedModule} from "../shared/shared.module";
import {FrameworkService} from "../shared/services/framework/framework.service";
#NgModule({
declarations: [
MainComponent
],
imports: [
CommonModule,
BackendRoutingModule,
SharedModule
]
})
export class BackendModule {
constructor(FrameworkService: FrameworkService){
FrameworkService.setLocation('bg-backend');
}
}
As far as I can see, I'm running into the problem that it is not using a singleton pattern (as I would have expected it) but more a multi instance approach. Who can I fix this. Several of the pages I looked at didn't really help me or just simply confused me. What I currently also jet need to find out is who to set the value depending on the active module.
Any help is appreciated
:-)
Chris
In the end it didn't work as expected.
I figured out that each session opens an new instance of this service.
So what I did is to store the required informations in the localstorage and accessing it in an static manor.
thanks for you help :-)

Angular 6 Universal service provided in Injector needs another app injected variable

I am using Angular Universal. I have created a PlatformService to detect which platform I am currently working on.
/* platform.service.js */
import { Injectable, Inject, PLATFORM_ID } from '#angular/core';
import { isPlatformBrowser, isPlatformServer } from '#angular/common';
#Injectable({
providedIn: 'root'
})
export class PlatformService {
constructor(
#Inject(PLATFORM_ID) private platformId: Object
) {
this.platformId; // this is coming out undefined
}
isBrowser() {
return isPlatformBrowser(this.platformId);
}
isServer() {
return isPlatformServer(this.platformId);
}
}
I am creating a BaseComponent for common handling of my route binded components.
/* base.component.ts */
import { Component, OnInit, Inject } from '#angular/core';
import { InjectorHolderService } from '#core/services/util/injector-holder.service';
import { PlatformService } from '#core/services/util/platform.service';
#Component({
selector: 'app-base',
template: '',
})
export class BaseComponent implements OnInit {
protected platformService: PlatformService;
constructor() {
this.platformService = InjectorHolderService.injector.get(PlatformService);
console.log(this.platformService);
}
}
Since this component will be inherited by many components, I didn't want to pass the PlatformService through super(). So I decided to go with creating an Injector.
/* app.module.ts */
import { InjectorHolderService } from '#core/services/util/injector-holder.service';
import { PlatformService } from '#core/services/util/platform.service';
#NgModule({ ... })
export class AppModule {
constructor() {
InjectorHolderService.injector = Injector.create({
providers: [
{
provide: PlatformService,
useClass: PlatformService,
deps: [], // I think i need to put something here, but not sure.
}
]
});
}
}
And a service which can hold all the injected module for future use.
/* injector-holder.service.ts */
import { Injectable, Injector } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class InjectorHolderService {
static injector: Injector;
}
But #Inject(PLATFORM_ID) private platformId: Object is giving out undefined, because of which I am not able to detect the platform.
What am I missing here? or If there is a better approach to achieve the above functionality.
Please let me know if you guys need to see any other file.
I am not sure whether the following approach is good or bad, currently, it is the only thing working for me. Would love to hear any new approach to it.
Since PlatformService needed #Inject(PLATFORM_ID) which is provided only from AppModule, the new Injector I created was not able to find any value for #Inject(PLATFORM_ID) and hence undefined.
So, instead of using class PlatformService in Injector, now I am using PlatformService's instantiated object and hence was able to access everything fine in BaseComponent.
Modified my AppModule like following:
/* app.module.ts */
import { InjectorHolderService } from '#core/services/util/injector-holder.service';
import { PlatformService } from '#core/services/util/platform.service';
#NgModule({ ... })
export class AppModule {
constructor(
private platformService: PlatformService,
) {
InjectorHolderService.injector = Injector.create({
providers: [
{
provide: PlatformService,
useValue: this.platformService, // notice the change of key, using value not class
deps: [],
}
]
});
}
}
Will try to add a minimal repo to recreate this issue and share with you guys, If anyone wants to explore more.

Read route params from directly entered url in app

My question would be regarding angular 4, how to get route params, if for example a user gets on your page with, instead of the default url, like for example http://localhost:3000/, to something like http://localhost:3000/user/:id, and to be able to pick up the :id from that url (user has directly entered it in the browser, not navigating through the app).
In the example bellow same component is used, mainly because of needing to catch that id and dispatch other actions, if its present, and that would be it.
I have tried playing around with ActivatedRoute but from what I could tell so far, that only works when navigation throughout the app, from within the app, not in this case, which always returns a null value if that url is directly entered in the browser, it gets redirected to the default / route and that would be it.
Any tips or pointers are much appreciated
app.routing-module.ts
import {hookComponent} from './hook.component';
import {RouterModule, Routes} from '#angular/router';
import {NgModule} from '#angular/core';
export const routes: Routes = [
{
path: '',
component: HookComponent
},
{
path: 'user/:id',
component: HookComponent
}
];
#NgModule({
imports: [RouterModule.forRoot(routes, { enableTracing: true })],
exports: [RouterModule]
})
export class AppRoutingModule {}
hook.component
import {Component, EventEmitter, Input, OnInit, ViewChild} from '#angular/core';
import { ActivatedRoute, ParamMap} from '#angular/router';
#Component({
selector: 'hook',
templateUrl: 'hook.component.html',
styleUrls: ['hook.component.scss']
})
export class HookComponent implements OnDestroy, OnInit {
constructor(private route: ActivatedRoute) {
}
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
console.log('params are', params); //null?
});
}
}
Your way is already ok, but in your example params is an array and you can access to :id by calling params['id']:
this.sub = this.route.params.subscribe(params => {
console.log('params are', params['id']);
});
Here is an working example on stackblitz.
Access current url via Location
public constructor(location:Location) {
let url = location.prepareExternalUrl(location.path());
}
and parse out id from this.
If all you want to do is log the params.id; try using the ActivatedRouteSnapshot like this.
ngOnInit() {
console.log(this.route.snapshot.params.id);
}
If you want to check if the params.id is present, maybe do something like:
import {Component, EventEmitter, Input, OnInit, ViewChild} from '#angular/core';
import { ActivatedRoute, ParamMap} from '#angular/router';
#Component({
selector: 'hook',
templateUrl: 'hook.component.html',
styleUrls: ['hook.component.scss']
})
export class HookComponent implements OnDestroy, OnInit {
hasId: boolean = false;
constructor(private route: ActivatedRoute) {
}
ngOnInit() {
if(this.route.snapshot.params.id !== null)
{
// do magic....
}
}
}

Angular Server-Side Rendering with Route Resolve

I am attempting to use Server-Side Rendering in Angular (v4) to allow for better SEO.
Things work as expected until I add resolve on my route. Adding resolve causes HTML title to retain it's initial value when viewing source.
My Module:
import {
Injectable,
ModuleWithProviders,
NgModule
} from '#angular/core';
import {
ActivatedRouteSnapshot,
Resolve,
Router,
RouterModule,
RouterStateSnapshot
} from '#angular/router';
import {
Observable
} from 'rxjs/Rx';
import {
ArticleComponent
} from './article.component';
import {
Article,
ArticlesService,
UserService,
SharedModule
} from '../shared';
#Injectable()
export class ArticleResolver implements Resolve < Article > {
constructor(
private articlesService: ArticlesService,
private router: Router,
private userService: UserService
) {}
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): any {
return this.articlesService.get(route.params['slug'])
.catch((err) => this.router.navigateByUrl('/'));
}
}
const articleRouting: ModuleWithProviders = RouterModule.forChild([{
path: 'article/:slug',
component: ArticleComponent,
resolve: {
article: ArticleResolver
},
data: {
preload: true
}
}]);
#NgModule({
imports: [
articleRouting,
SharedModule
],
declarations: [
ArticleComponent
],
providers: [
ArticleResolver
]
}) export class ArticleModule {}
My Component:
import {
Component,
OnInit
} from '#angular/core';
import {
ActivatedRoute,
Router,
} from '#angular/router';
import {
Title,
Meta
} from '#angular/platform-browser';
import {
AppComponent
} from '../app.component';
import {
Article,
} from '../shared';
#Component({
selector: 'article-page',
templateUrl: './article.component.html'
})
export class ArticleComponent implements OnInit {
article: Article;
constructor(
private route: ActivatedRoute,
private meta: Meta,
private title: Title
) {}
ngOnInit() {
this.route.data.subscribe(
(data: {
article: Article
}) => {
this.article = data.article;
}
);
this.title.setTitle(this.article.title);
}
}
I am new to Angular SSR so any guidance is greatly appreciated.
Instead of subscribing to route data, retrieve your results from the snapshot like this:
this.route.snapshot.data['article']
You also might need to register ArticlesService in your providers for the module.
As a side note, this import:
import {
Observable
} from 'rxjs/Rx';
is an RxJS antipattern. Please use the following import instead:
import {Observable} from 'rxjs/Observable';
I found that my primary service was referencing a secondary service that was attempting to return an authentication token from window.localStorage.
Attempting to access the client storage caused Angular SSR to omit the generation of source code for my component.
Thanks #Adam_P for helping me walk through it!

Categories

Resources