Skip to content

Commit

Permalink
[WIP] But added the logic to ignore "remote" TomSelect when checking …
Browse files Browse the repository at this point in the history
…if options changed
  • Loading branch information
weaverryan committed Feb 29, 2024
1 parent 4254244 commit 4c6c5d3
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 37 deletions.
1 change: 1 addition & 0 deletions src/Autocomplete/assets/dist/controller.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export default class extends Controller {
private isObserving;
private hasLoadedChoicesPreviously;
private originalOptions;
private parentElement;
initialize(): void;
connect(): void;
initializeTomSelect(): void;
Expand Down
38 changes: 20 additions & 18 deletions src/Autocomplete/assets/dist/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class default_1 extends Controller {
this.isObserving = false;
this.hasLoadedChoicesPreviously = false;
this.originalOptions = [];
this.parentElement = null;
}
initialize() {
if (!this.mutationObserver) {
Expand All @@ -42,12 +43,11 @@ class default_1 extends Controller {
if (this.selectElement) {
this.originalOptions = this.createOptionsDataStructure(this.selectElement);
}
const parentElement = this.element.parentElement;
if (!parentElement) {
return;
this.parentElement = this.element.parentElement;
if (this.parentElement) {
this.parentElement.addEventListener('turbo:before-morph-element', this.beforeMorphElement.bind(this));
this.parentElement.addEventListener('turbo:before-morph-attribute', this.beforeMorphAttribute.bind(this));
}
parentElement.addEventListener('turbo:before-morph-element', this.beforeMorphElement.bind(this));
parentElement.addEventListener('turbo:before-morph-attribute', this.beforeMorphAttribute.bind(this));
this.initializeTomSelect();
}
initializeTomSelect() {
Expand All @@ -67,12 +67,11 @@ class default_1 extends Controller {
}
disconnect() {
this.stopMutationObserver();
const parentElement = this.element.parentElement;
if (!parentElement) {
return;
if (this.parentElement) {
this.parentElement.removeEventListener('turbo:before-morph-element', this.beforeMorphElement.bind(this));
this.parentElement.removeEventListener('turbo:before-morph-attribute', this.beforeMorphAttribute.bind(this));
this.parentElement = null;
}
parentElement.removeEventListener('turbo:before-morph-element', this.beforeMorphElement.bind(this));
parentElement.removeEventListener('turbo:before-morph-attribute', this.beforeMorphAttribute.bind(this));
let currentSelectedValues = [];
if (this.selectElement) {
if (this.selectElement.multiple) {
Expand Down Expand Up @@ -187,7 +186,7 @@ class default_1 extends Controller {
}
});
const newOptions = this.selectElement ? this.createOptionsDataStructure(this.selectElement) : [];
const areOptionsEquivalent = this.areOptionsEquivalent(newOptions);
const areOptionsEquivalent = this.areOptionsEquivalent(this.originalOptions, newOptions);
const value = this.selectElement ? Array.from(this.selectElement.options || []).map((option) => option.value) : this.formElement.value;
const didValueChange = value !== this.tomSelect.getValue();
if (!areOptionsEquivalent || requireReset || didValueChange) {
Expand All @@ -205,21 +204,22 @@ class default_1 extends Controller {
};
});
}
areOptionsEquivalent(newOptions) {
const filteredOriginalOptions = this.originalOptions.filter((option) => option.value !== '');
areOptionsEquivalent(currentOptions, newOptions) {
const filteredCurrentOptions = currentOptions.filter((option) => option.value !== '');
const filteredNewOptions = newOptions.filter((option) => option.value !== '');
console.log(filteredCurrentOptions, filteredNewOptions);
const originalPlaceholderOption = this.originalOptions.find((option) => option.value === '');
const newPlaceholderOption = newOptions.find((option) => option.value === '');
if (originalPlaceholderOption &&
newPlaceholderOption &&
originalPlaceholderOption.text !== newPlaceholderOption.text) {
return false;
}
if (filteredOriginalOptions.length !== filteredNewOptions.length) {
if (filteredCurrentOptions.length !== filteredNewOptions.length) {
return false;
}
const normalizeOption = (option) => `${option.value}-${option.text}-${option.group}`;
const originalOptionsSet = new Set(filteredOriginalOptions.map(normalizeOption));
const originalOptionsSet = new Set(filteredCurrentOptions.map(normalizeOption));
const newOptionsSet = new Set(filteredNewOptions.map(normalizeOption));
return (originalOptionsSet.size === newOptionsSet.size &&
[...originalOptionsSet].every((option) => newOptionsSet.has(option)));
Expand All @@ -229,9 +229,11 @@ class default_1 extends Controller {
event.preventDefault();
return;
}
if (event.target === this.element) {
const newOptions = this.selectElement ? this.createOptionsDataStructure(this.selectElement) : [];
if (this.areOptionsEquivalent(newOptions)) {
if (event.target === this.element && event.target.tagName === 'SELECT') {
const newOptions = this.createOptionsDataStructure(event.detail.newElement);
const currentOptions = this.selectElement ? this.createOptionsDataStructure(this.selectElement) : [];
console.log(this.areOptionsEquivalent(currentOptions, newOptions));
if (this.areOptionsEquivalent(currentOptions, newOptions)) {
event.preventDefault();
return;
}
Expand Down
44 changes: 25 additions & 19 deletions src/Autocomplete/assets/src/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ export default class extends Controller {
private isObserving = false;
private hasLoadedChoicesPreviously = false;
private originalOptions: Array<{ value: string; text: string; group: string | null }> = [];
private parentElement: HTMLElement| null = null;

initialize() {
if (!this.mutationObserver) {
Expand All @@ -53,12 +54,11 @@ export default class extends Controller {
this.originalOptions = this.createOptionsDataStructure(this.selectElement);
}
// TODO - also listen on `live:before-morph-element`
const parentElement = this.element.parentElement;
if (!parentElement) {
return;
this.parentElement = this.element.parentElement;
if (this.parentElement) {
this.parentElement.addEventListener('turbo:before-morph-element', this.beforeMorphElement.bind(this));
this.parentElement.addEventListener('turbo:before-morph-attribute', this.beforeMorphAttribute.bind(this));
}
parentElement.addEventListener('turbo:before-morph-element', this.beforeMorphElement.bind(this));
parentElement.addEventListener('turbo:before-morph-attribute', this.beforeMorphAttribute.bind(this));

this.initializeTomSelect();
}
Expand Down Expand Up @@ -92,12 +92,11 @@ export default class extends Controller {
disconnect() {
this.stopMutationObserver();

const parentElement = this.element.parentElement;
if (!parentElement) {
return;
if (this.parentElement) {
this.parentElement.removeEventListener('turbo:before-morph-element', this.beforeMorphElement.bind(this));
this.parentElement.removeEventListener('turbo:before-morph-attribute', this.beforeMorphAttribute.bind(this));
this.parentElement = null;
}
parentElement.removeEventListener('turbo:before-morph-element', this.beforeMorphElement.bind(this));
parentElement.removeEventListener('turbo:before-morph-attribute', this.beforeMorphAttribute.bind(this));

// TomSelect.destroy() resets the element to its original HTML. This
// causes the selected value to be lost. We store it.
Expand Down Expand Up @@ -411,9 +410,9 @@ export default class extends Controller {
});

const newOptions = this.selectElement ? this.createOptionsDataStructure(this.selectElement) : [];
const areOptionsEquivalent = this.areOptionsEquivalent(newOptions);
const areOptionsEquivalent = this.areOptionsEquivalent(this.originalOptions, newOptions);

// TODO: test this: look for changes in the "value" of the select element
// TODO: test this: look for chsrc/Autocomplete/assets/dist/coanges in the "value" of the select element
const value = this.selectElement ? Array.from(this.selectElement.options || []).map((option) => option.value) : this.formElement.value;
const didValueChange = value !== this.tomSelect.getValue();

Expand All @@ -436,10 +435,13 @@ export default class extends Controller {
});
}

private areOptionsEquivalent(newOptions: Array<{ value: string; text: string; group: string | null }>): boolean {
private areOptionsEquivalent(currentOptions: Array<{ value: string; text: string; group: string | null }>, newOptions: Array<{ value: string; text: string; group: string | null }>): boolean {
const filteredCurrentOptions = currentOptions.filter((option) => option.value !== '');

// remove the empty option, which is added by TomSelect so may be missing from new options
const filteredOriginalOptions = this.originalOptions.filter((option) => option.value !== '');
//const filteredOriginalOptions = this.originalOptions.filter((option) => option.value !== '');
const filteredNewOptions = newOptions.filter((option) => option.value !== '');
console.log(filteredCurrentOptions, filteredNewOptions);

const originalPlaceholderOption = this.originalOptions.find((option) => option.value === '');
const newPlaceholderOption = newOptions.find((option) => option.value === '');
Expand All @@ -452,13 +454,13 @@ export default class extends Controller {
return false;
}

if (filteredOriginalOptions.length !== filteredNewOptions.length) {
if (filteredCurrentOptions.length !== filteredNewOptions.length) {
return false;
}

const normalizeOption = (option: { value: string; text: string; group: string | null }) =>
`${option.value}-${option.text}-${option.group}`;
const originalOptionsSet = new Set(filteredOriginalOptions.map(normalizeOption));
const originalOptionsSet = new Set(filteredCurrentOptions.map(normalizeOption));
const newOptionsSet = new Set(filteredNewOptions.map(normalizeOption));

return (
Expand All @@ -475,9 +477,13 @@ export default class extends Controller {
return;
}

if (event.target === this.element) {
const newOptions = this.selectElement ? this.createOptionsDataStructure(this.selectElement) : [];
if (this.areOptionsEquivalent(newOptions)) {
if (event.target === this.element && event.target.tagName === 'SELECT') {
const newOptions = this.createOptionsDataStructure(event.detail.newElement);
const currentOptions = this.selectElement ? this.createOptionsDataStructure(this.selectElement) : [];
// if the options are the same OR this is an Ajax select (where the options
// don't represent the actual options), then prevent the morph to avoid
// the problem described in the comment below
if (this.areOptionsEquivalent(currentOptions, newOptions) || this.urlValue) {
// prevent the <option> elements from being mutated, as this will
// change their order, which befuddles TomSelect (who changes the
// order of the <option> elements when you select them)
Expand Down

0 comments on commit 4c6c5d3

Please sign in to comment.