Get the selected items and validate the number of checked items? - ionic-framework

I'm using an ion-select and I'm enabling the multiple attribute to select several options. I can not find a way to disable the rest of the options in real time if 3 options have already been checked. I am currently using the ionSelect event, but it only works when an option is checked. How can I solve my problem? How can I solve my problem? I would like to understand how I know how many options I have marked and get their value in real time.
This is my code:
https://stackblitz.com/edit/ionic-8wewvd?file=pages/home/home.ts
pages/home
<ion-label>Select a person</ion-label>
<ion-select [(ngModel)]="person" multiple="true">
<ion-option *ngFor="let item of options; let i = index"
[value]="item.id" (ionSelect)="fn_checkOptions()" >
{{item.name}}
</ion-option>
</ion-select>
export class HomePage {
public options:object=[];
constructor(public navCtrl: NavController) {
this.options=
[
{"name":"pedro","id":1},
{"name":"juan","id":2},
{"name":"maria","id":3},
{"name":"velez","id":4},
{"name":"yaya","id":4}
]
}
fn_checkOptions(){
alert("hey")
}
}

I did the following:
Get a reference of our Ion Select as a #ViewChild and search it's properties until I found where the values of the checked items are stored. select._overlay.data.inputs looks promising, but of course this may be subject to changes in future Ionic versions.
Once we got the inputs we can filter those who are actually checked and do our logic.
See the code here or as Stackblitz.
HTML:
<ion-item>
<ion-label>Select a person</ion-label>
<ion-select #select [(ngModel)]="person" multiple="true">
<ion-option *ngFor="let item of options; let i = index" [value]="item.id" (ionSelect)="fn_checkOptions()">
{{item.name}}
</ion-option>
</ion-select>
</ion-item>
TS:
import { Component, ViewChild } from '#angular/core';
import { NavController, Select } from 'ionic-angular';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
#ViewChild('select', { read: Select }) select;
public options: object = [];
constructor(public navCtrl: NavController) {
this.options =
[
{ "name": "pedro", "id": 1 },
{ "name": "juan", "id": 2 },
{ "name": "maria", "id": 3 },
{ "name": "velez", "id": 4 },
{ "name": "yaya", "id": 4 }
]
}
fn_checkOptions() {
let inputs = this.select._overlay.data.inputs;
let checkedItems = inputs.filter(item => item.checked);
if (checkedItems.length === 3) {
// Disable checkboxes here
console.log('Three checkboxes have been checked');
}
}
}

Related

Ionic 4 Manual Override of ion-select

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

Set default value for an ion-select-item dynamically

I'm having some mind blow working with ionic 4, I'm trying to set a default value for an ion-select-option dynamically but I'm not getting the correct behavior
I want to load the data into the ion-select and then assign the first value
HTML
<ion-header>
<ion-toolbar>
<ion-title>home</ion-title>
</ion-toolbar>
</ion-header>
<ion-content>
<div style="height: 30%;"></div>
<ion-item>
<ion-label>Ubicación</ion-label>
<ion-select [(ngModel)]="ubicacion" okText="Aceptar" cancelText="Cancelar">
<ion-select-option *ngFor="let ubicacion of ubicaciones">{{ubicacion.nombre}}
</ion-select-option>
</ion-select>
</ion-item>
<ion-item>
<ion-label>Fruta</ion-label>
<ion-select [(ngModel)]="selfruits">
<ion-select-option *ngFor="let fruit of fruits" [value]="fruit">{{fruit.name}}</ion-select-option>
</ion-select>
</ion-item>
<div style="height: 25%;"></div>
</ion-content>
<ion-footer>
<ion-toolbar>
<ion-button expand="block" (click)="goForward('check-in')">Control</ion-button>
<ion-button expand="block" (click)="goForward('item-list')">Check list</ion-button>
</ion-toolbar>
</ion-footer>
TS
import { Component, OnInit } from '#angular/core';
import { NavController } from '#ionic/angular';
import { Maquina } from 'src/app/model/control/maquina';
import { ControlService } from 'src/app/services/control.service';
import { Ubicacion } from 'src/app/model/control/ubicacion';
import { GeneralService } from 'src/app/services/general.service';
#Component({
selector: 'app-home',
templateUrl: './home.page.html',
styleUrls: ['./home.page.scss'],
})
export class HomePage implements OnInit {
ubicaciones: Ubicacion[]
ubicacion
constructor(
private navController: NavController,
private controlService: ControlService,
private generalService: GeneralService,
) { }
fruits = [
{ id: 1, name: 'apple' },
{ id: 2, name: 'banana' },
{ id: 3, name: 'cherry' },
];
selfruits = [this.fruits[1]];
ngOnInit() {
this.fillUbicaciones()
}
fillUbicaciones() {
this.controlService.getUbicaciones().subscribe(x => {
this.ubicaciones = x
console.log("ubicaciones", x)
this.ubicacion = x[1]
})
}
changeUbicacion(value) {
console.log("changeUbicacion", value.detail.value);
// this.ubicacion = this.ubicaciones.find(x => x.nombre == value.detail.value)
}
goForward(action) {
this.generalService.goForward(action)
}
}
This is my data source : https://api.myjson.com/bins/191wsg
You are specifying the second element by using index 1, you should use this.fruits[0] to get the first item in the array.
fruits = [
{ id: 1, name: 'apple' }, // 0
{ id: 2, name: 'banana' }, // 1
{ id: 3, name: 'cherry' }, // 2
];
selfruits = [this.fruits[0]];
You don't need to wrap selFruits in an array, so you can just do:
selFruits = this.fruits[0];

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 streaming-media in android

i have i problem i want to use plugin streaming-media in ionic3
when i build projet i tested apk have blank page
I followed all the steps inside website : https://ionicframework.com/docs/native/streaming-media/
import { Component } from '#angular/core';
import { NavController } from 'ionic-angular';
import { StreamingMedia, StreamingAudioOptions } from '#ionic-native/streaming-media';
#Component({
selector: 'page-home',
templateUrl: 'home.html'
})
export class HomePage {
constructor(public navCtrl: NavController ,private streamingMedia: StreamingMedia) {
}
startAudio() {
let options: StreamingAudioOptions = {
bgImage: 'https://cdn0.iconfinder.com/data/icons/large-glossy-icons/512/Sound.png',
successCallback: () => { console.log('Finished Audio') },
errorCallback: (e) => { console.log('Error: ', e) },
initFullscreen: false // iOS only!
};
this.streamingMedia.playAudio('http://10.10.10.10:8000/;', options);
}
}
<button (click)="startAudio()" ion-button color="secondary" icon-end>
Start Audio
<ion-icon name="musical-notes"></ion-icon>
</button>
please help me
thank you

how do I create a modal view in ionic 2?

The documentation shows you how to open the modal, but isn't clear on what kind of page you're supposed to be passing to the open() method
example from docs:
import { Component } from '#angular/core';
import { ModalController, ViewController } from 'ionic-angular';
constructor(public modalCtrl: ModalController) {
}
presentContactModal() {
let contactModal = this.modalCtrl.create(ContactUs);
contactModal.present();
}
It isn't clear how where the 'ContactUs' object comes from, there is no import for it.
This example linked to here: https://ionicframework.com/docs/api/components/modal/ModalController/
import { Component } from '#angular/core';
import { ModalController, ViewController } from 'ionic-angular';
#Component(...)
class HomePage {
constructor(public modalCtrl: ModalController) { }
presentContactModal() {
let contactModal = this.modalCtrl.create(ContactUs);
contactModal.present();
}
}
///////////////below is the Contact us component which is define with in Homepage
#Component(...)
class ContactUs {
constructor(public viewCtrl: ViewController) {
}
dismiss() {
this.viewCtrl.dismiss();
}
}
The easiest way is to generate a modal content page:
ionic g ModalPage
Then you have to open modal-content.module.ts if the command creates this file, you have to change
imports: [
IonicModule.forChild(ModalPage),
],
TO :
imports: [
IonicModule.forRoot(ModalPage),
],
Then you have to add some html for the modal structure:
<ion-header>
<ion-toolbar>
<ion-title>
GO OUT
</ion-title>
<ion-buttons start>
<button ion-button (click)="dismiss()">
<span ion-text color="primary" showWhen="ios">Cancel</span>
<ion-icon name="md-close" showWhen="android,windows"></ion-icon>
</button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<p> This is a modal test!!!! </p>
</ion-content>
Then you have to import in the declarations and entryComponents of the app module.
import { ModalPage } from '../pages/modal-page/modal-page';
#NgModule({
declarations: [
MyApp,
HomePage,
Main,
ModalPage
],
imports: [
BrowserModule,
IonicModule.forRoot(MyApp),
HttpModule
],
bootstrap: [IonicApp],
entryComponents: [
MyApp,
HomePage,
ModalPage
],
providers: [
StatusBar,
SplashScreen,
Device,
{provide: ErrorHandler, useClass: IonicErrorHandler}
]
})
Then in the page you want to execute the modal you have to add a function to the element you want to use to fire it.
<div full large class="button-el btn-goOut" (tap)="openModal()">
In the page you want to use the modal you have to import :
import { ModalPage } from '../modal-page/modal-page'
Important: this element should not be in the constructor, to call the modal you only have to do like this:
openModal(){
let modal = this.modalCtrl.create(ModalPage);
modal.present();
}
You can find a working example here in the docs repository.
It isn't clear how where the 'ContactUs' object comes from, there is
no import for it.
ContactUs is just another page, you can use any page from your app to create a modal with it.
import { Component } from '#angular/core';
import { ModalController, Platform, NavParams, ViewController } from 'ionic-angular';
#Component({
templateUrl: 'template.html'
})
export class BasicPage {
constructor(public modalCtrl: ModalController) { }
openModal(characterNum) {
let modal = this.modalCtrl.create(ModalContentPage, characterNum);
modal.present();
}
}
#Component({
template: `
<ion-header>
<ion-toolbar>
<ion-title>
Description
</ion-title>
<ion-buttons start>
<button ion-button (click)="dismiss()">
<span ion-text color="primary" showWhen="ios">Cancel</span>
<ion-icon name="md-close" showWhen="android, windows"></ion-icon>
</button>
</ion-buttons>
</ion-toolbar>
</ion-header>
<ion-content>
<ion-list>
<ion-item>
<ion-avatar item-left>
<img src="{{character.image}}">
</ion-avatar>
<h2>{{character.name}}</h2>
<p>{{character.quote}}</p>
</ion-item>
<ion-item *ngFor="let item of character['items']">
{{item.title}}
<ion-note item-right>
{{item.note}}
</ion-note>
</ion-item>
</ion-list>
</ion-content>
`
})
export class ModalContentPage {
character;
constructor(
public platform: Platform,
public params: NavParams,
public viewCtrl: ViewController
) {
var characters = [
{
name: 'Gollum',
quote: 'Sneaky little hobbitses!',
image: 'assets/img/avatar-gollum.jpg',
items: [
{ title: 'Race', note: 'Hobbit' },
{ title: 'Culture', note: 'River Folk' },
{ title: 'Alter Ego', note: 'Smeagol' }
]
},
{
name: 'Frodo',
quote: 'Go back, Sam! I\'m going to Mordor alone!',
image: 'assets/img/avatar-frodo.jpg',
items: [
{ title: 'Race', note: 'Hobbit' },
{ title: 'Culture', note: 'Shire Folk' },
{ title: 'Weapon', note: 'Sting' }
]
},
{
name: 'Samwise Gamgee',
quote: 'What we need is a few good taters.',
image: 'assets/img/avatar-samwise.jpg',
items: [
{ title: 'Race', note: 'Hobbit' },
{ title: 'Culture', note: 'Shire Folk' },
{ title: 'Nickname', note: 'Sam' }
]
}
];
this.character = characters[this.params.get('charNum')];
}
dismiss() {
this.viewCtrl.dismiss();
}
}
In the example below, ModalContentPage is used to create the modal. Please notice that it's recommended to include just one component per file, so ideally you'd create the page to use as a modal in a different file.