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);
Related
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)
}
}
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.
I want to import js file in typescript.
And I want to access object and function in the js files.
Also I added js file in index.html but It doesn't working too.
so I find a clue that "import '[js file path]'" but it doesn't working.
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { NavParams } from 'ionic-angular';
import '../../pages/mobile.js';
#Component({
selector: 'page-success',
templateUrl: 'success.html'
})
export class SuccessPage {
constructor(public navCtrl: NavController, public navParms: NavParams) {
let centerPos = new atlan.maps.UTMK(953933.75, 1952050.75);
}
}
This is success.ts file. I want to find 'atlan' object.
Give me a solution please. Thx a lot!
You have to use the declare keyword so you do not get any compilation errors. You can do the following
import { Component } from '#angular/core';
....
/* Here you are telling typescript compiler to
ignore this variable it did not originate with typescript.*/
declare var atlan: any;
#Component({
selector: 'page-success',
templateUrl: 'success.html'
})
export class SuccessPage {
....
}
In your file ../../pages/mobile.js, you must export your atlan object (if you can edit this file of course), then, you import it the same way you do with everything.
I am in need to give a Go-Back button for this I am using location services as:
import {Location} from '#angular/common';
backclicked(): void
{
console.log("back clicked.");
this.location.back();
}
<a id="redirect-link" (click)="backclicked();" style="padding:8px 15px;" >
Issue is this that location.back() is working but with page load. So is their a way where it can be achieved without page load ?. Any help please ?
You can use built in location service in angular 2 which having "Back" api.
import {Component} from '#angular/core';
import {Location} from '#angular/common';
#Component({ directives: [ROUTER_DIRECTIVES] })
#RouteConfig([
{...},
])
class AppCmp {
constructor(private _location: Location) {
}
backClicked() {
this._location.back();
}
}
I don't understand why I get the following error when I use the native InAppBrowser plugin : Can't resolve all parameters for InAppBrowser
import { Component } from '#angular/core';
import { NavController, NavParams, Platform } from 'ionic-angular';
import { InAppBrowser } from 'ionic-native';
#Component({
selector: 'page-sign-in',
templateUrl: 'sign-in.html',
providers: [ InAppBrowser ]
})
export class SignInPage {
constructor(public navCtrl: NavController, public platform: Platform, public inAppBrowser: InAppBrowser ) {
};
}
You don't need to add InAppBrowser to the providers array and you also don't need to inject it in the constructor.
Simply import it in the beginning of the page (as you did), and then use it anywhere in the code like that:
openPage() {
new InAppBrowser('https://google.com', '_system');
}