Ionic2 alert with dropdown? - ionic-framework

I am building an Ionic2 app. I have an alert like following:
constructor(private platform: Platform, public nav : NavController,
public exhibitionSurveyObjectService : ExhibitionSurveyObjectService ) {
this.initializeMap();
this.nav=nav;
this.testArray=[];
this.area=null;
}
addSurveyObject(){
let prompt = Alert.create({
title: 'Subscribe to our service',
message: "All the fields are necessary",
inputs: [
{
name: 'name',
placeholder: 'Name'
},
....
{
name: 'cycle',
placeholder: 'Cycle: once/weekly/monthly'
},
{
name: 'object_type',
placeholder: 'Farm/Solarpanel/plain'
},
],
buttons: [
....
{
text: 'Save',
handler: data => {
this.createExhibitionSuveyObject(data);
}
}
]
});
this.nav.present(prompt);
}
createExhibitionSuveyObject(data: any){
var cycle = data.cycle;
cycle = cycle.toUpperCase()
console.log(cycle)
var type = data.object_type;
type = type.toUpperCase()
console.log(type)
this.exhibitionSurveyObjectService.addObject(
data.name, data.farmer_email,
data.farmer_name, data.size, data.path, cycle, type).subscribe(
response => {
this.exhibitionSurveyObjects = response;
this.sayThanks();
},
error => {
this.errorMessage = <any>error;
console.log("error")
}
);
}
sayThanks(){
let alert = Alert.create({
title: 'Thank you!',
subTitle: 'We have received your data, we will get back to you soon!',
buttons: [{
text: 'Ok',
handler: () => {
this.nav.push(HomePage)
}
}]
});
this.nav.present(alert);
}
I want the last two fields to be dropdowns. How can I achieve this?
UPDATE: updated the code snippet with some more code. How it can be updated to use Modal instead of alert?

Just like you can see in Ionic2 docs
Alerts can also include several different inputs whose data can be
passed back to the app. Inputs can be used as a simple way to prompt
users for information. Radios, checkboxes and text inputs are all
accepted, but they cannot be mixed. For example, an alert could have
all radio button inputs, or all checkbox inputs, but the same alert
cannot mix radio and checkbox inputs.
And...
If you require a complex form UI which doesn't fit within the
guidelines of an alert then we recommend building the form within a
modal instead.
So you'll have to create a new Component with that form and then use it to create the Modal:
import { Modal, NavController, NavParams } from 'ionic-angular';
#Component(...)
class YourPage {
constructor(nav: NavController) {
this.nav = nav;
}
presentSubscriptionModal() {
let subscriptionModal = Modal.create(Subscription, { yourParam: paramValue });
this.nav.present(subscriptionModal);
}
}
#Component(...)
class Subscription{
constructor(params: NavParams) {
let param = params.get('yourParam');
}
}

Related

Create Radio Button Alert from Firestore Data

I want to create a radio button alert by using the data in fireStore. I generated an observable by valueChanges() but console.log returns Undefined when I used it in the function that can't read the data and eventually cannot insert the values for radio button. I am new to fireStore and ionic.
I have also tried using .get().then(function(doc) but returns error as not a function. I have also tried using subscribe() but also not able to give me the actual data, or I have missed something. I have google for many days but just can't find the solution. I hope somebody could help.
myMemberList = [];
constructor(public navCtrl: NavController,
public alertCtrl: AlertController,
public firestore: AngularFirestore,
public afAuth: AngularFireAuth,
) { }
ionViewDidEnter() {
this.afAuth.authState.subscribe(user => {
if (user) {
this.userId = user.uid;
this.fireStoreTaskList = this.firestore.doc<any>('users/' +
this.userId).collection('Member').valueChanges();
}
});
}
// create the inputs for radio button //
createInputs() {
const theNewInputs = [];
for (let i = 0; i < this.fireStoreTaskList.length; i++) { // undefined
theNewInputs.push(
{
type: 'radio',
label: this.fireStoreTaskList.memberName, // undefined
value: this.fireStoreTaskList.memberId, // undefined
checked: false
}
);
} {
console.log(theNewInputs);
}
return theNewBeneInputs;
}
// Radio button alert to choose data //
async selectMember() {
this.myMemberList = this.createInputs();
const alert = await this.alertCtrl.create({
header: 'Member',
inputs: this.myMemberList,
buttons: [{ text: 'Cancel', role: 'cancel' },
{ text: 'OK',
handler: data => {
console.log(data)
}
}
]
});
await alert.present();
}
I have been working with Ionic 4 for some time now and I have also integrated Firebase Firestore in my app. I didn't really understand the whole description, but I have a solution for you initial question "I want to create a radio button alert by using the data in Firestore"
I assume that you have already setup your application with your Firebase app, if not then I suggest following the How to Build An Ionic 4 App with Firebase and AngularFire 5.
My example has 1 button, that whenever you click it, it will do the following:
Access the Firestore database.
Download the Firestore documents.
Get the field memberName of each document.
Add those names in an array of names
Create an Alert of Radio Buttons.
For the radio buttons it will create a list of radio buttons that will have the names of the members.
Display the array.
For my code to work, this is the Firestore database structure that I have followed:
.
└── collection: "users"
└── document: "autogenerated_id"
| ├── memberID: "user_id"
| └── memberName: "Name 01"
└── document: "autogenerated_id"
├── memberID: "user_id"
└── memberName: "Name 02"
When clicking the button you will see an alert with radio buttons e.g. Name 01 and Name 02
As I have mentioned above, this is my example code. It loads data from Firestore and Creates an alert with radio buttons using that data, as you have described in your question. I have added a lot of comments for you in the code. If this is not exactly what you were looking for, take a look at the code and modify it according to your needs.
UPDATED CODE FOR LOADING memberID and memberName into the array of type interface.
import { Component, OnInit } from '#angular/core';
//Import AngularFirestore to access Firestore database
import { AngularFirestore } from '#angular/fire/firestore';
//Import AlertControll to display alerts
import { AlertController } from '#ionic/angular';
//You have to add the interface, before the calss' declaration
interface Data {
memberID?: string;
memberName?: string;
}
#Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage implements OnInit {
//List that will be used to load the data from Firestore into it
//members = []; //You don't this anymore
//Just the array of type interface that you created.
data: Data[] = [];
//Constractor: add AngularFirestore and AlertController
constructor(private db: AngularFirestore, public alertController: AlertController) { }
ngOnInit() {
}
//Load data and create the alert
showAlert(){
//Clear the array before loading again
this.members = [];
//Access the Collection "users" in Firestore and load all the documents
this.db.collection("users").ref
.get()
.then(async (querySnapshot) => {
//Parse through all the loaded documents
querySnapshot.forEach((doc) => {
//Add the loaded name to the list
//this.members.push(doc.data().memberName) // You don't need this anymore as you are going to push the loaded data in the new array
//Pushing the data in the new array or logging it if you want
this.data.push( {
memberID: doc.data().memberID, //This is how you get the memberID from Firestore document
memberName: doc.data().memberName} //This is how you get the memberName from Firestore document
);
});
//Create an array of Radio Buttons to be used in the alert
var newInputs = [];
//Parse through all memebers in the loaded array from Firestore
for (const d of this.data){
newInputs.push({
name: 'radio1', //You can costumize those as well to cast the clicked once afterwards
type: 'radio',
label: "ID: " + d.memberID + " name: " + d.memberName, //Add the member and the ID as label
value: 'value1',
checked: false
})
}
//Create an alert
const alert = await this.alertController.create({
header: 'Radio',
inputs: newInputs, //Add the dynamically generated array of radio buttons.
buttons: [
{
text: 'Cancel',
role: 'cancel',
cssClass: 'secondary',
handler: () => {
console.log('Confirm Cancel');
}
}, {
text: 'Ok',
handler: () => {
console.log('Confirm Ok');
}
}
]
});
//Present the alert
await alert.present();
})
.catch(function(error) {
console.log("Error getting documents: ", error);
});
}

Unit testing - Getting issue with Alert Controller in Ionic Framework

I am trying to write a testcase for a method which has been called or not. Inside that method, I am calling an alert confirmation box.
I am getting an error like
Failed: this.alertCtrl.create is not a function
Component.ts
submitTicket(comments) {
if (comments.length > 0) {
const prompt = this.alertCtrl.create({
title: "<span> Improve Solution </span>",
message: "<span>" + 'Are you sure you want <br>' + "</span>" +
"<span>" + 'to submit this improvement' + "</span>",
enableBackdropDismiss: false,
buttons: [
{
text: 'Cancel',
handler: data => {
// Some stuff
}
},
{
text: 'Improve Solution',
handler: data => {
//Some stuff
}
}
]
});
prompt.present();
} else {
this.errorMsg = true;
}
}
component.spec.ts
import {AlertControllerMock } from 'ionic-mocks';
beforeEach(async(()=> {
TestBed.configureTestingModule({
declarations: [ImprovedsolutionsPage],
imports: [
IonicModule.forRoot(ImprovedsolutionsPage),
HttpClientTestingModule
],
providers: [
NavController,
AppService,
AlertController,
ImprovedsolutionsPage,
{provide: ViewController, useClass: ViewControllerMock},
{provide: LoadingController, useClass: LoadingControllerMock},
{provide: AlertController, useClass: AlertControllerMock},
]
}).compileComponents
}))
beforeEach(()=> {
fixture=TestBed.createComponent(ImprovedsolutionsPage)
component=fixture.componentInstance
fixture.detectChanges()
})
it('should be call submitTicket method', async(()= > {
spyOn(component, 'submitTicket').and.callThrough()
let comment='Needs to improve in detailing '
component.submitTicket(comment)
expect(component.submitTicket).toHaveBeenCalled()
}))
Here I am using ionic-mocks module and I imported AlertControllerMock as shown in the above code. And I am using ionic version 3. For testing I am using Karma and jasmine
Could someone please help me out in this issue.
[Updated] Here is my tip: I am not able to check your mock's implementation. However, make sure you have a separate boolean var to testify if the mocked function, for example, create, is called elsewhere.
create(opts?: AlertOptions): Promise<HTMLIonAlertElement> {
this.createAlertCalled = true;
this.opts = opts;
const self = this;
return Promise.resolve(<HTMLIonAlertElement>{
present: (): Promise<void> => {
self.presentCalled = true;
return Promise.resolve();
}
});
}
Subsequently, do a spyOn with AlertControllerMock on the mentioned variable and expect the assertion to be truthy.

Alert in Alert ionic 3

I have managed to open an alert with in an alert. But when I choose Admin I want to close the first alert after the user chooses Admin.
How can I do that?
showAlert2(message)
{
let alert = this.alertCtrl.create({
title:'Sign in as',
inputs: [
{
type:'checkbox',
label:'Admin',
value:'admin',
handler: data => {
this.showAlert3('Sign in');
}
},
{
type:'checkbox',
label:'Patient',
value:'patient'
}
],
buttons: [
{
text: 'Login',
handler: data => {
// if the user chooses patient open a page
this.navCtrl.push(PMainPage);
// if the user chooses admin i want to create an other alert message
}
}
]
});
alert.present();
}
Thank you in advance!
You can dismiss the current alert by alert.dismiss() since you defined it with let alert.
let alert = this.alertCtrl.create({
title:'Sign in as',
inputs: [
{
type:'checkbox',
label:'Admin',
value:'admin',
handler: data => {
alert.dismiss(); //here dismiss this alert
this.showAlert3('Sign in');
}
},
{
type:'checkbox',
label:'Patient',
value:'patient'
}
],
});

Prevent multiple Ionic Alerts from stacking up

How can I detect if ionic 2 alert ui component instance is already open in order not to present another alert ?
I ended up writing a wrapping provider for Ionic's Alert controller like so :
import { Injectable } from '#angular/core';
import { AlertController } from 'ionic-angular';
#Injectable()
export class Alert {
public alertPresented: any;
constructor(public alertCtrl: AlertController) {
this.alertPresented = false
}
present(title, subTitle) {
let vm = this
if(!vm.alertPresented) {
vm.alertPresented = true
vm.alertCtrl.create({
title: title,
subTitle: subTitle,
buttons: [{
text: 'OK',
handler: () => {
vm.alertPresented = false
}
}],
}).present();
}
}
}
where alertPresented flag prevents more than one instance from being presented
I have another idea that you can assign message for a variable and check new message is equal to it or not. If equal, return.
This is my code and hope you enjoy with it.
import { Injectable } from '#angular/core';
import { AlertController } from 'ionic-angular';
#Injectable()
export class AlertProvider {
public showingMessage = ""
constructor(
private alertController: AlertController
) {}
showAlert(message) {
// Check this message is showing or not
if (message === this.showingMessage) {
return
}
this.showingMessage = message
this.alertController.create({
title: "APP_NAME",
message: message,
buttons: [{
text: "OK",
handler: () => {
this.showingMessage = ""
}
}]
}).present()
}
}
You can create an AlertService to handle that with more options without inject an event for the buttons
import { Injectable } from '#angular/core';
import { AlertController, Alert } from 'ionic-angular';
/**
* A simple alert class to show only one alert at the same time
*/
#Injectable()
export class AlertService {
currentAlert: Alert
constructor(private alertCtrl: AlertController) {
}
show(title, message, buttons: any = [], inputs: any = [], cssClass = '') {
if (!buttons.length) {
buttons.push('Ok')
}
let alertOptions: any = {
title: title,
subTitle: message,
buttons: buttons,
cssClass: buttons.length === 2 ? 'confirmAlert' : cssClass
}
if (inputs.length) {
alertOptions.inputs = inputs
}
if (!this.currentAlert) {
this.currentAlert = this.alertCtrl.create(alertOptions)
this.currentAlert.present()
this.currentAlert.onDidDismiss(() => {
this.currentAlert = null
})
}
return this.currentAlert
}
}
Regards, Nicholls
My solution worked, i had to put a boolean and set it true after a cancel event and set it false when an alert is presented
if (this.network_alert) {
let alert = await this.alertController.create({
header: "No Network",
message:
"Please check your internet connection",
buttons: [{
text: "Dismiss",
role: 'cancel',
handler: () => {
console.log('Cancel clicked');
this.network_alert = true
}
}],
});
await alert.present();
this.network_alert = false
}
}

is it possible to change button's text with $ionicPopup.confirm()?

I'm using $ionicPopup.confirm() but I would like to change "cancel's button" text. Is it possible to do so ?
I'm aware of .show() syntax:
buttons: [
{ text: 'Cancel' }
]
But it does not seem to work with .confirm() ...
Thank 4 the help
At least in the latest release of Ionic (1.0.0) you can do the following:
var confirmPopup = $ionicPopup.confirm({
title: 'Popup title',
template: 'Popup text',
cancelText: 'Custom cancel',
okText: 'Custom ok'
}).then(function(res) {
if (res) {
console.log('confirmed');
}
});
Here is the relative documentation.
UPDATE : on ionic 1.0.0, this is now possible, check here
showConfirm Options :
{
title: '', // String. The title of the popup.
cssClass: '', // String, The custom CSS class name
subTitle: '', // String (optional). The sub-title of the popup.
template: '', // String (optional). The html template to place in the popup body.
templateUrl: '', // String (optional). The URL of an html template to place in the popup body.
cancelText: '', // String (default: 'Cancel'). The text of the Cancel button.
cancelType: '', // String (default: 'button-default'). The type of the Cancel button.
okText: '', // String (default: 'OK'). The text of the OK button.
okType: '', // String (default: 'button-positive'). The type of the OK button.
}
Yes you can do wathever you want, using ionic popup.show and bind the Cancel event.
$ionicPopup.show({
template: msg,
title: titleConfirm,
buttons: [
{ text: "BTN_NO",
onTap:function(e){
return false;
}
},
{ text: "BTN_OK",
onTap:function(e){
return true;
}
},
]
});
After investigation on the ionic popover.confirm function this is
not possible to customize it. The value of popover.confirm are hardcoded line 446
function showConfirm(opts) {
return showPopup(extend({
buttons: [{
text: opts.cancelText || 'Cancel',
type: opts.cancelType || 'button-default',
onTap: function() { return false; }
}, {
text: opts.okText || 'OK',
type: opts.okType || 'button-positive',
onTap: function() { return true; }
}]
}, opts || {}));
}
It's possible to do, you have to use the "type" thing inside the button
buttons: [
{ text: 'Cancel' },
{
text: '<b>Save</b>',
type: 'button-assertive',
onTap: function(e) {
$scope.request_form.abc = "accepted";
}
}
]
in the type part you have to give the class name , and you can change the color of the button.