Skip to content

Commit cf9dd61

Browse files
committed
refactor(picker): making multi-column select type ahead more flexible with how it picks numbers
1 parent 52869e4 commit cf9dd61

File tree

1 file changed

+50
-100
lines changed

1 file changed

+50
-100
lines changed

core/src/components/picker/picker.tsx

Lines changed: 50 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -410,17 +410,59 @@ export class Picker implements ComponentInterface {
410410
colEl: HTMLIonPickerColumnElement,
411411
value: string,
412412
zeroBehavior: 'start' | 'end' = 'start'
413-
) => {
413+
): boolean => {
414+
if (!value) {
415+
return false;
416+
}
417+
414418
const behavior = zeroBehavior === 'start' ? /^0+/ : /0$/;
419+
value = value.replace(behavior, '');
415420
const option = Array.from(colEl.querySelectorAll('ion-picker-column-option')).find((el) => {
416421
return el.disabled !== true && el.textContent!.replace(behavior, '') === value;
417422
});
418423

419424
if (option) {
420425
colEl.setValue(option.value);
421426
}
427+
428+
return !!option;
422429
};
423430

431+
/**
432+
* Attempts to intelligently search the first and second
433+
* column as if they're number columns for the provided numbers
434+
* where the first two numbers inpu are the first column
435+
* and the last 2 are the last column. Tries to allow for the first
436+
* number to be ignored for situations where typos occurred.
437+
*/
438+
private multiColumnSearch = (firstColumn: HTMLIonPickerColumnElement, secondColumn: HTMLIonPickerColumnElement, input: string) => {
439+
if (input.length === 0) {
440+
return;
441+
}
442+
443+
const inputArray = input.split('');
444+
const hourValue = inputArray.slice(0, 2).join('');
445+
const foundHour = this.searchColumn(firstColumn, hourValue);
446+
447+
if (inputArray.length > 2 && foundHour) {
448+
const minuteValue = inputArray.slice(2, 4).join('');
449+
this.searchColumn(secondColumn, minuteValue);
450+
} else if (!foundHour && inputArray.length >= 1) {
451+
let singleDigitHour = inputArray[0];
452+
let singleDigitFound = this.searchColumn(firstColumn, singleDigitHour);
453+
if (!singleDigitFound) {
454+
inputArray.shift();
455+
singleDigitHour = inputArray[0];
456+
singleDigitFound = this.searchColumn(firstColumn, singleDigitHour);
457+
}
458+
459+
if (singleDigitFound && inputArray.length > 1) {
460+
const remainingDigits = inputArray.slice(1, 3).join('');
461+
this.searchColumn(secondColumn, remainingDigits);
462+
}
463+
}
464+
}
465+
424466
private selectMultiColumn = () => {
425467
const { inputEl, el } = this;
426468
if (!inputEl) {
@@ -432,108 +474,16 @@ export class Picker implements ComponentInterface {
432474
const firstColumn = numericPickers[0];
433475
const lastColumn = numericPickers[1];
434476

435-
// Get the maximum value from the first column's options
436-
const columnOptions = Array.from(firstColumn.querySelectorAll('ion-picker-column-option'));
437-
const maxFirstColumnValue = Math.max(
438-
...columnOptions
439-
.map((option) => parseInt(option.textContent?.trim() || '0', 10)) // Extract and parse text content
440-
.filter((num) => !isNaN(num)) // Ensure valid numbers only
441-
);
442-
443-
// check for 24-hour format
444-
const allowTwo = maxFirstColumnValue >= 20;
445-
446477
let value = inputEl.value;
447-
let minuteValue;
448-
switch (value.length) {
449-
case 1:
450-
this.searchColumn(firstColumn, value);
451-
break;
452-
/**
453-
* If the first character is `0` or `1` or allowed '2' it is
454-
* possible that users are trying to type `09`
455-
* or `11` into the hour field, so we should look
456-
* at that first.
457-
*/
458-
case 2:
459-
const firstCharacter = inputEl.value.substring(0, 1);
460-
value =
461-
firstCharacter === '0' || firstCharacter === '1' || (allowTwo && firstCharacter === '2')
462-
? inputEl.value
463-
: firstCharacter;
464-
465-
this.searchColumn(firstColumn, value);
466-
467-
/**
468-
* If only checked the first value,
469-
* we can check the second value
470-
* for a match in the minutes column
471-
*/
472-
if (value.length === 1) {
473-
minuteValue = inputEl.value.substring(inputEl.value.length - 1);
474-
this.searchColumn(lastColumn, minuteValue, 'end');
475-
}
476-
break;
477-
case 3:
478-
/**
479-
* If the first character is `0` or `1` or allowed '2' it is
480-
* possible that users are trying to type `09`
481-
* or `11` into the hour field, so we should look
482-
* at that first.
483-
*/
484-
const firstCharacterAgain = inputEl.value.substring(0, 1);
485-
value =
486-
firstCharacterAgain === '0' || firstCharacterAgain === '1' || (allowTwo && firstCharacterAgain === '2')
487-
? inputEl.value.substring(0, 2)
488-
: firstCharacterAgain;
489-
490-
this.searchColumn(firstColumn, value);
491-
492-
/**
493-
* If only checked the first value,
494-
* we can check the second value
495-
* for a match in the minutes column
496-
*/
497-
minuteValue = value.length === 1 ? inputEl.value.substring(1) : inputEl.value.substring(2);
498-
499-
this.searchColumn(lastColumn, minuteValue, 'end');
500-
break;
501-
case 4:
502-
/**
503-
* If the first character is `0` or `1` or allowed '2' it is
504-
* possible that users are trying to type `09`
505-
* or `11` into the hour field, so we should look
506-
* at that first.
507-
*/
508-
const firstCharacterAgainAgain = inputEl.value.substring(0, 1);
509-
value =
510-
firstCharacterAgainAgain === '0' ||
511-
firstCharacterAgainAgain === '1' ||
512-
(allowTwo && firstCharacterAgainAgain === '2')
513-
? inputEl.value.substring(0, 2)
514-
: firstCharacterAgainAgain;
515-
this.searchColumn(firstColumn, value);
478+
if (value.length > 4) {
479+
const startIndex = inputEl.value.length - 4;
480+
const newString = inputEl.value.substring(startIndex);
516481

517-
/**
518-
* If only checked the first value,
519-
* we can check the second value
520-
* for a match in the minutes column
521-
*/
522-
const minuteValueAgain =
523-
value.length === 1
524-
? inputEl.value.substring(1, inputEl.value.length)
525-
: inputEl.value.substring(2, inputEl.value.length);
526-
this.searchColumn(lastColumn, minuteValueAgain, 'end');
527-
528-
break;
529-
default:
530-
const startIndex = inputEl.value.length - 4;
531-
const newString = inputEl.value.substring(startIndex);
532-
533-
inputEl.value = newString;
534-
this.selectMultiColumn();
535-
break;
482+
inputEl.value = newString;
483+
value = newString;
536484
}
485+
486+
this.multiColumnSearch(firstColumn, lastColumn, value);
537487
};
538488

539489
/**

0 commit comments

Comments
 (0)