Working on a small angular project with a few components that represent the views, the app has a home component which contains a list of items which when clicked load the views in the other(appropriate) components. The project has a service that provides data to all the components, this service loads the shared data from an API when the home component's ngOnInit() {} method is called after which the data is available to every other component in the app.
Now, my problem is when a user enters the full url path to any other component apart from the home component(usually due to hitting refresh while on this component), the data in the service is lost and the component has nothing to display. Is there a way to make the home component always load first even when a direct path to the component is entered into the url? Should I just always check in every component if data has been loaded and load if not? Thank you
Here is the source for the Home Component.
import { Component, OnInit } from '#angular/core';
import { ServiceCodeService } from './service-code.service';
import { ActivatedRoute, Router } from '#angular/router';
#Component({
selector: 'app-home-page',
templateUrl: './home-page.component.html',
styleUrls: ['./home-page.component.css']
})
export class HomePageComponent implements OnInit {
private specialityList: string[];
private route: ActivatedRoute;
private router: Router;
private svpList: string[];
constructor(private serviceCodeService: ServiceCodeService, route: ActivatedRoute, router: Router) {
this.route = route;
this.router = router;
}
ngOnInit() {
this.serviceCodeService.updateServiceCodesFromAPI().subscribe(
servCodes => {
this.specialityList = this.serviceCodeService.getAllSpecialities();
}
);
}
specialitySelected(item: any) {
this.router.navigate(['../speciality/'.concat(item)], {relativeTo: this.route});
}
svpSelected(item: any) {
this.router.navigate(['../svp/'.concat(item)], {relativeTo: this.route});
You could add a <router-outlet> to your home component, and then make the other views (/speciality etc...) children routes of the home route.
This would ensure that the home route always loads first
this.serviceCodeService.updateServiceCodesFromAPI().subscribe(
servCodes => {
if(servCodes) {
console.log(servCodes);
this.specialityList = this.serviceCodeService.getAllSpecialities();
}
}
);
You can do above mentioned code in all the components.
Related
I have a module which initially redirects to
redirectTo: "/profile/bbb"
Where profile has two children :
{
path: '',
component: ProfileComponent,
children: [{
path: 'aaa',
component: AComponent
}, {
path: 'bbb',
component: BComponent
}]
}
Now - In profile's constructor I want to know what is the current route (which is profile) and what is the next route which it is goint to execute ( which is bbb).
This is the code :
profile.component.ts
constructor(private route: ActivatedRoute) {
route.children[0].url.subscribe(f => console.log(f))
}
But it shows me :
I guess I just queried the structure of the routes rather than the current active route
Question
How can I , in each path along the route , can know what is the parent route , current route , and where is it going to navigate ?
ps I don't want to do it via snapshot solution since component can be reused.
Online Demno
You can do this using ActivatedRoute.
Import it like:
import { ActivatedRoute } from '#angular/router';
Now inject it in the component:
constructor( private route: ActivatedRoute) {
console.log('Parent URL:', route.parent.url['value'][0].path);
console.log('Child URL:', route.firstChild.url['value'][0].path);
}
If you want to know complete URL for every navigation.
Then you can do this by using Router. Probably in AppComponent.
import { Router, NavigationStart, NavigationEnd } from '#angular/router';
A component will look like:
constructor(private router: Router) {
router.events.subscribe((route) => {
if (route instanceof NavigationStart) {
console.log("NavigationStart called:", route.url);
}
if (route instanceof NavigationEnd) {
console.log("NavigationEnd called:", route.url);
}
});
}
I have the following routerlink which contains a param:
http://localhost:4200/item/1
How would I go about doing an *ngIf with a param....
I tried the following
<div *ngIf="router.url === '/item/:item_id'">
</div>
The component which I'm running this *ngIf is a header component which isn't connect to the itemComponent
Have you tried using ActivatedRoute.
Import into your component
import { ActivatedRoute } from '#angular/router';
then get your url value as following..
constructor(private route: ActivatedRoute) {
this.route.params.subscribe(params => {
this.item_id = +params['item_id'];
});
after this you implement your logic for DOM view.
I have a problem. I don't know how to send object from one component to another.
In first component cinema.component.html I have following function call:
<a title="Reserve" (click)="openReservationPage(repertoire)">Reserve</a>
In cinema.component.ts file, for that .html I have something like:
openReservationPage(repertoire: UpcomingRepertoire) {
this.router.navigate(['/reserve', {repertoire: JSON.stringify(repertoire)}]);
}
My app.routes.ts file contains appropriate routing:
{ path: 'reserve', component: ReserveFormComponent }
How can I use this repertoire object in another page reserve-form.component.ts and reserve-form.component.html ?
As an answer for the question in the title, i would said create a service to pass data between components.
Since its a router implementation you can pass the repertoire as a route parameter.
Follow these steps:
1)Modify the route in app.routes.ts to take a param
{ path: 'reserve/:repertoire', component: ReserveFormComponent }
2)In cinema.component.ts pass the repertoire as param
this.router.navigate(['/reserve',JSON.stringify(repertoire)]);
3)Extract the param in reserve-form.component.ts
First of all you need to import
import {ActivatedRoute } from "#angular/router";
Technique 1
repertoire:any;
constructor(private activatedRoute: ActivatedRoute) {
this.repertoire = JSON.parse(activatedRoute.snapshot.params["repertoire"]);
}
Technique 2
import { Subscription } from "rxjs/Rx";
private subscription: Subscription;
repertoire:any;
constructor(private activatedRoute: ActivatedRoute) {
this.subscription = activatedRoute.params.subscribe(
(param: any) => this.repertoire = JSON.parse(param['repertoire'])
);
}
ngOnDestroy() { // here we unsubscribe to the observable
this.subscription.unsubscribe();
}
Further Explanation :
Technique 1 is adopted when you are sure that the param will be passed every time you navigate to the component.
Technique 2 is a subscription to the observable once there a param published but don't forget to unsubscribe in the ngOnDestroy() component's life cycle method to prevent memory leak.
It is more preferable because some times there a scenario that a param is passed to a component after it was created where the snapshot method wouldn't capture and it more flexible with different scenario than the basic one in technique 1.
The link below explains how you can do this. I've recently used this to create a messaging service. The example below, shows the code for a simple messaging service. It allows you to pass a number between components, just change the to I guess. You can also write out to local storage, but It seems services are more popular. Once you've got your head around them, they're easy to re-use.
Hope this helps
Sharing Data Between Angular Components - Four Methods
Message Service (PmMessageService)
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable()
export class PmMessageService
{
private pillMenuIndexBS = new BehaviorSubject <number> (null);
pillMenuIndex = this.pillMenuIndexBS.asObservable();
constructor() {}
setPillMenuIndex(index : number)
{
this.pillMenuIndexBS.next(index);
}
}
Component consuming message service, setting a value
import { Component, OnInit } from '#angular/core';
import { PmMessageService } from '../pm-message-service/pm-message.service'
import { BrowserModule } from '#angular/platform-browser';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
#Component({
selector: 'app-pm-configure',
templateUrl: './pm-configure.component.html',
styleUrls: ['./pm-configure.component.css']
})
export class PmConfigureComponent implements OnInit
{
constructor (private messageService : PmMessageService) {}
ngOnInit()
{
this.messageService.setPillMenuIndex(1);
}
}
Component consuming and subscribing.
import { Component, OnInit } from '#angular/core';
import { PmMessageService } from '../pm-message-service/pm-message.service'
import { BrowserModule } from '#angular/platform-browser';
import { platformBrowserDynamic } from '#angular/platform-browser-dynamic';
#Component({
selector: 'pm-bs-navbar',
templateUrl: './pm-bs-navbar.component.html',
styleUrls: ['./pm-bs-navbar.component.css']
})
export class PmBsNavbarComponent implements OnInit
{
tabActiveNumber;
constructor (private messageService : PmMessageService) {}
ngOnInit()
{
this.messageService.pillMenuIndex.subscribe(index => this.tabActiveNumber = index)
}
}
How can I get a value from link in angular 4, I have made *ngIf and I want it to show div based on the value of the link
<div *ngIf="get the value from the current href">
<div *ngIf="isHomePage()>
and in TS,
isHomePage(): boolean {
return this.router.url == 'yourcheckurl';
}
import { Router } from '#angular/router';
add router in constructor and method in class
constructor(router: Router) {
}
getUrl() {
return this.router.url;
}
No change html code to
<div *ngIf="getUrl()">
you have to import router in the component
import { Router, ActivatedRoute } from '#angular/router';
if you dont have #angular/router you have to run "npm install #angular/router"
now inject router in your component like
constructor(private route: ActivatedRoute, private router: Router) { }
now you can write a method which returns true for your URL
return this.router.url === 'your URL'
then you can call that method inside *ngIf="isYourPage()"
I'm learning Ionic 2 by building a simple app, but I've ran into a problem I can't solve.
The app has a ion-nav for the login page, after logging in it goes into a tabs navigator. So the app nav would be something like:
app<Nav> {
LoginPage,
restrictedTabs<Nav> {
Page1,
...
}
}
My problem is I don't know how to access appNav while I'm inside Page1, so that I can, for example, logout the user and block him from "restrictedTabs".
I've tried as the docs say with #ViewChild
import {Component, ViewChild} from '#angular/core';
import {NavController} from 'ionic-angular';
#Component({
templateUrl: 'page1url...'
})
export class ProfilePage {
#ViewChild('appNav') appNav : NavController
constructor(private _nav: NavController) {
}
pushNewPlace() {
console.log(this._nav.rootNav);
console.log(this._nav.parent);
}
ngAfterViewInit() {
console.log(this.appNav);
}
}
But appNav is always undefined, as is rootNav (which I've seen in some tutorial...). If I try #ViewChild('appNav') on LoginPage controller it works good
Because your navcontroller is local, you need to get access to the rootNav.
that is done thanks to the appController.
Tabs are creating a view inside the 'root' view.
In the page loaded inside one of the tabs :
First, import Nav from ionic-angular, same place as navController
import { App, NavController } from 'ionic-angular';
Be sure to have your loginPage also
import { LoginPage } from 'pages/login/login';
then provide it in your constructor :
constructor(public navCtrl: NavController, public appCtrl: App)
now you can acces the rootnav:
this.appCtrl.getRootNav().setRoot(myLoginPage);