Related
Hi I need 'select from list' functionality on a form but with the ability to enter a value manually if needed. I've been trying ion-select but there doesn't seem to be a way to have a manual override. Is there a way to do this?
Thanks
For example
<ion-header>
<ion-toolbar>
<ion-title>kitlist testy</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<form [formGroup]="myForm">
<ion-list>
<ion-item>
<ion-label stacked>Lens</ion-label>
<ion-select placeholder="Select One">
<ion-select-option value="f">Female</ion-select-option>
<ion-select-option value="m">Male</ion-select-option>
</ion-select>
<ion-input type="text" formControlName='lens'></ion-input>
</ion-item>
</ion-list>
</form>
</ion-content>
will give
I want the user to be able to add their own value - which I will then store.
Thanks
Following Sergey's very helpful answer I have tried getting this to work and I'm stuck at inputAlert.onDidDismiss which gives me
Expected 0 arguments, but got 1
Here's the code which I have adjusted for my use case:-
import { Component, OnInit } from "#angular/core";
import { FormBuilder, FormGroup } from "#angular/forms";
import { AlertController } from "#ionic/angular";
#Component({
selector: "app-kitlist",
templateUrl: "./kitlist.page.html",
styleUrls: ["./kitlist.page.scss"]
})
export class KitlistPage implements OnInit {
kitlist = ["lens1", "lens2", "Custom"];
currentLens: any;
myForm: FormGroup;
constructor(
private fb: FormBuilder,
private alertController: AlertController
) {
this.myForm = new FormGroup({});
}
ngOnInit() {
this.myForm = this.fb.group({
lens: ""
});
this.myForm.valueChanges.subscribe(console.log);
}
submitForm() {
console.log("submit");
}
selectChanged(selectedLens) {
if (selectedLens === "Custom") {
this.inputCustomLensValue();
} else {
this.currentLens = selectedLens;
}
}
async inputCustomLensValue() {
const inputAlert = await this.alertController.create({
header: "Enter your custom lens:",
inputs: [{ type: "text", placeholder: "type in" }],
buttons: [{ text: "Cancel" }, { text: "Ok" }]
});
inputAlert.onDidDismiss(data => {
let customLensName: string = data.data.values[0];
if (customLensName) {
let indexFound = this.kitlist.findIndex(
lens => lens === customLensName
);
if (indexFound === -1) {
this.kitlist.push(customLensName);
this.currentLens = customLensName;
} else {
this.currentLens = this.kit[indexFound];
}
}
});
await inputAlert.present();
}
}
Since ion-select under the hood uses alert controller, I would leverage it directly and I would have a couple of alerts working together here:
In your template:
<ion-item>
<ion-label>Hair Color</ion-label>
<ion-button slot="end" (click)="selectColors()">{{ currentOptionLabel }}
<ion-icon slot="end" name="arrow-dropdown"></ion-icon>
</ion-button>
</ion-item>
You can style ion-button according to your needs.
Now in your ts file we can import Alert Controller and have 2 of them: one for selecting premade options and one that we will create input type of alert in case our user wants to add custom value.
I am not using button's handler's methods here to make sure Angular can pick up all the data changes:
import { Component } from '#angular/core';
import { AlertController } from '#ionic/angular';
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.css'],
})
export class HomePage {
public colorOptions: Array<{type: string, label: string, value: string}>
public currentColorOptionIndex: number;
public currentOptionLabel: string;
constructor(public alertController: AlertController) {
this.currentColorOptionIndex = 1;
this.colorOptions = [
{
type: "radio",
label: "Custom",
value: "Custom"
},
{
type: "radio",
label: "Brown",
value: "Brown",
},
{
type: "radio",
label: "Dark",
value: "Dark",
}
]
this.currentOptionLabel = this.colorOptions[this.currentColorOptionIndex].label;
}
async selectColors() {
const radioAlert = await this.alertController.create({
header: 'Prompt!',
inputs: this.colorOptions as any,
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary'
}, {
text: 'Ok'
}
]
});
await radioAlert.present();
radioAlert.onDidDismiss().then((data) => {
let selectedValue = data.data.values;
if (selectedValue === 'Custom') {
this.inputCustomColorValue()
};
this.currentColorOptionIndex = this.colorOptions.findIndex(option => option.value == selectedValue)
this.currentOptionLabel = this.colorOptions[this.currentColorOptionIndex].label;
})
}
async inputCustomColorValue() {
const inputAlert = await this.alertController.create({
header: 'Enter your custom color:',
inputs: [
{
type: 'text',
placeholder: 'type in'
}
],
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary'
}, {
text: 'Ok',
}
]
});
await inputAlert.present();
inputAlert.onDidDismiss().then((data) => {
let customValue = data.data.values[0];
let indexFound = this.colorOptions.findIndex(option => option.value == customValue)
if (indexFound !== -1) {
this.currentColorOptionIndex = indexFound
} else {
this.colorOptions.push(
{
type: 'radio',
label: customValue,
value: customValue,
}
)
this.currentColorOptionIndex = this.colorOptions.length - 1;
};
this.currentOptionLabel = this.colorOptions[this.currentColorOptionIndex].label;
})
}
}
Updated: added the fact that now in latest Ionic versions (compared to Stackblitz that uses old 4 beta) onDidDismiss hook returns Promise and requires onDidDismiss.then((data) => {}) syntax vs onDidDismiss((data => {})
I am building an app with ionic 5, i want to show ion-loader when a user tries to login, and after a response is gotten from the server, it will dismiss the ion-loader, but when i tried it, i got this error
Error: Uncaught (in promise): TypeError: Cannot read property 'dismiss' of undefined
here is my code
import { Component, OnInit } from '#angular/core';
import { HomePage } from '../home/home.page';
import { NavController, AlertController, LoadingController } from '#ionic/angular';
import { AuthServiceService } from '../auth-service.service';
#Component({
selector: 'app-login',
templateUrl: './login.page.html',
styleUrls: ['./login.page.scss'],
})
export class LoginPage implements OnInit {
ngOnInit() {
}
registerCredentials = { email: '', password: '' };
loaderToShow: any;
constructor(
public navCtrl: NavController,
private auth: AuthServiceService,
private alertCtrl: AlertController,
private loadingCtrl: LoadingController
) {
console.log(this.registerCredentials);
}
public login() {
this.showLoading();
this.auth.login(this.registerCredentials).subscribe(allowed => {
if (allowed) {
this.loaderToShow.dismiss();
console.log('canceal')
} else {
this.showError('Access Denied');
}
}, error => {
this.showError(error);
});
}
public async showLoading() {
this.loaderToShow = await this.loadingCtrl.create({
message: 'Please Wait...'
});
await this.loaderToShow.present();
}
public async showError(text) {
this.loaderToShow.dismiss();
let alert = await this.alertCtrl.create({
header: 'Fail',
message: text,
buttons: ['OK']
});
await alert.present();
}
}
Pls how can i properly dismiss the ion-loader
Create a hideLoading() method like below can call it when you want to hide the loading circle.
async hideLoading() {
this.loadingController.getTop().then(loader => {
if (loader) {
loader.dismiss();
}
});
}
I created below class to handle show hide of loading in my ionic application.
loading.service.ts
import { Injectable } from '#angular/core';
import { LoadingController } from '#ionic/angular';
#Injectable({
providedIn: 'root'
})
export class LoadingService {
isLoading = false;
constructor(public loadingController: LoadingController) { }
async showLoading(message?: string) {
this.isLoading = true;
this.loadingController.create({
message: message ? message : 'Please wait...'
}).then(loader => {
loader.present().then(() => {
if (!this.isLoading) {
loader.dismiss();
}
});
});
}
async hideLoading() {
this.isLoading = false;
this.loadingController.getTop().then(loader => {
if (loader) {
loader.dismiss();
}
});
}
}
Usage in a component:
export class SomePage implements OnInit {
subscription: Subscription;
constructor(private loadingService: LoadingService) { }
someMethod(updateNameForm: NgForm) {
this.loadingService.showLoading();
this.someService.someMethod().subscribe(response => {
// Some code
});
this.subscription.add(() => {
this.loadingService.hideLoading();
});
}
}
}
The solution is to add await to the call of the function showLoading
public login() {
await this.showLoading();
this.auth.login(this.registerCredentials).subscribe(allowed => {
if (allowed) {
this.loaderToShow.dismiss();
console.log('canceal')`enter code here`
} else {`enter code here`
this.showError('Access Denied');
}
}, error => {
this.showError(error);
});
}
async showLoading() {
this.loaderToShow = await this.loadingCtrl.create({
message: 'Please Wait...'
});
await this.loaderToShow.present();
}
async showError(text) {
await this.loaderToShow.dismiss();
let alert = await this.alertCtrl.create({
header: 'Fail',
message: text,
buttons: ['OK']
});
await alert.present();
}
I am working on a project in Ionic, and when I login, I did set the storage('id') which was used in the app.component.ts to get the user details, but when I run the code, it didn't work, but when I reload the whole page (Ctrl + R), it then works.
Here is my code.
login.ts:
import {Component} from "#angular/core";
import {NavController, AlertController, ToastController, MenuController} from "ionic-angular";
import {HomePage} from "../home/home";
import {RegisterPage} from "../register/register";
import { ServicesProvider } from '../../providers/services/services';
import { Storage } from '#ionic/storage';
#Component({
selector: 'page-login',
templateUrl: 'login.html'
})
export class LoginPage {
private user = {
email: '',
password: ''
}
private setputt:string;
constructor(public navCtrl: NavController,
public forgotCtrl: AlertController,
public menu: MenuController,
public toastCtrl: ToastController,
private storage: Storage,
public ServicesProvider: ServicesProvider
) {
this.menu.swipeEnable(false);
}
register() {
this.navCtrl.setRoot(RegisterPage);
}
login(user){
this.ServicesProvider.loginpost(user).subscribe(
data => {
if(data.success){
this.setputt = data.message;
if(this.setputt == 'Login Successfull'){
this.storage.set('id', data.id);
this.navCtrl.setRoot(HomePage);
}
}
else{
this.setputt = data.message;
}
},
error => {
console.log(error);
}
)
}
// set a key/value
// storage.set('name', 'Max');
// // Or to get a key/value pair
// storage.get('age').then((val) => {
// console.log('Your age is', val);
// });
// storage.remove('name');
forgotPass() {
let forgot = this.forgotCtrl.create({
title: 'Forgot Password?',
message: "Enter you email address to send a reset link password.",
inputs: [
{
name: 'email',
placeholder: 'Email',
type: 'email'
},
],
buttons: [
{
text: 'Cancel',
handler: data => {
console.log('Cancel clicked');
}
},
{
text: 'Send',
handler: data => {
console.log('Send clicked');
let toast = this.toastCtrl.create({
message: 'Email was sended successfully',
duration: 3000,
position: 'top',
cssClass: 'dark-trans',
closeButtonText: 'OK',
showCloseButton: true
});
toast.present();
}
}
]
});
forgot.present();
}
}
app.component.ts:
import { Component, ViewChild } from '#angular/core';
import { Platform, Nav } from 'ionic-angular';
import { StatusBar } from '#ionic-native/status-bar';
import { SplashScreen } from '#ionic-native/splash-screen';
import { Storage } from '#ionic/storage';
import { ServicesProvider } from '../providers/services/services';
import { HomePage } from '../pages/home/home';
import {LoginPage} from "../pages/login/login";
import {ProfilePage} from "../pages/profile/profile";
import {FriendsPage} from "../pages/friends/friends";
import {YearbooksPage} from "../pages/yearbooks/yearbooks";
import {ChatPage} from "../pages/chat/chat";
import {FilesPage} from "../pages/files/files";
import {CheckLoginPage} from "../pages/check-login/check-login";
export interface MenuItem {
title: string;
component: any;
icon: string;
}
#Component({
templateUrl: 'app.html'
})
export class MyApp {
#ViewChild(Nav) nav: Nav;
rootPage: any = CheckLoginPage;
appMenuItems: Array<MenuItem>;
public FullNamer;
public pixr;
public id:number;
constructor(
platform: Platform,
statusBar: StatusBar,
splashScreen: SplashScreen,
public storage: Storage,
public ServicesProvider: ServicesProvider
) {
platform.ready().then(() => {
statusBar.styleDefault();
splashScreen.hide();
});
this.storage.get('id').then((vals) => {
if (vals != null) {
this.ServicesProvider.getDetails(vals).subscribe(data=>{
// console.log(data);
this.pixr = this.ServicesProvider.theurl+data.pix;
this.FullNamer = data.fullname;
});
}
});
this.appMenuItems = [
{title: 'Home', component: HomePage, icon: 'home'},
{title: 'Files', component: FilesPage, icon: 'ios-folder'},
{title: 'Friends', component: FriendsPage, icon: 'ios-people'},
{title: 'Yearbooks', component: YearbooksPage, icon: 'ios-book'},
{title: 'Chat', component: ChatPage, icon: 'md-chatbubbles'}
];
}
ionViewCanEnter(){
}
openPage(page) {
this.nav.setRoot(page.component);
}
GoPages(){
this.nav.setRoot(ProfilePage);
}
logout() {
this.storage.remove('id');
this.storage.remove('FullName');
this.nav.setRoot(LoginPage);
}
}
app.html
<ion-menu side="left" id="authenticated" [content]="content">
<ion-header>
<ion-toolbar class="user-profile">
<ion-grid>
<ion-row>
<ion-col col-4>
<div class="user-avatar">
<img [src]="pixr">
</div>
</ion-col>
<ion-col padding-top col-8>
<h2 ion-text class="no-margin bold text-white">
{{FullNamer}}
</h2>
<span ion-text color="light">Customer</span>
</ion-col>
</ion-row>
<ion-row no-padding class="other-data">
<ion-col no-padding class="column">
<button ion-button icon-left small full class="round" color="light" menuClose (click)="GoPages()">
<ion-icon name="ios-person"></ion-icon>
Edit Profile
</button>
</ion-col>
<ion-col no-padding class="column">
<button ion-button icon-left class="round" small full color="light" menuClose (click)="logout()">
<ion-icon name="log-out"></ion-icon>
Log Out
</button>
</ion-col>
</ion-row>
</ion-grid>
</ion-toolbar>
</ion-header>
<ion-content color="primary">
<ion-list class="user-list">
<button ion-item menuClose class="text-1x" *ngFor="let menuItem of appMenuItems" (click)="openPage(menuItem)">
<ion-icon item-left [name]="menuItem.icon" color="primary"></ion-icon>
<span ion-text color="primary">{{menuItem.title}}</span>
</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-nav [root]="rootPage" #content swipeBackEnabled="false"></ion-nav>
service.ts:
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { Storage } from '#ionic/storage';
#Injectable()
export class ServicesProvider {
public theurl = 'http://localhost/HoleeSheet/php/';
public tittle = 'Holee Sheet';
public id:number;
constructor(public http: HttpClient, private storage: Storage) {
this.storage.get('id').then((valr) => {
if (valr != null) {
this.id = valr;
}
});
}
loginpost(user){
return this.http.put<obbbbs>(this.theurl+'login.php', {
email: user.email,
password: user.password
});
}
getDetails(humid){
console.log(humid);
return this.http.post<details>(this.theurl+'getDetails.php', {
id: humid
});
}
}
interface details{
'fullname': string,
'pix':string
}
interface obbbbs {
'success': 'boolean',
'message': 'string',
'id': 'string'
}
How can I solve this issue?
Welcome to Stack Overflow.
// LoginPage.login method (login.ts)
this.storage.set('id', data.id);
this.navCtrl.setRoot(HomePage);
You're navigating to the home page before the value gets saved to storage. You should wait until the promise returned by this.storage.set is resolved before continuing navigation:
// LoginPage.login method (login.ts)
this.storage.set('id', data.id)
.then(() => this.navCtrl.setRoot(HomePage));
This is Ionic3 project and I was doing login page.
This page I want to show login button first in slide menu, after I login into apps, hidden login button and showing logout button. But when I was doing it this error coming out:
Can't resolve all parameters for UserDataProvider: ([object Object],
[object Object], ?).
This is my ionic info:
Ionic Framework: 3.6.0
Ionic Native: 2.4.1
Ionic App Scripts: 2.1.3
Angular Core: 4.0.0
Angular Compiler CLI: 4.0.0
Node: 6.11.3
OS Platform: macOS Sierra
Navigator Platform: MacIntel
User Agent: Mozilla/5.0 (Macintosh; Intel
app.component.ts
import { Component, ViewChild } from '#angular/core';
import { Events, MenuController, Nav, Platform } from 'ionic-angular';
import { StatusBar, Splashscreen } from 'ionic-native';
import { QQSDK, QQShareOptions } from '#ionic-native/qqsdk';
import { Facebook, FacebookLoginResponse } from '#ionic-native/facebook';
import { TabsPage } from '../pages/tabs/tabs';
declare var Wechat:any;
export interface PageInterface {
title: string;
name: string;
component: any;
icon: string;
logsOut?: boolean;
index?: number;
tabName?: string;
tabComponent?: any;
}
#Component({
templateUrl: 'app.html'
})
export class MyApp {
#ViewChild(Nav) nav: Nav;
appPages: PageInterface[] = [
{ title: 'News', name: 'TabsPage', component: TabsPage, index: 0, icon: 'ios-globe-outline' }
];
loggedInPages: PageInterface[] = [
{ title: 'News', name: 'TabsPage', component: TabsPage, index: 0, icon: 'ios-globe-outline' },
{ title: 'Logout', name: 'TabsPage', component: TabsPage, icon: 'log-out', logsOut: true }
];
userData = null;
rootPage = TabsPage;
pages: Array<{title: string, component: any}>;
constructor(public platform: Platform, public events: Events, public menu: MenuController,
private qq: QQSDK,private fb: Facebook) {
this.initializeApp();
this.userData.hasLoggedIn().then((hasLoggedIn) => {
this.enableMenu(hasLoggedIn === true);
});
this.enableMenu(true);
this.listenToLoginEvents();
}
openPage(page: PageInterface) {
let params = {};
if (page.index) {
params = { tabIndex: page.index };
}
if (this.nav.getActiveChildNavs().length && page.index != undefined) {
this.nav.getActiveChildNavs()[0].select(page.index);
} else {
// Set the root of the nav with params if it's a tab index
this.nav.setRoot(page.name, params).catch((err: any) => {
console.log(`Didn't set nav root: ${err}`);
});
}
if (page.logsOut === true) {
// Give the menu time to close before changing to logged out
this.userData.logout();
}
}
listenToLoginEvents() {
this.events.subscribe('user:login', () => {
this.enableMenu(true);
});
this.events.subscribe('user:signup', () => {
this.enableMenu(true);
});
this.events.subscribe('user:logout', () => {
this.enableMenu(false);
});
}
enableMenu(loggedIn: boolean) {
this.menu.enable(loggedIn, 'loggedInMenu');
this.menu.enable(!loggedIn, 'loggedOutMenu');
}
isActive(page: PageInterface) {
let childNav = this.nav.getActiveChildNavs()[0];
// Tabs are a special case because they have their own navigation
if (childNav) {
if (childNav.getSelected() && childNav.getSelected().root === page.tabComponent) {
return 'primary';
}
return;
}
if (this.nav.getActive() && this.nav.getActive().name === page.name) {
return 'primary';
}
return;
}
initializeApp() {
this.platform.ready().then(() => {
StatusBar.styleDefault();
Splashscreen.hide();
});
}
QQLogin(){
const loginOptions: QQShareOptions = {
client: this.qq.ClientType.QQ,
};
this.qq.ssoLogin(loginOptions)
.then((result) => {
console.log('shareNews success');
alert('token is ' + result.access_token);
alert('userid is ' + result.userid);
})
.catch(error => {
console.log(error);
});
this.qq.logout().then(() => {
console.log('logout success');
}).catch(error => {
console.log(error);
});
}
wechatLogin(){
let scope = "snsapi_userinfo",
state = "_" + (+new Date());
Wechat.auth(scope, state, function (response) {
// you may use response.code to get the access token.
alert(JSON.stringify(response));
}, function (reason) {
alert("Failed: " + reason);
});
}
weiboLogin(){}
FBLogin(){
this.fb.login(['email', 'public_profile']).then((response: FacebookLoginResponse) => {
this.fb.api('me?fields=id,name,email,first_name,picture.width(360).height(360).as(picture_large)', []).then(profile => {
this.userData = {email: profile['email'], first_name: profile['first_name'], picture: profile['picture_large']['data']['url'], username: profile['name']}
});
});
}
}
EDIT:
app.html
<ion-menu id="loggedOutMenu" [content]="content">
<ion-header>
<ion-toolbar color="danger">
<ion-title>菜单</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-list-header>请登录</ion-list-header>
<button style="width:40%" ion-button round outline (click)= "QQLogin()">
<ion-icon name="minan-qq"></ion-icon>
</button>
<button color="wechat" style="width:40%" ion-button round outline (click)= "wechatLogin()">
<ion-icon name="minan-wechat"></ion-icon>
</button>
<button color="danger" style="width:40%" ion-button round outline (click)= "weiboLogin()">
<ion-icon name="minan-weibo"></ion-icon>
</button>
<button color="facebook" style="width:40%" ion-button round outline (click)= "FBLogin()">
<ion-icon name="minan-facebook"></ion-icon>
</button>
</ion-list>
<ion-list>
<ion-list-header>导航栏1</ion-list-header>
<button menuClose ion-item *ngFor="let p of appPages" (click)="openPage(p)">
<ion-icon item-start [name]="p.icon" [color]="isActive(p)"></ion-icon>
{{p.title}}
</button>
</ion-list>
</ion-content>
</ion-menu>
<ion-menu id="loggedInMenu" [content]="content">
<ion-header>
<ion-toolbar color="danger">
<ion-title>菜单</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-card *ngIf="userData">
<ion-card-header>账号</ion-card-header>
<ion-thumbnail>
<img [src]="userData.picture" />
</ion-thumbnail>
<ion-card-title>{{ userData.username }}</ion-card-title>
<!-- <ion-card-content>
<p>Email: {{ userData.email }}</p>
<p>First Name: {{ userData.first_name }}</p>
</ion-card-content> -->
</ion-card>
<ion-list>
<ion-list-header>导航栏2</ion-list-header>
<button menuClose ion-item *ngFor="let p of loggedInPages" (click)="openPage(p)">
<ion-icon item-start [name]="p.icon" [color]="isActive(p)"></ion-icon>
{{p.title}}
</button>
</ion-list>
</ion-content>
</ion-menu>
<!-- Disable swipe-to-go-back because it's poor UX to combine STGB with side menus -->
<ion-nav [root]="rootPage" #content swipeBackEnabled="false"></ion-nav>
UPDATE:
app.module.ts
import { NgModule, ErrorHandler } from '#angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { QQSDK } from '#ionic-native/qqsdk';
import { Facebook } from '#ionic-native/facebook';
import { SocialSharing } from '#ionic-native/social-sharing';
import { PhotoViewer } from '#ionic-native/photo-viewer';
import { BrowserModule } from '#angular/platform-browser';
import { HttpModule } from '#angular/http';
import { OneSignal } from '#ionic-native/onesignal';
import { IonicStorageModule } from '#ionic/storage';
import { MyApp } from './app.component';
import { SosPage } from '../pages/sos/sos';
import { ServicesPage } from '../pages/services/services';
import { NewsPage } from '../pages/news/news';
import { NewsDetailPage } from '../pages/news-detail/news-detail';
import { ServicesDetailPage } from '../pages/services-detail/services-detail';
import { TabsPage } from '../pages/tabs/tabs';
import { InsurencePage } from '../pages/insurence/insurence';
import { InsurenceDetailPage } from '../pages/insurence-detail/insurence-detail';
import { EducationPage } from '../pages/education/education';
import { EducationDetailPage } from '../pages/education-detail/education-detail';
import { TravelPage } from '../pages/travel/travel';
import { TravelDetailPage } from '../pages/travel-detail/travel-detail';
import { InvestmentPage } from '../pages/investment/investment';
import { InvestmentDetailPage } from '../pages/investment-detail/investment-detail';
import { LifePage } from '../pages/life/life';
import { LifeDetailPage } from '../pages/life-detail/life-detail';
import { NewsDataProvider } from '../providers/news-data/news-data';
import { ServicesDataProvider } from '../providers/services-data/services-data';
import { UserDataProvider } from '../providers/user-data/user-data';
#NgModule({
declarations: [
MyApp,
SosPage,
ServicesPage,
NewsPage,
TabsPage,
NewsPage,
NewsDetailPage,
ServicesDetailPage,
InsurencePage,EducationPage,TravelPage,InvestmentPage,LifePage,
InsurenceDetailPage,TravelDetailPage,InvestmentDetailPage,EducationDetailPage,LifeDetailPage
],
imports: [
BrowserModule,
HttpModule,
IonicStorageModule.forRoot(),
IonicModule.forRoot(MyApp,{
})
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
SosPage,
ServicesPage,
NewsPage,
TabsPage,
NewsPage,
NewsDetailPage,
ServicesDetailPage,
InsurencePage,EducationPage,TravelPage,InvestmentPage,LifePage,
InsurenceDetailPage,TravelDetailPage,InvestmentDetailPage,EducationDetailPage,LifeDetailPage
],
providers: [{provide: ErrorHandler, useClass: IonicErrorHandler},
NewsDataProvider,
ServicesDataProvider,
SocialSharing,
PhotoViewer,
QQSDK,Facebook,
OneSignal,
UserDataProvider]
})
export class AppModule {}
user-data.ts
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import { Events } from 'ionic-angular';
import 'rxjs/add/operator/map';
#Injectable()
export class UserDataProvider {
HAS_LOGGED_IN = 'hasLoggedIn';
constructor(public http: Http, public events: Events, public storage: Storage) {
console.log('Hello UserDataProvider Provider');
}
login(username: string): void {
this.storage.set(this.HAS_LOGGED_IN, true);
this.setUsername(username);
this.events.publish('user:login');
};
signup(username: string): void {
this.storage.set(this.HAS_LOGGED_IN, true);
this.setUsername(username);
this.events.publish('user:signup');
};
logout(): void {
this.storage.remove(this.HAS_LOGGED_IN);
this.storage.remove('username');
this.events.publish('user:logout');
};
setUsername(username: string): void {
this.storage.set('username', username);
};
getUsername(): Promise<string> {
return this.storage.get('username').then((value) => {
return value;
});
};
hasLoggedIn(): Promise<boolean> {
return this.storage.get(this.HAS_LOGGED_IN).then((value) => {
return value === true;
});
};
}
please update your code file as below
user-data.ts
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import { Events } from 'ionic-angular';
import { Storage } from '#ionic/storage';
import 'rxjs/add/operator/map';
#Injectable()
export class UserDataProvider {
HAS_LOGGED_IN = 'hasLoggedIn';
constructor(public http: Http, public events: Events, public storage: Storage) {
console.log('Hello UserDataProvider Provider');
}
login(user: any): void {
this.storage.set(this.HAS_LOGGED_IN, true);
this.setUser(user);
this.events.publish('user:login');
};
signup(user: any): void {
this.storage.set(this.HAS_LOGGED_IN, true);
this.setUser(user);
this.events.publish('user:signup');
};
logout(): void {
this.storage.remove(this.HAS_LOGGED_IN);
this.storage.remove('username');
this.events.publish('user:logout');
};
setUser(user: any): void {
this.storage.set('user', user);
};
getUser(): Promise<any> {
return this.storage.get('user').then((value) => {
return value;
});
};
hasLoggedIn(): Promise<boolean> {
return this.storage.get(this.HAS_LOGGED_IN).then((value) => {
return value === true;
});
};
}
app.component.ts
import { Component, ViewChild } from '#angular/core';
import { Events, MenuController, Nav, Platform } from 'ionic-angular';
import { StatusBar, Splashscreen } from 'ionic-native';
import { QQSDK, QQShareOptions } from '#ionic-native/qqsdk';
import { Facebook, FacebookLoginResponse } from '#ionic-native/facebook';
import { UserDataProvider } from '../src/to/user-data'
import { TabsPage } from '../pages/tabs/tabs';
declare var Wechat:any;
export interface PageInterface {
title: string;
name: string;
component: any;
icon: string;
logsOut?: boolean;
index?: number;
tabName?: string;
tabComponent?: any;
}
#Component({
templateUrl: 'app.html'
})
export class MyApp {
#ViewChild(Nav) nav: Nav;
appPages: PageInterface[] = [
{ title: 'News', name: 'TabsPage', component: TabsPage, index: 0, icon: 'ios-globe-outline' }
];
loggedInPages: PageInterface[] = [
{ title: 'News', name: 'TabsPage', component: TabsPage, index: 0, icon: 'ios-globe-outline' },
{ title: 'Logout', name: 'TabsPage', component: TabsPage, icon: 'log-out', logsOut: true }
];
//userData = null;
rootPage = TabsPage;
pages: Array<{title: string, component: any}>;
constructor(public platform: Platform, public events: Events, public menu: MenuController,
private qq: QQSDK,private fb: Facebook, private userData: UserDataProvider) {
this.initializeApp();
this.userData.hasLoggedIn().then((hasLoggedIn) => {
this.enableMenu(hasLoggedIn === true);
});
this.enableMenu(true);
this.listenToLoginEvents();
}
openPage(page: PageInterface) {
let params = {};
if (page.index) {
params = { tabIndex: page.index };
}
if (this.nav.getActiveChildNavs().length && page.index != undefined) {
this.nav.getActiveChildNavs()[0].select(page.index);
} else {
// Set the root of the nav with params if it's a tab index
this.nav.setRoot(page.name, params).catch((err: any) => {
console.log(`Didn't set nav root: ${err}`);
});
}
if (page.logsOut === true) {
// Give the menu time to close before changing to logged out
this.userData.logout();
}
}
listenToLoginEvents() {
this.events.subscribe('user:login', () => {
this.enableMenu(true);
});
this.events.subscribe('user:signup', () => {
this.enableMenu(true);
});
this.events.subscribe('user:logout', () => {
this.enableMenu(false);
});
}
enableMenu(loggedIn: boolean) {
this.menu.enable(loggedIn, 'loggedInMenu');
this.menu.enable(!loggedIn, 'loggedOutMenu');
}
isActive(page: PageInterface) {
let childNav = this.nav.getActiveChildNavs()[0];
// Tabs are a special case because they have their own navigation
if (childNav) {
if (childNav.getSelected() && childNav.getSelected().root === page.tabComponent) {
return 'primary';
}
return;
}
if (this.nav.getActive() && this.nav.getActive().name === page.name) {
return 'primary';
}
return;
}
initializeApp() {
this.platform.ready().then(() => {
StatusBar.styleDefault();
Splashscreen.hide();
});
}
QQLogin(){
const loginOptions: QQShareOptions = {
client: this.qq.ClientType.QQ,
};
this.qq.ssoLogin(loginOptions)
.then((result) => {
console.log('shareNews success');
alert('token is ' + result.access_token);
alert('userid is ' + result.userid);
})
.catch(error => {
console.log(error);
});
this.qq.logout().then(() => {
console.log('logout success');
}).catch(error => {
console.log(error);
});
}
wechatLogin(){
let scope = "snsapi_userinfo",
state = "_" + (+new Date());
Wechat.auth(scope, state, function (response) {
// you may use response.code to get the access token.
alert(JSON.stringify(response));
}, function (reason) {
alert("Failed: " + reason);
});
}
weiboLogin(){}
FBLogin(){
this.fb.login(['email', 'public_profile']).then((response: FacebookLoginResponse) => {
this.fb.api('me?fields=id,name,email,first_name,picture.width(360).height(360).as(picture_large)', []).then(profile => {
this.userData.login({email: profile['email'], first_name: profile['first_name'], picture: profile['picture_large']['data']['url'], username: profile['name']});
});
});
}
}
I have an Express API that responds with data from MongoDB when requested upon mounting of a reactJS component.
app.get('/api/characters', function(req, res) {
var db = req.db;
var collection = db.get('usercollection');
collection.find({},{},function(e,docs){
res.send({
data: docs
});
});
});
Code for Characters component :
export default class Characters extends React.Component {
constructor(props) {
super(props);
this.state = CharactersStore.getState();
this.onChange = this.onChange.bind(this);
}
componentDidMount() {
CharactersStore.listen(this.onChange);
CharactersActions.getCharacters('http://localhost:3000/api/characters');
}
componentWillUnmount() {
CharactersStore.unlisten(this.onChange);
}
onChange(state) {
this.setState(state);
}
render() {
return (
<section>
<div className="container">
<div className="row">
<h2 className="text-center">{this.props.route.header}</h2>
<hr className="star-light"/>
<CharacterList data={this.state.characters}/>
</div>
</div>
</section>
)
}
}
Code for Characters component Action
class CharactersActions {
constructor() {
this.generateActions(
'getCharactersSuccess',
'getCharactersFail'
);
}
getCharacters(query) {
requestPromise(query)
.then((res) => {
this.actions.getCharactersSuccess(res)
}).catch((err) => {
console.log('error:', err);
this.actions.getCharactersFail(err)
})
}
}
export default alt.createActions(CharactersActions);
Code for Characters component Store
class CharactersStore {
constructor() {
this.bindActions(CharactersActions);
this.characters = [''];
this.isLoading = true;
}
getCharactersSuccess(res) {
this.characters = res;
this.isLoading = false;
}
getCharactersFail(err) {
toastr.error(err.responseJSON && err.responseJSON.message || err.responseText || err.statusText);
}
}
export default alt.createStore(CharactersStore);
The Characters component above requests the API upon mounting and sends the response data along to the store to be saved into State.
I then pass the Characters state into the child component CharacterList as props (named data)
Characters List Component
export default class CharacterList extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div className="col-lg-3 col-sm-6">
{console.log(this.props.data)}
// THIS IS WHERE I AM TRYING TO .MAP THROUGH THE RESULTS
</div>
)
}
}
I am trying to use .map to loop through the returned data but am a little unsure on how to proceed, any advice would be appreciated. Data is being returned as follows:
{
"data": [
{
"_id": "58d5044b0898f816066227f1",
"character": "Luke Skywalker"
},
{
"_id": "58d504c60898f816066227f2",
"character": "Obi Wan Kenobi"
},
{
"_id": "58d504c60898f816066227f3",
"character": "Han Solo"
}
]
}
You want to set res.data as your characters store.
getCharactersSuccess(res) {
this.characters = res.data; // <--
this.isLoading = false;
}
Then you can map over the data array, and not the full response:
const data = [
{
_id: '58d5044b0898f816066227f1',
character: 'Luke Skywalker'
},
{
_id: '58d504c60898f816066227f2',
character: 'Obi Wan Kenobi'
},
{
_id: '58d504c60898f816066227f3',
character: 'Han Solo'
}
];
const Character = ({ data }) => <div>{data.character}</div>;
class CharacterList extends React.Component {
render() {
return (
<div>
{this.props.data.map((character, i) => (
<Character key={i} data={character} />
))}
</div>
);
}
}
ReactDOM.render(<CharacterList data={data} />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
It is simple.I dont know where you confused. try this
<div className="col-lg-3 col-sm-6">
{
Array.isArray(this.props.data)&& this.props.data.map((val,index)=>{
return val
})
}
</div>