refactor(): remove checked property in favor of parent value (#19449)

BREAKING CHANGE:


The following components have been updated to remove the checked or selected properties:

- Radio
- Segment Button
- Select

Developers should set the value property on the respective parent components in order to managed checked/selected status.

Co-authored-by: Liam DeBeasi <liamdebeasi@users.noreply.github.com>
This commit is contained in:
Manu MA
2020-01-17 23:22:26 +01:00
committed by Liam DeBeasi
parent 9232f16eea
commit a5229d90ca
52 changed files with 879 additions and 939 deletions

View File

@ -125,7 +125,6 @@ export class Select implements ComponentInterface {
@Watch('value')
valueChanged() {
this.updateOptions();
this.emitStyle();
if (this.didInit) {
this.ionChange.emit({
@ -135,25 +134,10 @@ export class Select implements ComponentInterface {
}
async connectedCallback() {
if (this.value === undefined) {
if (this.multiple) {
// there are no values set at this point
// so check to see who should be selected
const checked = this.childOpts.filter(o => o.selected);
this.value = checked.map(o => getOptionValue(o));
} else {
const checked = this.childOpts.find(o => o.selected);
if (checked) {
this.value = getOptionValue(checked);
}
}
}
this.updateOptions();
this.updateOverlayOptions();
this.emitStyle();
this.mutationO = watchForOptions<HTMLIonSelectOptionElement>(this.el, 'ion-select-option', async () => {
this.updateOptions();
this.updateOverlayOptions();
});
}
@ -218,30 +202,32 @@ export class Select implements ComponentInterface {
return;
}
const childOpts = this.childOpts;
const value = this.value;
switch (this.interface) {
case 'action-sheet':
overlay.buttons = this.createActionSheetButtons(childOpts);
overlay.buttons = this.createActionSheetButtons(childOpts, value);
break;
case 'popover':
const popover = overlay.querySelector('ion-select-popover');
if (popover) {
popover.options = this.createPopoverOptions(childOpts);
popover.options = this.createPopoverOptions(childOpts, value);
}
break;
case 'alert':
const inputType = (this.multiple ? 'checkbox' : 'radio');
overlay.inputs = this.createAlertInputs(childOpts, inputType);
overlay.inputs = this.createAlertInputs(childOpts, inputType, value);
break;
}
}
private createActionSheetButtons(data: any[]): ActionSheetButton[] {
private createActionSheetButtons(data: HTMLIonSelectOptionElement[], selectValue: any): ActionSheetButton[] {
const actionSheetButtons = data.map(option => {
const value = getOptionValue(option);
return {
role: (option.selected ? 'selected' : ''),
role: (isOptionSelected(value, selectValue, this.compareWith) ? 'selected' : ''),
text: option.textContent,
handler: () => {
this.value = getOptionValue(option);
this.value = value;
}
} as ActionSheetButton;
});
@ -258,38 +244,39 @@ export class Select implements ComponentInterface {
return actionSheetButtons;
}
private createAlertInputs(data: any[], inputType: string): AlertInput[] {
return data.map(o => {
return {
type: inputType,
label: o.textContent,
value: getOptionValue(o),
checked: o.selected,
disabled: o.disabled
} as AlertInput;
});
}
private createPopoverOptions(data: any[]): SelectPopoverOption[] {
private createAlertInputs(data: HTMLIonSelectOptionElement[], inputType: 'checkbox' | 'radio', selectValue: any): AlertInput[] {
return data.map(o => {
const value = getOptionValue(o);
return {
text: o.textContent,
type: inputType,
label: o.textContent || '',
value,
checked: o.selected,
checked: isOptionSelected(value, selectValue, this.compareWith),
disabled: o.disabled
};
});
}
private createPopoverOptions(data: HTMLIonSelectOptionElement[], selectValue: any): SelectPopoverOption[] {
return data.map(o => {
const value = getOptionValue(o);
return {
text: o.textContent || '',
value,
checked: isOptionSelected(value, selectValue, this.compareWith),
disabled: o.disabled,
handler: () => {
this.value = value;
this.close();
}
} as SelectPopoverOption;
};
});
}
private async openPopover(ev: UIEvent) {
const interfaceOptions = this.interfaceOptions;
const mode = getIonMode(this);
const value = this.value;
const popoverOpts: PopoverOptions = {
mode,
...interfaceOptions,
@ -301,22 +288,21 @@ export class Select implements ComponentInterface {
header: interfaceOptions.header,
subHeader: interfaceOptions.subHeader,
message: interfaceOptions.message,
value: this.value,
options: this.createPopoverOptions(this.childOpts)
value,
options: this.createPopoverOptions(this.childOpts, value)
}
};
return popoverController.create(popoverOpts);
}
private async openActionSheet() {
const mode = getIonMode(this);
const interfaceOptions = this.interfaceOptions;
const actionSheetOpts: ActionSheetOptions = {
mode,
...interfaceOptions,
buttons: this.createActionSheetButtons(this.childOpts),
buttons: this.createActionSheetButtons(this.childOpts, this.value),
cssClass: ['select-action-sheet', interfaceOptions.cssClass]
};
return actionSheetController.create(actionSheetOpts);
@ -335,7 +321,7 @@ export class Select implements ComponentInterface {
...interfaceOptions,
header: interfaceOptions.header ? interfaceOptions.header : labelText,
inputs: this.createAlertInputs(this.childOpts, inputType),
inputs: this.createAlertInputs(this.childOpts, inputType, this.value),
buttons: [
{
text: this.cancelText,
@ -368,23 +354,6 @@ export class Select implements ComponentInterface {
return this.overlay.dismiss();
}
private updateOptions() {
// iterate all options, updating the selected prop
let canSelect = true;
const { value, childOpts, compareWith, multiple } = this;
for (const selectOption of childOpts) {
const optValue = getOptionValue(selectOption);
const selected = canSelect && isOptionSelected(value, optValue, compareWith);
selectOption.selected = selected;
// if current option is selected and select is single-option, we can't select
// any option more
if (selected && !multiple) {
canSelect = false;
}
}
}
private getLabel() {
return findItemLabel(this.el);
}
@ -490,6 +459,17 @@ export class Select implements ComponentInterface {
}
}
const isOptionSelected = (currentValue: any[] | any, compareValue: any, compareWith?: string | SelectCompareFn | null) => {
if (currentValue === undefined) {
return false;
}
if (Array.isArray(currentValue)) {
return currentValue.some(val => compareOptions(val, compareValue, compareWith));
} else {
return compareOptions(currentValue, compareValue, compareWith);
}
};
const getOptionValue = (el: HTMLIonSelectOptionElement) => {
const value = el.value;
return (value === undefined)
@ -507,24 +487,13 @@ const parseValue = (value: any) => {
return value.toString();
};
const isOptionSelected = (currentValue: any[] | any, compareValue: any, compareWith?: string | SelectCompareFn | null) => {
if (currentValue === undefined) {
return false;
}
if (Array.isArray(currentValue)) {
return currentValue.some(val => compareOptions(val, compareValue, compareWith));
} else {
return compareOptions(currentValue, compareValue, compareWith);
}
};
const compareOptions = (currentValue: any, compareValue: any, compareWith?: string | SelectCompareFn | null): boolean => {
if (typeof compareWith === 'function') {
return compareWith(currentValue, compareValue);
} else if (typeof compareWith === 'string') {
return currentValue[compareWith] === compareValue[compareWith];
} else {
return currentValue === compareValue;
return Array.isArray(compareValue) ? compareValue.includes(currentValue) : currentValue === compareValue;
}
};