Ionic2 NativeStorage can't getItem(user) - ionic2

I have an ionic 2 app and am using native FB Login to retrieve name/pic and saving it to NativeStorage. The flow is that I open WelcomePage, log in, and save the data. From there, navPush to HomePage. So far it works great.
However, I have a ProfilePage (accessible via tabRoot), the fails. The reason is that in my profile.html I have the following tag that should render Username (this works on HomePage, but not on ProfilePage):
{{ user.name }}
The error I get on XCode is:
2017-05-02 18:40:41.657374 FoxBox App[1102:226159] ERROR: Failed to navigate: undefined is not an object (evaluating 'co.user.picture')
Note that for some reason it prepends it with 'co.' which I have no idea where its coming from or what it means.
Here is the WelcomePage code:
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { HomePage } from '../home/home';
import { AboutPage } from '../about/about';
import { Facebook, NativeStorage } from 'ionic-native';
//import { FacebookAuth, User, Auth } from '#ionic/cloud-angular';
import { CloudSettings, CloudModule } from '#ionic/cloud-angular';
import {GoogleAnalytics} from 'ionic-native';
#Component({
selector: 'page-welcome',
templateUrl: 'welcome.html'
})
export class WelcomePage {
FB_APP_ID: number = 1234567890;
homePage = HomePage;
aboutPage = AboutPage;
constructor(
public navCtrl: NavController,
//public facebookAuth: FacebookAuth,
//public auth: Auth,
//public user: User,
) {
Facebook.browserInit(this.FB_APP_ID, "v2.8");
}
doFbLogin(){
//alert("fb is logged in");
let permissions = new Array();
let nav = this.navCtrl;
//the permissions your facebook app needs from the user
permissions = ["public_profile"];
Facebook.login(permissions)
.then(function(response){
let userId = response.authResponse.userID;
let params = new Array();
//Getting name and gender properties
Facebook.api("/me?fields=name,gender", params)
.then(function(user) {
user.picture = "https://graph.facebook.com/" + userId + "/picture?type=large";
//now we have the users info, let's save it in the NativeStorage
NativeStorage.setItem('user',
{
name: user.name,
gender: user.gender,
picture: user.picture,
email: user.email,
})
.then(function(){
nav.push(HomePage);
console.log("User Data Stored");
}, function (error) {
console.log(error);
})
})
}, function(error){
console.log(error);
});
}
}
Here is the HomePage code:
import { Component } from '#angular/core';
import { NavController, Platform } from 'ionic-angular';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
import { ClaimPage } from '../claim/claim';
import { SocialSharing } from '#ionic-native/social-sharing';
import { Facebook, NativeStorage } from 'ionic-native';
//import { FacebookAuth, User, Auth } from '#ionic/cloud-angular';
import { CloudSettings, CloudModule } from '#ionic/cloud-angular';
import {GoogleAnalytics} from 'ionic-native';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
posts: any;
sendme: any;
claimPage = ClaimPage;
user: any;
userReady: boolean = false;
constructor(
public navCtrl: NavController,
public http: Http,
private sharingVar: SocialSharing,
public platform: Platform,
) {
// Check to see if user already exists (via FB login)
let env = this;
NativeStorage.getItem('user')
.then(function (data){
env.user = {
name: data.name,
gender: data.gender,
picture: data.picture
};
env.userReady = true;
// console.log(data.name);
}, function(error){
console.log(error);
});
this.platform.ready().then(() => {
//alert("platform is ready");
GoogleAnalytics.trackView("Home-Page", "http://foxboxapp.com/home", true);
//alert("GA called");
});
this.http.get('http://getyourtryston.com/foox/sample.php').map(res => res.json()).subscribe(data => {
this.posts = data.data.children;
});
}
otherShare(){
this.sharingVar.share("FoxBox App","Get Awesome College Deals",null/*File*/,"http://fooxsocial.com")
.then(()=>{
//alert("Success");
},
()=>{
alert("Sharing Failed!")
})
}
}
And here is the ProfilePage code which fails:
import { Component } from '#angular/core';
import { NavController, Platform } from 'ionic-angular';
import { WelcomePage } from '../welcome/welcome';
import {GoogleAnalytics} from 'ionic-native';
import { SocialSharing } from '#ionic-native/social-sharing';
import { Facebook, NativeStorage } from 'ionic-native';
//import { FacebookAuth, User, Auth } from '#ionic/cloud-angular';
//import { CloudSettings, CloudModule } from '#ionic/cloud-angular';
#Component({
selector: 'page-about',
templateUrl: 'about.html'
})
export class AboutPage {
user: any;
userReady: boolean = false;
constructor(
public navCtrl: NavController,
public platform: Platform,
private sharingVar: SocialSharing,
//public facebookAuth:FacebookAuth,
//public auth:Auth,
) {
// Check to see if user already exists (via FB login)
let env = this;
NativeStorage.getItem('user')
.then(function (data){
env.user = {
name: data.name,
gender: data.gender,
picture: data.picture
};
env.userReady = true;
// console.log(data.name);
}, function(error){
console.log(error);
});
// PLATFORM READY, do your thang!
this.platform.ready().then(() => {
// Ping Google Analytics
GoogleAnalytics.trackView("Profile Page", "http://foxboxapp.com/home", true);
});
}
otherShare(){
this.sharingVar.share("FOOX Social App","Get Awesome College Deals",null/*File*/,"http://fooxsocial.com")
.then(()=>{
//alert("Success");
},
()=>{
alert("Sharing Failed!")
})
}
doFbLogout(){
var nav = this.navCtrl;
Facebook.logout()
.then(function(response) {
//user logged out so we will remove him from the NativeStorage
NativeStorage.remove('user');
nav.push(WelcomePage);
}, function(error){
console.log(error);
});
}
}
And here is ProfilePage.html
<ion-header>
<ion-navbar color="light" hideBackButton="true">
<ion-buttons end>
<button ion-button icon-only (click)="otherShare()">
<ion-icon name="share"></ion-icon>
</button>
</ion-buttons>
</ion-navbar>
</ion-header>
<ion-content>
<ion-card class="pCard">
<div class="pHeader" align="center">
<div *ngIf="user" class="pImgBox" align="center">
<img class="pImage" src="{{ user.picture }}">
</div>
<div class="pUsername" align="center">
<div *ngIf="user"> {{user.name}} </div>
<br>
<span class="pSchool">(Santa Monica College)</span>
</div>
</div>
<ion-list>
<ion-item class="pItems">
Share App
</ion-item>
<ion-item class="pItems">
Give Us Feedback
</ion-item>
<ion-item class="pItems">
Suggest Vendors
</ion-item>
<ion-item class="pItems">
Privacy & Terms of Service
</ion-item>
<ion-item class="pItems">
Log Out
</ion-item>
<ion-item class="pItems">
Delete Account
</ion-item>
</ion-list>
</ion-card>
<button ion-button round (click)="doFbLogout()">Log Out</button>
</ion-content>
I should mention that, if I remove {{ user.name }} and {{ user.picture }} from my ProfilePage.html, there does NOT seem to be any problems. In fact, if you notice in the ts of ProfilePage, I can both Alert and Console.log the username (data.name) without any issues.
I'm a beginner and would appreciate any concise help in this regard. Thank you.

I finally found a solution. In the html file (ProfilePage.html), I used an *ngIf conditional:
<div *ngIf="user"> {{user.name}} </div>
This will introduce a delay such that the 'user' object is no longer null as it reads from NativeStorage.
Alternatively, an Elvis Operator also works for me:
<div> {{ user?.name }} </div>

Related

Angular 8 - problem with GET request for a json file

Please help, i'm trying to lift up my django web page with REST API and use Angular FrontEnd where I am beginning. I have followed some tutorials on how to consume REST api and somehow I'm making a mistake there. The browser shows no errors when requesting the content but it is not coming. I appreciate every bit of help.....
here we go usluga-list.component.ts:
import { Component, OnInit } from '#angular/core';
import { Observable } from "rxjs";
import { Usluga } from "../models/usluga";
import { UslugaService } from "../services/usluga.service";
#Component({
selector: 'app-usluga-list',
templateUrl: './usluga-list.component.html',
styleUrls: ['./usluga-list.component.css']
})
export class UslugaListComponent implements OnInit {
uslugi: Observable<Usluga[]>;
constructor(private uslugaService: UslugaService) { }
ngOnInit() {
this.loadUslugiData();
}
loadUslugiData(){
this.uslugi = this.uslugaService.getAllUslugi();
then i have usluga.service.ts:
import { Injectable } from '#angular/core';
import { HttpClient } from "#angular/common/http";
import { Observable } from "rxjs";
import { Usluga } from "../models/usluga";
#Injectable({
providedIn: 'root'
})
export class UslugaService {
private endpoint ='http://localhost:8000/uslugi/';
constructor(private http: HttpClient) { }
getAllUslugi(): Observable<any>{
return this.http.get(this.endpoint)
}
getUsluga(id: number): Observable<any> {
return this.http.get(this.endpoint + id);
}
}
Then I have app-routing.ts:
import { NgModule } from '#angular/core';
import { Routes, RouterModule } from '#angular/router';
import { UslugaListComponent } from './usluga-list/usluga-list.component';
const routes: Routes = [
{path: '', redirectTo: 'uslugi', pathMatch: 'full'},
{path: 'uslugi', component: UslugaListComponent}
];
#NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
It is odd as i get the json via localhost:8000/uslugi and it must be something wrong in the Angular:
[{"id": 1, "title": "Wizyta", "text": "Wizyta", "price": "10.99", "slug": "wizyta-p", "category": "psyc", "lekarz_id": 1}, {"id": 2, "title": "Wizyta d", "text": "Wizyta dia to...", "price": "199.30", "slug": "wiz", "category": "sek", "lekarz_id": 1}]
In order for the http call to be made you need to subscribe to it.
In your component:
this.uslugi = this.uslugaService.getAllUslugi();
// if you just want to test that it works:
this.uslugi.subscribe();
The proper way is to unsubscribe, there are many ways of doing this. This is one way that only require 'rxjs' and operators. So what you do is essentially like this:
#Component({
selector: 'app-usluga-list',
templateUrl: './usluga-list.component.html',
styleUrls: ['./usluga-list.component.css']
})
export class UslugaListComponent implements OnInit, OnDestroy {
uslugi: Observable<Usluga[]>;
unsubscribe = new Subject();
constructor(private uslugaService: UslugaService) { }
ngOnInit() {
this.loadUslugiData();
}
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
}
loadUslugiData(){
this.uslugi = this.uslugaService.getAllUslugi();
this.uslugi.pipe(takeUntil(this.unsubscribe)).subscribe();
}
Then that should make the http call for you
The observable variable (that stores the object from the api) name must be the same as the name in the html template, alike (flightss):
#Component({
selector: 'app-flight-list',
templateUrl: './usluga-list.component.html',
styleUrls: ['./usluga-list.component.css']
})
export class UslugaListComponent implements OnInit {
flightss: Observable<Usluga[]>;
constructor(private uslugaService: UslugaService) { }
ngOnInit() {
this.loadUslugisData();
}
loadUslugisData() {
this.flightss = this.uslugaService.getAllUslugi();
}
}
and in the template:
<tr *ngFor="let flight of flightss | async; let i=index">
<td class="text-center">{{flight.id}}</td>
<td>{{flight.title}}</td>
<td>{{flight.text}}</td>
<td>{{flight.price}}</td>
<td>{{flight.slug}}</td>
<td>{{flight.category}}</td>
<td class="td-actions text-right">
<a type="button" class="btn btn-success btn-just-icon btn-sm "
style="margin-left:10px;">
<i class="material-icons">Edit</i>
</a>
<button type="button" rel="tooltip" class="btn btn-danger btn-just-icon btn-sm" data-original-title="" title="" style="margin-left:10px;">
<i class="material-icons">Delete</i>
</button>
</td>
</tr>

Ionic2 : Uncaught (in promise): invalid link: calendar

I have implemented a side-menu in Ionic2.I am getting "Invalid link" when i click on the Event or Map button on the side-menu and sometimes i get the error as "Invalid Views to insert". I tried removing quotes from the calendar and gmap but it does not work out.
Please guide.
This is my TS file:
import { Component } from '#angular/core';
import { Platform , IonicPage } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { CalendarPage } from '../pages/calendar/calendar'
import { GmapPage } from '../pages/gmap/gmap'
import firebase from 'firebase';
import { LoginPage } from '../pages/login/login';
import { ViewChild } from '#angular/core';
import { NavController } from 'ionic-angular/navigation/nav-controller';
import { AuthProvider } from '../providers/auth/auth';
#IonicPage()
#Component({
templateUrl: 'app.html'
})
export class MyApp {
calendar: CalendarPage;
gmap: GmapPage;
#ViewChild('nav') nav: NavController;
rootPage: any = CalendarPage;
pages = []
constructor(platform: Platform, statusBar: StatusBar, splashScreen:SplashScreen,
public authProvider: AuthProvider) {
platform.ready().then(() => {
// Okay, so the platform is ready and our plugins are available.
// Here you can do any higher level native things you might need.
statusBar.styleDefault();
splashScreen.hide();
const unsubscribe = firebase.auth().onAuthStateChanged(user => {
if (!user) {
this.rootPage = 'LoginPage';
unsubscribe();
} else {
this.rootPage = 'EventPage';
unsubscribe();
}
});
});
}
onLoad(page : string) {
this.nav.setRoot(page);
}
onLogout(){
this.authProvider.logoutUser();
}
}
This is my HTML code :
<ion-menu [content] = "nav">
<ion-header>
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<button ion-item (click) = "onLoad('calendar')">Events</button>
<button ion-item (click) = "onLoad('gmap')">Maps</button>
<button ion-item (click) = "onLogout()">Logout</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-nav [root]="rootPage" #nav></ion-nav>

I am try to login with django using Angular4

i create Rest API for login in Django and i want to call it in angular4
heare is my angular4 code
login.components.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { Http, Response, Headers} from '#angular/http';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
constructor(private router:Router, private http:Http) { }
getData = [];
with this function i get data from my APIand i am trying to compare this data with form data
fatchData = function(){
this.http.get("http://127.0.0.1:8000/loginAdmin/").subscribe((res:Response) => {
this.getData = res.json();
})
}
loginUser(e){
e.preventDefault();
var username = e.target.elements[0].value;
var password = e.target.elements[1].value;
if(username == 'this.getData.username' && password == 'this.getData.password')
{
this.router.navigate(['/deshbord'])
}
else{
console.log('Error Find');
}
}
ngOnInit() {
this.fatchData();
}
}
this is my login.comonents.login i want that when user give user name and password its compare with my API data and it's true then navigate to other page..
<form (submit)="loginUser($event)">
<div class="input">
<label>UserName</label>
<input type="text">
</div>
<div class="input">
<label>password</label>
<input type="password">
</div>
<div class="input">
<input type="submit" value="Login">
</div>
</form>

How to hide native android keyboard in IONIC 2 when clicking on a text box?

How to hide native android keyboard when clicking on text box using IONIC 2? I have installed IONIC keyboard plugin from https://ionicframework.com/docs/native/keyboard/ link and uses this.keyboard.close();
But still keyboard is opening. Help me how to close the keyboard. I am basically showing DOB from the datepicker plugin in a TEXTBOXenter image description here.
This is the ts file(datepicker1.ts)
import { Component } from '#angular/core';
import { IonicPage, NavController, NavParams } from 'ionic-angular';
import { DatePicker } from '#ionic-native/date-picker';
import { Keyboard } from '#ionic-native/keyboard';
#IonicPage()
#Component({
selector: 'page-datepicker1',
templateUrl: 'datepicker1.html',
})
export class Datepicker1Page {
public today:any;
constructor(public navCtrl: NavController, public navParams: NavParams,private datePicker: DatePicker,private keyboard: Keyboard) {
}
ionViewDidLoad() {
console.log('ionViewDidLoad Datepicker1Page');
}
openDatepicker()
{
this.keyboard.close();
this.datePicker.show({
date: new Date(),
mode: 'date',
androidTheme: this.datePicker.ANDROID_THEMES.THEME_DEVICE_DEFAULT_LIGHT
}).then(
date => {
this.today=date.getDate()+'/'+date.getMonth()+'/'+date.getFullYear()},
err => console.log('Error occurred while getting date: ', err)
);
}
}
And this is the datepicker1.html page
<ion-header>
<ion-navbar>
<ion-title>datepicker page</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-item>
<ion-label>DOB</ion-label>
<ion-input type="text" name="DOB" (click)="openDatepicker()" [(ngModel)]="today" ng-readonly></ion-input>
</ion-item>
</ion-content>
You have missed to declare the today variable in the class and you missed to add disabled="true" in ion-input tag. Everything is working fine and I have tested it.
TS File
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { Keyboard } from '#ionic-native/keyboard';
import { DatePicker } from '#ionic-native/date-picker';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController, public keyboard : Keyboard, public datePicker : DatePicker) {
}
today : any;
openDatepicker(){
this.keyboard.close();
this.datePicker.show({
date: new Date(),
mode: 'date',
androidTheme: this.datePicker.ANDROID_THEMES.THEME_DEVICE_DEFAULT_LIGHT
}).then(
date => {
this.today=date.getDate()+'/'+date.getMonth()+'/'+date.getFullYear()},
err => console.log('Error occurred while getting date: ', err)
);
}
}
HTML File
<ion-header>
<ion-navbar>
<ion-title>
Ionic Blank
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-item>
<ion-label>DOB</ion-label>
<ion-input disabled="true" type="text" name="DOB" (click)="openDatepicker()" [(ngModel)]="today" ng-readonly></ion-input>
</ion-item>
</ion-content>
1) import { DatePicker } from '#ionic-native/date-picker/ngx'; in app.module.ts and keyboard.page.ts
2) public keyboard : Keyboard, in your constructor inject
3) https://ionicframework.com/docs/native/keyboard Take reference from this Official site
openDatepickerStart(){
setTimeout(() => {
this.keyboard.hide();
}, 100);
this.datePicker.show({
date: new Date(),
mode: 'date',
androidTheme: this.datePicker.ANDROID_THEMES.THEME_DEVICE_DEFAULT_LIGHT
}).then(
date => {
this.SelectDateModelDetails.get('StartTime').patchValue(date.getDate()+'/'+date.getMonth()+'/'+date.getFullYear())},
err => console.log('Error occurred while getting date: ', err)
);
}

ionic 2 Side menu and log out and back key navigation

I am trying to achieve a log out functionality. I am using FB authentication. My problem here is after I do a logout successfully(This happens from the Side menu ) I return to the Login Screen. But now if I tap the device's back button it is taking me to the homepage(. Any idea how to prevent this ?
This is my app.component.ts
import { Component, ViewChild } from '#angular/core';
import { Platform, Nav, AlertController } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { LoginPage } from '../pages/login/login';
import { NativeStorage } from '#ionic-native/native-storage';
import { TabsPage } from '../pages/tabs/tabs';
import { Facebook } from 'ionic-native';
#Component({
templateUrl: 'app.html',
})
export class MyApp {
#ViewChild(Nav) nav: Nav;
rootPage: any = LoginPage;
constructor(platform: Platform, statusBar: StatusBar, splashScreen: SplashScreen, private nativeStorage: NativeStorage, private alertCtrl: AlertController) {
platform.ready().then(() => platform.ready().then(() => {
this.nativeStorage.getItem("userId").then((data) => {
console.log(data.userExists);
this.rootPage = TabsPage;
this.nav.push(TabsPage);
}, (error) => {
console.log("No data in storage");
this.nav.push(LoginPage);
})
statusBar.styleDefault();
splashScreen.hide();
})
)
}
presentConfirm() {
let alert = this.alertCtrl.create({
title: "Confirm Logout",
message: "Do you really really want to quit this awesome app?",
buttons: [{
text: 'Nah! Just Kidding!', role: 'cancel', handler: () => {
}
},
{
text: "Ok",
handler: () => {
this.nativeStorage.clear();
this.nav.push(LoginPage);
this.rootPage = LoginPage;
Facebook.logout().then((response) => {
}, (error) => {
})
}
}]
});
alert.present();
}
}
This is my login page. Login.ts
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { Facebook } from 'ionic-native';
import { NativeStorage } from '#ionic-native/native-storage';
import { TabsPage } from '../tabs/tabs'
#Component({
selector: 'login-home',
templateUrl: 'login.html'
})
export class LoginPage {
constructor(public navCtrl: NavController, private nativeStorage: NativeStorage) {
}
FBLogin() {
//this.navCtrl.push(TabsPage); - To be used on browser environment
Facebook.login(['email']).then((response) => {
Facebook.getLoginStatus().then((response) => {
if (response.status == 'connected') {
this.navCtrl.push(TabsPage); // - to be used on device
console.log("Setting Storage")
this.nativeStorage.setItem("userId", { userExists: true });
Facebook.api('/' + response.authResponse.userID + '?fields=id,name,gender', []).then((response) => {
}, (error) => {
alert(error)
})
}
else
alert("Not Logged in");
})
}, (error) => {
console.log((error));
})
}
}
This is my Menu
<ion-menu swipeEnabled="false" side="right" [content]="content">
<ion-toolbar>
<ion-title>Menu</ion-title>
</ion-toolbar>
<ion-content>
<ion-list>
<p> </p>
<button menuClose padding-top ion-item> Test 1 </button>
<button menuClose ion-item> Test 2 </button>
<button menuClose ion-item (click)="presentConfirm()"><ion-icon name="power"></ion-icon> Logout </button>
</ion-list>
</ion-content>
</ion-menu>
<ion-nav id="nav" [root]="rootPage" #content swipe-back-enabled="false"></ion-nav>
Your issue is you are doing:
this.nav.push(LoginPage);
in your logout handler.
This means LoginPage is added on top of your old navigation stack. You need to set a new stack and set LoginPage as root.
Do :
this.nav.setRoot(LoginPage);