Ionic 4 Manual Override of ion-select - ionic-framework

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 => {})

Related

How to scroll to the bottom of the chat page in ionic 5

i am building a chatting mobile app with ionic 5, i want to be able to scroll to the bottom of the chat but its not working, i searched online but the solution i saw wasn't working, it just scrolled a little bit, but not to the end of the chat
Here is my code for the chat.page.html
<ion-header>
....
</ion-header>
<ion-content class="bg">
<ion-button expand="block" (click)="scrollContent()">Scroll 1</ion-button>
<div class="chat-container">
<div *ngFor="let message of messages; let i=index;" class="chat-bubble" [(ngClass)]="message.type">
<h6>{{ message.text }}</h6>
<p>{{ message.created }}</p>
</div>
</div>
</ion-content>
<ion-footer>
.......
</ion-footer>
Here's the code for the chat.page.ts
import { Component, OnInit, ViewChild } from '#angular/core';
import { IonContent } from '#ionic/angular';
#Component({
selector: 'app-chats',
templateUrl: './chats.page.html',
styleUrls: ['./chats.page.scss'],
})
export class ChatsPage implements OnInit {
messages=new Array()
#ViewChild(IonContent, { static: false }) content: IonContent;
constructor(
) { }
ngOnInit() {
this.messages=[
{ text: "Hey what's up?", type: 'received', created: '14:02' },
{ text: "Nothing", type: 'send', created: '14:05' },
{ text: "Want to go to the movies?", type: 'send', created: '14:05' },
{ text: "I'm sorry, I can't", type: 'received', created: '14:15' },
{ text: "but can we go tomorrow?", type: 'received', created: '14:16' },
{ text: "Nothing", type: 'send', created: '14:05' },
{ text: "Nothing", type: 'send', created: '14:05' },
{ text: "Nothing", type: 'send', created: '14:05' },
{ text: "Nothing", type: 'send', created: '14:05' },
{ text: "I'm sorry, I can't", type: 'received', created: '14:15' },
{ text: "but can we go tomorrow?", type: 'received', created: '14:16' },
]
}
scrollContent() {
this.content.scrollToBottom(300)
}
}
I want it to scroll to the bottom of the div with class="chat-container" when i click the button.
Please what am i doing thats not right
try this
scrollToBottomSetTimeOut(){
setTimeout(() => {
this.content.scrollToBottom();
}, 30);
}

How can I change an item in app.component.ts?

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));

Print PDF in ionic 3

I am using PDFMake for creating the pdf with my predefined Document definition. In my old ionic 1 project, I am passing the encoded string to print function which works fine. here is the code for old ionic 1
var dd = $scope.createDocumentDefinition();
$timeout(function () {
var pdf = pdfMake.createPdf(dd);
pdf.getBase64(function (encodedString) {
console.log(encodedString);
$ionicLoading.hide();
window.plugins.PrintPDF.print({
data: encodedString,
type: 'Data',
title: 'Print Document',
success: function () {
console.log('success');
},
error: function (data) {
data = JSON.parse(data);
console.log('failed: ' + data.error);
}
});
});
}, 1000);
Now I am upgrading my project to Ionic 3 so I tried the same thing but the output is different here is my new ionic 3 code. printer open but instead of printing as per my document definition it just prints the encoded string.
let printer_ = this.printer;
var dd = this.createDocumentDefinition();
var pdf = pdfMake.createPdf(dd);
pdf.getBase64(function (_encodedString) {
let options: PrintOptions = {
name: 'MyDocument'
};
console.log(JSON.stringify(pdf));
printer_.print(_encodedString, options).then((msg)=>{
console.log("Success",msg);
},(error) => {
console.log("Error", error);
});
});
Any idea how to use this in ionic 3 ??
You can use pdfmake for generate PDF using ionic.
First you need to install plugin for file and file opener.
ionic cordova plugin add cordova-plugin-file-opener2
ionic cordova plugin add cordova-plugin-file
After that install NPM package of file, FileOpener and PDF make
npm install pdfmake
npm install #ionic-native/file-opener
npm install #ionic-native/file
Open your src/app.module.ts and include file and fileoperner reference:
import { File } from '#ionic-native/file';
import { FileOpener } from '#ionic-native/file-opener';
Add File and FileOpener in provider
providers: [
StatusBar,
SplashScreen,
{provide: ErrorHandler, useClass: IonicErrorHandler},
File,
FileOpener
]
I am generating a template UI looks like this:
<ion-header>
<ion-navbar>
<ion-title>
Ionic PDF
</ion-title>
</ion-navbar>
</ion-header>
<ion-content padding>
<ion-item>
<ion-label stacked>From</ion-label>
<ion-input [(ngModel)]="letterObj.from"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>To</ion-label>
<ion-input [(ngModel)]="letterObj.to"></ion-input>
</ion-item>
<ion-item>
<ion-label stacked>Text</ion-label>
<ion-textarea [(ngModel)]="letterObj.text" rows="10"></ion-textarea>
</ion-item>
<button ion-button full (click)="createPdf()">Create PDF</button>
<button ion-button full (click)="downloadPdf()" color="secondary" [disabled]="!pdfObj">Download PDF</button>
</ion-content>
After that your home.component.ts code looks like this:
import { Component } from '#angular/core';
import { NavController, Platform } from 'ionic-angular';
import pdfMake from 'pdfmake/build/pdfmake';
import pdfFonts from 'pdfmake/build/vfs_fonts';
pdfMake.vfs = pdfFonts.pdfMake.vfs;
import { File } from '#ionic-native/file';
import { FileOpener } from '#ionic-native/file-opener';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
letterObj = {
to: '',
from: '',
text: ''
}
pdfObj = null;
constructor(public navCtrl: NavController, private plt: Platform, private file: File, private fileOpener: FileOpener) { }
createPdf() {
var docDefinition = {
content: [
{ text: 'REMINDER', style: 'header' },
{ text: new Date().toTimeString(), alignment: 'right' },
{ text: 'From', style: 'subheader' },
{ text: this.letterObj.from },
{ text: 'To', style: 'subheader' },
this.letterObj.to,
{ text: this.letterObj.text, style: 'story', margin: [0, 20, 0, 20] },
{
ul: [
'Bacon',
'Rips',
'BBQ',
]
}
],
styles: {
header: {
fontSize: 18,
bold: true,
},
subheader: {
fontSize: 14,
bold: true,
margin: [0, 15, 0, 0]
},
story: {
italic: true,
alignment: 'center',
width: '50%',
}
}
}
this.pdfObj = pdfMake.createPdf(docDefinition);
}
downloadPdf() {
if (this.plt.is('cordova')) {
this.pdfObj.getBuffer((buffer) => {
var blob = new Blob([buffer], { type: 'application/pdf' });
// Save the PDF to the data Directory of our App
this.file.writeFile(this.file.dataDirectory, 'myletter.pdf', blob, { replace: true }).then(fileEntry => {
// Open the PDf with the correct OS tools
this.fileOpener.open(this.file.dataDirectory + 'myletter.pdf', 'application/pdf');
})
});
} else {
// On a browser simply use download!
this.pdfObj.download();
}
}
}

ionic3 - Didn't set nav root: invalid link: FeedbackPage

I want when I clicked feedback button can go feedback page, but after I set up all, after clicked still showing tabsPage.
app.component.ts
appPages: PageInterface[] = [
{ title: '新闻', name: 'TabsPage', component: TabsPage, index: 0, icon: 'ios-globe-outline' },
{ title: 'SOS', name: 'TabsPage', component: TabsPage, index: 1, icon: 'call' },
{ title: '服务', name: 'TabsPage', component: TabsPage, index: 2, icon: 'people' },
{ title: '反馈', name: 'FeedbackPage', component: FeedbackPage, icon: 'contacts' }
];
loggedInPages: PageInterface[] = [
{ title: '新闻', name: 'TabsPage', component: TabsPage, index: 0, icon: 'ios-globe-outline' },
{ title: 'SOS', name: 'TabsPage', component: TabsPage, index: 1, icon: 'call' },
{ title: '服务', name: 'TabsPage', component: TabsPage, index: 2, icon: 'people' },
{ title: '反馈', name: 'FeedbackPage', component: FeedbackPage, icon: 'contacts' },
{ title: '注销', name: 'TabsPage', component: TabsPage, icon: 'log-out', logsOut: true }
];
The last one is the feedback button, when I click feedback button just back to tabsPage not go into feedback page.
UPDATE:
I am checking this code in app.components.ts
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();
}
}
Is it need to change params?
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 color="wechat" style="width:40%" ion-button clear (click)= "wechatLogin()">
<ion-icon name="minan-login-wechat"></ion-icon>
</button>
<button color="facebook" style="width:40%" ion-button clear (click)= "FBLogin()">
<ion-icon name="minan-login-facebook"></ion-icon>
</button>
<ion-list-header>导航栏</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>
Feedback page doesn't have own module because I am using 'ionic generate page Feedback --no-module' to generate my Feedback page
This means you are not using lazy loading and the page is not an IonicPage.
#IonicPage()
which sets the name property as the component name by default.
This will automatically create a link to the MyPage component using the same name as the class, name: 'MyPage'. The page can now be navigated to by using this name.
And also you dont have PageModule
In your case, you will have to set the imported component/page and not the string with your NavController functions.
Do:
this.nav.setRoot(page.component, params).catch((err: any) => {
console.log(`Didn't set nav root: ${err}`);
});//page.component
Based on your app structure, you app might be based on ionic conference starter template, what iv'e done is remove extra parameters in IonicModule.forRoot(ConferenceApp), like links array and extra objects, then do the lazy loading for your pages by Adding and importing an #IonicPage() on your components.
Before:
IonicModule.forRoot(ConferenceApp, {}, {
links: [
{ component: TabsPage, name: 'TabsPage', segment: 'tabs-page' },
{ component: SchedulePage, name: 'Schedule', segment: 'schedule' },
{ component: SessionDetailPage, name: 'SessionDetail', segment: 'sessionDetail/:sessionId' },
{ component: ScheduleFilterPage, name: 'ScheduleFilter', segment: 'scheduleFilter' },
{ component: SpeakerListPage, name: 'SpeakerList', segment: 'speakerList' },
{ component: SpeakerDetailPage, name: 'SpeakerDetail', segment: 'speakerDetail/:speakerId' },
{ component: MapPage, name: 'Map', segment: 'map' },
{ component: AboutPage, name: 'About', segment: 'about' },
{ component: TutorialPage, name: 'Tutorial', segment: 'tutorial' },
{ component: SupportPage, name: 'SupportPage', segment: 'support' },
{ component: AccountPage, name: 'AccountPage', segment: 'account' },
{ component: SignupPage, name: 'SignupPage', segment: 'signup' }
]
After:
IonicModule.forRoot(ConferenceApp),
login.module.ts
import { NgModule } from '#angular/core';
import { IonicPageModule } from 'ionic-angular';
import { LoginPage } from './login';
#NgModule({
declarations: [
LoginPage,
],
imports: [
IonicPageModule.forChild(LoginPage),
],
})
export class RequestTrainingPageModule {}
login.ts
import { Component } from '#angular/core';
import { NgForm } from '#angular/forms';
import { IonicPage, NavController } from 'ionic-angular';
import { UserOptions } from '../../interfaces/user-options';
import { UserData } from '../../providers/user-data';
import { TabsPage } from '../tabs-page/tabs-page';
#IonicPage()
#Component({
selector: 'page-user',
templateUrl: 'login.html'
})
export class LoginPage {
login: UserOptions = { username: '', password: '' };
submitted = false;
constructor(public navCtrl: NavController, public userData: UserData) { }
onLogin(form: NgForm) {
this.submitted = true;
if (form.valid) {
this.userData.login(this.login.username);
this.navCtrl.push(TabsPage);
}
}
onSignup() {
this.navCtrl.push('SignupPage');
}
}

ionic3 - Can't resolve all parameters for UserDataProvider: ([object Object], [object Object], ?)

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']});
});
});
}
}