I'm using ionic 4 and I want to set custom buttons on ion-select through interfaceOptions
HTML
<ion-item>
<ion-label>Lines</ion-label>
<ion-select multiple="true" [(ngModel)]="SelectedLines" [interfaceOptions]="customAlertOptions">
<ion-select-option [value]="line" *ngFor="let line of Lines">{{linea.Name}}</ion-select-option>
</ion-select>
</ion-item>
TS
customAlertOptions: any = {
buttons: [
{
text: 'Select All',
handler: (blah) => {
console.log('Select All Clicked');
},
{
text: 'No',
handler: (blah) => {
console.log('Confirm Cancel: blah');
}
}, {
text: 'Okay',
handler: () => {
console.log('Confirm Okay');
}
}
]
};
However, only the default buttons are showing (Ok and Cancel)
Docs say it should be possible
https://ionicframework.com/docs/api/select
I can see this has been reported for previous versions of Ionic
https://forum.ionicframework.com/t/custom-button-for-ion-select-through-selectoptions-not-working/157305
Is it possible to make this work on Ionic 4? Is there a workaround?
EDIT: I tried with the PopOver interface with the same results
What you are trying to do isn't possible from what I can see.
The documentation actually only says you can set the buttons text:
ion-select#select-buttons - Ionic Documentation
By default, the alert has two buttons: Cancel and OK. Each button's text can be customized using the cancelText and okText properties.
It doesn't say that the buttons can be customised.
You can pass in the interfaceOptions but its overridden later by the default button set:
https://github.com/ionic-team/ionic/blob/master/core/src/components/select/select.tsx#L339
The code looks like this:
const alertOpts: AlertOptions = {
mode,
...interfaceOptions,
header: interfaceOptions.header ? interfaceOptions.header : labelText,
inputs: this.createAlertInputs(this.childOpts, inputType),
buttons: [
{
text: this.cancelText,
role: 'cancel',
handler: () => {
this.ionCancel.emit();
}
},
{
text: this.okText,
handler: (selectedValues: any) => {
this.value = selectedValues;
}
}
],
cssClass: ['select-alert', interfaceOptions.cssClass,
(this.multiple ? 'multiple-select-alert' : 'single-select-alert')]
};
return alertController.create(alertOpts);
So as you can see the ...interfaceOptions, is passed in at the start, then the buttons are set to the defaults, with the only customisation options being the ok or cancel text.
i am working with AlertController from ionic and i can custom it, just take a look at my screen .
You just need to import AlertController and after you can do something like this for exemple :
home.page.ts
async addAlertHome(adresse: string, lat: string, lon: string) {
const alert = await this.alertController.create({
header: 'Ajouter aux favoris',
message: 'Êtes vous sûr de vouloir ajouter cette adresse à vos favoris ?',
buttons: [
{
text: 'Non',
role: 'cancel',
cssClass: 'secondary'
}, {
text: 'Oui',
handler: () => {
alert.dismiss().then(() => {
this.addFavoriteHome(adresse, lat, lon);
});
console.log('Confirm Okay');
}
}
]
});
await alert.present();
}
And use it where you want on html :
home.page.html
<ion-icon name="heart-empty" (click)="addAlert(location.display_name, location.lat, location.lon)" end>
</ion-icon>
And don't forget on your constructor :
public alertController: AlertController
Related
I am trying to use a search box in a mat-select that works correctly only when using data loaded by default. I want to use data from an api. But it does not work properly, the data is not displayed in the mat-select when loading the page, but it is displayed when a focus occurs in the mat-select tag.
I have a model where I use the data from a test API
export interface DataModel {
id: number;
title: string;
userId: number;
}
export const DataModels: DataModel[] = [
{ id: 1, title: 'Option A', userId: 23 },
{ id: 2, title: 'Option B', userId: 24 },
{ id: 3, title: 'Option C', userId: 25 },
{ id: 4, title: 'Option D', userId: 26 }
];
My service where I make the call
#Injectable()
export class DataloadService {
constructor(private http: HttpClient) {}
LoadData(): Observable<any> {
return this.http.get('https://jsonplaceholder.typicode.com/albums');
}
}
The component where the search filter is performed and controls are set. Following the documentation NgxMatSelectSearch
constructor(private service: DataloadService) {}
dataModel: DataModel[] = []; //DataModels
dataCtrl: FormControl = new FormControl();
dataFilterCtrl: FormControl = new FormControl();
filteredData: ReplaySubject<DataModel[]> = new ReplaySubject<DataModel[]>(1);
#ViewChild('singleSelect', { static: true }) singleSelect: MatSelect;
_onDestroy = new Subject<void>();
ngOnInit() {
this.load();
this.filteredData.next(this.dataModel.slice());
this.dataFilterCtrl.valueChanges
.pipe(takeUntil(this._onDestroy))
.subscribe(() => {
this.filterData();
});
}
ngOnDestroy() {
this._onDestroy.next();
this._onDestroy.complete();
}
filterData() {
if (!this.dataModel) {
return;
}
let search = this.dataFilterCtrl.value;
if (!search) {
this.filteredData.next(this.dataModel.slice());
return;
} else {
search = search.toLowerCase();
}
this.filteredData.next(
this.dataModel.filter(
(x: any) => x.title.toLowerCase().indexOf(search) > -1
)
);
}
load() {
return this.service.LoadData().subscribe(res => {
this.dataModel = res;
});
}
And the HTML
<mat-card>
<mat-toolbar>Demo</mat-toolbar><br />
<mat-card-content>
<mat-select [formControl]="dataCtrl" placeholder="Data" #singleSelect>
<mat-option>
<ngx-mat-select-search
[formControl]="dataFilterCtrl"
></ngx-mat-select-search>
</mat-option>
<mat-option *ngFor="let x of filteredData | async" [value]="x.id">
{{x.title}}
</mat-option>
</mat-select>
</mat-card-content>
</mat-card>
If I use the data that is by default in the model to simulate the process using "dataModels"
dataModel: DataModel[] = []; //DataModels
Instead of initializing it empty. It works normally but if I load the data with the request made to the API, the problem arises that it is not loaded after a focus occurs.
The demo I have in Stackblitz: Demo Stackblitz
You should add this line
this.filteredData.next(this.dataModel.slice());
into subscribe event of this.service.LoadData() as it is asynchronous. So that when the response result is returned, the filteredData is bonded with the response result.
load() {
return this.service.LoadData().subscribe(res => {
this.dataModel = res;
this.filteredData.next(this.dataModel.slice());
});
}
Sample Solution on StackBlitz
I need to generate html code in a customRender function of one column.
I cannot use scopedSlots as suggested here, since the html code is part of e generic component, and other components pass their columns array as a parameter.
BaseComponent.vue:
<template>
<a-table
:columns="attrs.columns"
:rowKey="record => record[attrs.recordId]"
:dataSource="filteredTableData"
>
</a-table>
</template>
<script>
export default {
props: {
attrs: {
type: Object,
required: true
}
:
</script>
ContactComponent.vue:
<template>
:
<base-component :attrs="attrs"/>
:
</template>
<script>
import BaseComponent from './BaseComponent';
export default {
components: {
BaseComponent
},
data() {
return {
attrs: {
columns: [
title: 'Type',
dataIndex: 'type',
customRender: (val, record) => {
return '<div class="myClass">' + val + </div>';
},
],
recordId: 'contactId'
}
}
}
:
</script>
The problem:
The following code:
customRender: (val, record) => {
return '<div class="myClass">' + val + '</div>';
},
renders this:
Is there a way to force raw html rendering directly from the customRender function?
You can transform your code:
customRender: (val, record) => {
return '<div class="myClass">' + val + '</div>';
},
In this way (if you have JSX support).
customRender: (data) => {
return <div class="myClass"> {data.text} </div>;
},
If you dont have JSX support, you can return a Vnode. Like specified here: https://vuejs.org/guide/extras/render-function.html#creating-vnodes (I didn't try this way).
Or you can try to add support for JSX: https://vuejs.org/guide/extras/render-function.html#jsx-tsx
(My reply is late but may help others.)
==========
Edit:
Here, another exemple, to show you where this piece of code should be (only work with JSX support):
data: function () {
return {
dataSource: [],
columns: [
{
title: 'Website',
dataIndex: "cat_website",
key: "cat_website",
customRender: (data) => {
return <a href={'http://' + data.text} target='_blank'>{data.text}</a>;
},
},
// other columns...
],
// ...
}
}
I want to make a text field with typeahead. I have a list of words and when you start typing them, a suggestion appears with the word(s). The thing is, it needs to be able to do it multiple times, every new word you type, it can show you a suggestion.
Anyone know how I can do this?
You can use vue-suggestion to accomplish this easily. Take a look at the demo to see if this suites you.
This is my implementation of App.vue which differs slightly.
<template>
<div>
{{ items }}
<vue-suggestion :items="results"
v-model="item"
:setLabel="setLabel"
:itemTemplate="itemTemplate"
#changed="inputChange"
#selected="itemSelected">
</vue-suggestion>
</div>
</template>
<script>
import itemTemplate from './item-template.vue';
export default {
data () {
return {
item: {},
items: [
{ id: 1, name: 'Golden Retriever'},
{ id: 2, name: 'Flying Squirrel'},
{ id: 3, name: 'Cat'},
{ id: 4, name: 'Catfish'},
{ id: 5, name: 'Squirrel'},
],
itemTemplate,
results: {}
}
},
methods: {
itemSelected (item) {
this.item = item;
},
setLabel (item) {
return item.name;
},
inputChange (text) {
// your search method
this.results = this.items.filter(item => item.name.includes(text));
// now `items` will be showed in the suggestion list
},
},
};
</script>
I was developing an ionic project, and when I implement native into my application, when I run the action sheet function it will automatically pop up an input tag in my title bar. why ? Below is my code
problem.html :
<button ion-button (click)="openMenu()"> Upload Photo</button>
<ion-card ng-show="showstartCard" >
<ion-slides pager="true" class="slides">
<ion-slide *ngFor="let photo of photos; let id = index">
<ion-icon ios="ios-add-circle" md="md-add-circle" class="deleteIcon" (click)="deletePhoto(id)"></ion-icon>
<img style="width:30px;height:30px;" [src]="photo" *ngIf="photo" />
</ion-slide>
</ion-slides>
</ion-card>
problem.ts
openMenu() {
let actionSheet = this.actionSheetCtrl.create({
title: 'Choose from',
cssClass: 'action-sheets-basic-page',
buttons: [
{
text: 'Camera',
icon: !this.platform.is('ios') ? 'trash' : null,
handler: () => {
this.takePhoto();
console.log('Delete clicked');
}
},
{
text: 'Album',
icon: !this.platform.is('ios') ? 'share' : null,
handler: () => {
this.takeGallery();
console.log('Share clicked');
}
},
{
text: 'Cancel',
icon: !this.platform.is('ios') ? 'close' : null,
handler: () => {
console.log('Cancel clicked');
}
}
]
});
actionSheet.present();
}
deletePhoto(index) {
let confirm = this
.alertCtrl
.create({
title: 'Sure you want to delete this photo? There is NO undo!',
message: '',
buttons: [
{
text: 'No',
handler: () => {
console.log('Disagree clicked');
}
}, {
text: 'Yes',
handler: () => {
console.log('Agree clicked');
this
.photos
.splice(index, 1);
//return true;
}
}
]
});
confirm.present();
}
takePhoto() {
const options: CameraOptions = {
quality: 50,
destinationType: this.camera.DestinationType.FILE_URI,
encodingType: this.camera.EncodingType.JPEG,
mediaType: this.camera.MediaType.PICTURE
}
this
.camera
.getPicture(options)
.then((imageData) => {
this.base64Image = "file://" + imageData;
this
.photos
.push(this.base64Image);
this
.photos
.reverse();
}, (err) => {
console.log(err);
});
}
takeGallery() {
this.camera.getPicture({
sourceType: this.camera.PictureSourceType.SAVEDPHOTOALBUM,
destinationType: this.camera.DestinationType.DATA_URL
}).then((imageData) => {
this.base64Image = 'data:image/jpeg;base64,' + imageData;
this
.photos
.push(this.base64Image);
this
.photos
.reverse();
}, (err) => {
console.log(err);
});
}
When I click on the Upload Photo button, it will pop up an action sheet
When i click on the album, it supposed to be run the album at pop up..but I don't know why the project pop an input tag at the top of my html, the Choose Files button. Anyone know what is the reason ??
Here is my console log.
Can anyone know what's make this error ? Please. Thanks !!
I'm having problems with clicking the button upon taking a test.
Scenario:
Upon Logging in -> the user takes a test and submits -> the user is redirected on the home page. But on my home page i cant click on the "Menu button"
on my Login.ts
if (this.checker == "false" || this.checker == null) {
this.navCtrl.setRoot(LearnertestPage);
} else {
this.navCtrl.setRoot(SplashscreenPage);
}
on my test.ts
in the alert controller, I have this
{
text: 'Yes',
handler: data => {
this.learningStyles.push(
[
{style: "Auditory", value: AudioTotal},
{style: "Logical", value: LogicalTotal},
{style: "Physical", value: PhysicalTotal},
{style: "Social", value: SocialTotal},
{style: "Solitary", value: SolitaryTotal},
{style: "Visual", value: VisualTotal},
{style: "Verbal", value: VerbalTotal}]
);
this.userChecker.update( this.currentUser, { Checker: 'true' });
this.navCtrl.setRoot(SplashscreenPage);
}
}
And lastly on my Splash screen or home :
HTMl:
<ion-menu [content]="content">
<ion-content>
<ion-item style="background-color:#00aced">
<img src="./assets/img/adapt.png" height="100px" width="350px"/>
</ion-item>
<ion-list>
<button ion-item *ngFor="let p of pages" (click)="openPage(p)">
<ion-icon name="{{p.icon}}"></ion-icon> {{p.title}}
</button>
<button ion-item (click)="doConfirm()">
<ion-icon name="log-out"></ion-icon> Logout
</button>
</ion-list>
on the splashscreen.ts
#ViewChild(Nav) nav: Nav;
selectedItem: any;
rootPage: any = ListPage;
selectedTheme:String;
icons: string[];
pages: Array<{ title: string, component: any, icon: string }>
constructor(){
// used for an example of ngFor and navigation
this.pages = [
{ title: 'Home', component: SplashscreenPage, icon: this.icons[0], },
{ title: 'Earth Science', component: LessonPage, icon: this.icons[1] },
{ title: 'Progress', component: ProfilePage, icon: this.icons[2] }
];
}
openPage(page) {
// Reset the content nav to have just this page
// we wouldn't want the back button to show in this scenario
this.nav.setRoot(page.component); }
I can't seem to click on this button. Hmm. What am I doing wrong?
try to custom toggle the menu. add the toggleMenu method to the (click) of the menu button
import { Component } from '#angular/core';
import { MenuController } from 'ionic-angular';
#Component({...})
export class MyPage {
constructor(public menuCtrl: MenuController) {
}
toggleMenu() {
this.menuCtrl.toggle();
}
}