Ionic 2 is loading the stale component - javascript

This is my footer component. I am calling few pages from the footer bar as follows. When i click on the footer, it is loading the stale component. i debugged it and found out it is not calling the constructor of the component (where i have the loading logic to refresh the data). i have to click twice from the footer to call the component to get the correct data
tab-footer.component.html
<ion-tabs>
<ion-tab [root]="home" tabIcon="md-home"
[rootParams]="homeparams"></ion-tab>
<ion-tab [root]="alertsPage" tabIcon="md-notifications-outline">
</iontab>
<ion-tab [root]="flagged" tabIcon="flag"></ion-tab>
</ion-tabs>
#Component({
selector: 'app-tab-footer',
templateUrl: './tab-footer.component.html',
styleUrls: ['./tab-footer.component.scss']
})
export class TabFooterComponent {
home = HomeComponent;
alertsPage = AlertsComponent;
flagged = FlaggedComponent;
homeparams: any;
constructor(public navparam: NavParams) {
this.homeparams = navparam;
}
}
Here is my one of the components that is called from footer
#Component({
selector: 'app-flagged',
templateUrl: './flagged.component.html',
styleUrls: ['./flagged.component.scss']
})
export class FlaggedComponent {
someData1: any;
someData:any[] = [];
someObj = {}
constructor(public someService: SomeServiceService,
public exampleService: ExampleService,
public navParams: NavParams,
public navCtrl: NavController) {
// some loading logic
}
Can anyone help finding out why it is not calling constructor every time?
Do I have specify some property to load it fresh?
Thank you

Add the lifecycle event ionViewDidEnter or ionViewWillEnter to your FlaggedComponent class and move your update or loading logic from the constructor into one of those methods.
ionViewDidEnter() {
console.log('the page has entered');
}
ionViewWillEnter() {
console.log('the page is about to enter');
}
ionViewDidEnter is called when the page has fully entered and is now the active page.
This event will fire, whether it was the first load or a cached page.
ionViewWillEnter is called when the page is about to enter and become the active page.
reference: https://ionicframework.com/docs/api/navigation/NavController/#lifecycle-events

Related

ionic page data does not update

So say i have page one:
This page contains multiple variables and a constructor. it could look something like this:
export class TestPage implements OnInit {
testInt: number;
testString: string;
constructor(private someService: SomeService) {
}
ngOnInit() {
this.testInt = this.someService.getInt();
this.testString = this.someService.getLongText();
}
}
Now when this page loads it correctly sets the values.
Now say that I change page and on this page, I change some of the values in the service.
When I then come pack to this TestPage it hasn't updated the values.
Does this have something to do with caching? or with push state?
How can I make sure that the page is "reloaded" ?
Try using RxJS.
#Injectable({...})
class SomeService {
private _testInt: BehaviorSubject<number> = new BehaviorSubject<number>(0); // initial value 0
setTestInt(value: number) {
this._testInt.next(value);
}
getTestInt(): Observable<number> {
return this._testInt.asObservable();
}
}
#Component({...})
class TestPage implements OnInit {
public testInt: number;
public testInt$: Observable<number>;
private subscription: Subscription;
constructor(private someService: SomeService) {}
ngOnInit() {
// one way
this.testInt$ = this.someService.getTestInt();
// or another
this.subscription = this.someService.getTestInt()
.subscribe((value: number) => {
this.testInt = value;
});
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}
in the HTML:
<p>{{ testInt }}</p>
<p>{{ testInt$ | async }}</p>
If you are subscribing to a Observable, make sure you unsubscribe after the usage (usually On Destroy lifecycle hook).
Async Pipe does that out of the box.
Or try the ionViewWillEnter lifecycle hook.
As you can see in the official documentation:
ngOnInit will only fire each time the page is freshly created, but not when navigated back to the page.
For instance, navigating between each page in a tabs interface will only call each page's ngOnInit method once, but not on subsequent visits.
ngOnDestroy will only fire when a page "popped". link That means that Page is cached, yes. Assigning value On Init will set the value only the first time page is visited and therefore not updated.

Angular 4/5 Observable - How to update component template depending on observable property?

Ok I am still a newbie. I have successfully created a 'dashboard' component that has a left sidebar with links. On the right is where I have content/components displayed that I want to change dynamically depending on what link was clicked on the left sidebar (see bootstrap sample of what this dashboard looks like here, click on the toggle button to view the sidebar: https://blackrockdigital.github.io/startbootstrap-simple-sidebar/).
I have created a DashboardService that has a Subject and an Observable to allow for sibling component communication. This works great since I have a console.log() that shows this communication working (when I click on link on sidebar in SidebarComponent, I console.log() a value 'emitted' by the DashboardService that is being listened to by the SidebarComponent's sibling, DashboardSectionComponent).
The problem that I am having is that the template in DashboardSectionComponent loads the correct component section ONLY on initial load of page - once I click on a link on the side bar the content is blank and nothing is rendered.
Here is the service that allows the componenent communication:
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
#Injectable()
export class DashboardService {
private selectedComponentAlias = new Subject<string>();
constructor() {}
setSelectedComponentAlias(alias: string) {
this.selectedComponentAlias.next(alias);
}
getSelectedComponentAlias(): Observable<string> {
return this.selectedComponentAlias.asObservable();
}
}
Here is the SidebarComponent:
import { Component, OnInit } from '#angular/core';
import { DashboardService } from '../dashboard.service';
#Component({
selector: 'app-sidebar',
templateUrl: './sidebar.component.html',
styleUrls: ['./sidebar.component.css']
})
export class SidebarComponent implements OnInit {
constructor(private dashboardService: DashboardService) { }
ngOnInit() {
}
onShowSection(event) {
event.preventDefault();
const componentAlias = event.target.getAttribute('data-componentAlias');
this.dashboardService.setSelectedComponentAlias(componentAlias);
}
}
here is the DashboardSectionComponent (the one that subscribes to the observable and I want to set property that controls the template views depending on the value that was caught)
import { Component, OnInit, OnDestroy } from '#angular/core';
import { Subscription } from 'rxjs/Subscription';
import { DashboardService } from '../dashboard.service';
#Component({
selector: 'app-dashboard-section',
templateUrl: './dashboard-section.component.html',
styleUrls: ['./dashboard-section.component.css']
})
export class DashboardSectionComponent implements OnInit, OnDestroy {
private subscrition: Subscription;
selectedComponentAlias: string = 'user-profile';
constructor(private dashboardService: DashboardService) {
}
ngOnInit() {
this.subscrition = this.dashboardService.getSelectedComponentAlias()
.subscribe((selectedComponentAlias: string) => {
this.selectedComponentAlias = selectedComponentAlias;
console.log('user clicked: ',this.selectedComponentAlias);
});
}
ngOnDestroy() {
this.subscrition.unsubscribe();
}
}
Finally here is the template for DashboardSectionComponent which might have wrong syntax:
<div *ngIf="selectedComponentAlias == 'my-cards'">
<app-cards></app-cards>
</div>
<div *ngIf="selectedComponentAlias == 'user-profile'">
<app-user-profile></app-user-profile>
</div>
<div *ngIf="selectedComponentAlias == 'user-settings'">
<app-user-settings></app-user-settings>
</div>
Again, this works great (selectedComponentAlias is 'user-profile' on page load by default). But it goes blank after I click on a Sidebar link....
Thanks.
this was easy - like #RandyCasburn pointed out, this was a matter of getting the routing working properly.

Ionic 3 How to close modal with Tabs and pass data to parent

Is this possible to create modal with contains Tabs and when select item pass data to parent view?
I known that Tabs have own, separate history stack so if is not possible what is best way to implement that like Tabs-looking way?
Creating modal with tabs from parent view:
selectContractor() {
let contractorsModal = this.modalCtrl.create('VisitAddTabsPage', {routeId: this.routeId});
contractorsModal.present();
contractorsModal.onDidDismiss(data => {
console.log(data);
})
}
VisitAddTabsPage.ts
#Component({
selector: 'page-visit-add-tabs',
templateUrl: 'visit-add-tabs.html'
})
#IonicPage()
export class VisitAddTabsPage {
ownContractorsRoot = 'OwnContractorsPage'
closestContractorsRoot = 'ClosestContractorsPage'
allContractorsRoot = 'AllContractorsPage'
constructor(public navCtrl: NavController,
public navParams: NavParams,
public viewCtrl: ViewController) {
}
}
visit-add-tabs.html
<ion-tabs tabsPlacement="top" selectedIndex="1">
<ion-tab [root]="ownContractorsRoot" tabTitle="Moi" tabUrlPath="own" tabIcon="star"></ion-tab>
<ion-tab [root]="closestContractorsRoot" tabTitle="W pobliżu" tabUrlPath="closest" tabIcon="locate"></ion-tab>
<ion-tab [root]="allContractorsRoot" tabTitle="Wszyscy" tabUrlPath="all" tabIcon="contacts"></ion-tab>
</ion-tabs>
Closest-contractors tab (closest-contractors.ts)
handleSelectedContractor(data) {
console.log(this.navCtrl);
console.log(this.appCtrl.getRootNav());
//this.viewCtrl.dismiss(data); <-- HOW TO DISMISS MODAL (and TABS) AND PASS DATA
}
Yes, you can do that using Events.
You can always emit an event, carrying any data you want, from any DOM element to any of it's parent dom elements.
So from the child page do something like this:
import { EventEmitter, Output } from '#angular/core';
#Component({
...
})
export class ChildPage {
#Output() tabGotClosed = new EventEmitter();
let data: any;
...
notifyPickupConfirmed() {
this.tabGotClosed.emit(data);
}
}
Then in the parent page's template you can just catch the event like you would with any other:
<ion-content (tabGotClosed)="onTabGotClosed($event)">
In this way, the page that opened the modal can finally have the data available to it after the modal closes by just looking into the data carried by the event event.detail.tabGotClosed.

Checking an event only in one page of the app in angular2

i'm developing my first app in angular 4.0.
My problem is pretty simple but i would like to know if there is a best practice to solve my issue.
I have an header with position: 'fixed' and when the user scrolls the page this element changes some of its properties (height, background-size..) by adding a 'small' class dynamically.
This is my component
import {Component, OnInit, HostListener} from '#angular/core';
#Component({
selector: 'my-header',
templateUrl: './my-header.component.html',
styleUrls: ['./my-header.component.css']
})
export class HeaderComponent implements OnInit {
scrollState: boolean;
constructor() { }
ngOnInit() {
this.scrollState = false;
}
#HostListener('window:scroll', [])
toggleScrollState() {
if(window.pageYOffset == 0){
this.scrollState = false;
}
else{
this.scrollState = true;
}
}
}
and this the html
<header class="bk-blue clearfix" [ngClass]="{small: scrollState}">
<a class="sx" href="#">Login</a>
<a class="dx arrow-down"></a>
<a class="dx" href="#">It</a>
</header>
Everything works fine but this should happen only in the home page. In the other page the header element should already be in the 'small' state without any DOM manipulations based on the scroll event.
I was thinking of checking the current route to set an additional variable (false if the current route matches the home page path, true otherwise) and put that in OR with scrollState. Something like this:
<header class="bk-blue clearfix" [ngClass]="{small: notHome || scrollState}">
By doing so, however, i can't avoid calling the listener with its implications in term of reduced performance.
What is for you the best approach to avoid calling the listener even in internal pages where it is not necessary?
well, I would do this using ActivatedRouteSnapshot
#Component({...})
class Header implements OnInit {
readonly snapshot: ActivatedRouteSnapshot = null;
constructor(private route: ActivatedRoute) {
this.snapshot = route.snapshot;
}
ngOnInit() {
// if this.snapshot is HOMEPAGE
// then
// subscribe to the scroll and switch class when you need.
}
}
You could also set a property on your route.data which tells you to animate or not the header.
const routes: Routes = [
{
path: '',
component: HomeRouteComponent,
data: { ANIMATE_HEADER: true }
}
];
// header.ts
ngOnInit() {
if(this.snapshot.data.ANIMATE_HEADER) {
// do stuff here
}
}

How to refresh a component on each page change

I am calling a data service in an angular 2 component to load data on the ngOnInit() function. This component is placed on a Ionic tabs page. The ngOnInit() function is only called on initialization, but not on every navigation to the tab. I want to reload data from the data service on each navigation to the page, to refresh the component with the latest data.
How can I call a function in the component on each navigation to a tabs page?
This is my component:
#Component({
selector: 'reservation-list',
templateUrl: 'build/components/reservation-list.component.html',
bindings: [DataService, TimeService]
})
export class ReservationListComponent {
public items: any = [];
constructor(private dataService: DataService) { }
public ngOnInit() {
// this I want to call on each tab navigation!
this.items = this.dataService.getEvents();
}
}
My tabs are basically the ionic2-tabs example:
#Page({
templateUrl: 'build/pages/tabs/tabs.html'
})
export class TabsPage {
// this tells the tabs component which Pages
// should be each tab's root Page
tab1Root: any = Page1;
tab2Root: any = Page2;
tab3Root: any = Page3;
}
And the page is a basic ionic page where the component is insert:
<reservation-list></reservation-list>
#Page({
templateUrl: 'build/pages/page1/page1.html',
directives: [ReservationListComponent]
})
export class Page1 {
constructor() {
}
}
I think you can add a click event handler when you click your tabs and call that function.
In your tag
<a (click)="getEvents()"></a>
In you Component
getEvents() {
this.items = this.dataService.getEvents();
}
Please follow the life cycle of ionic and use below method inside tab child pages.
ionViewWillEnter()
{
//apply your code
}
This method will call always when you come on page.

Categories