ui autocomplete usage

This commit is contained in:
Yuri Kuznetsov
2024-02-15 10:44:42 +02:00
parent 8cd6912fee
commit b0d9d7779f
5 changed files with 94 additions and 270 deletions
+6 -8
View File
@@ -51,14 +51,12 @@ class AssignedUserFieldView extends UserWithAvatarFieldView {
}
getEmptyAutocompleteResult() {
return {
list: [
{
id: this.getUser().id,
name: this.getUser().get('name'),
}
]
};
return [
{
id: this.getUser().id,
name: this.getUser().get('name'),
},
];
}
}
+18 -92
View File
@@ -30,6 +30,7 @@
import BaseFieldView from 'views/fields/base';
import RecordModal from 'helpers/record-modal';
import Autocomplete from 'ui/autocomplete';
/**
* A link-multiple field (for has-many relations).
@@ -518,69 +519,16 @@ class LinkMultipleFieldView extends BaseFieldView {
if (this.isEditMode() || this.isSearchMode()) {
this.$element = this.$el.find('input.main-element');
const $element = this.$element;
if (!this.autocompleteDisabled) {
// Does not work well with autocompleteOnEmpty.
/*this.$element.on('blur', () => {
setTimeout(() => this.$element.autocomplete('clear'), 300);
});*/
const minChar = this.autocompleteOnEmpty ? 0 : 1;
this.$element.autocomplete({
lookup: (q, callback) => {
Promise.resolve(this.getAutocompleteUrl(q))
.then(url => {
Espo.Ajax
.getRequest(url, {q: q})
.then(response => {
callback(this._transformAutocompleteResult(response));
});
});
},
minChars: minChar,
paramName: 'q',
noCache: true,
const autocomplete = new Autocomplete(this.$element.get(0), {
minChars: this.autocompleteOnEmpty ? 0 : 1,
focusOnSelect: true,
handleFocusMode: 3,
autoSelectFirst: true,
triggerSelectOnValidInput: false,
beforeRender: $c => {
if (this.$element.hasClass('input-sm')) {
$c.addClass('small');
}
// Prevent an issue that suggestions are shown and not hidden
// when clicking outside the window and then focusing back on the document.
if (this.$element.get(0) !== document.activeElement) {
setTimeout(() => this.$element.autocomplete('hide'), 30);
}
},
formatResult: suggestion => {
// noinspection JSUnresolvedReference
return this.getHelper().escapeString(suggestion.name);
},
transformResult: response => {
response = JSON.parse(response);
const list = [];
response.list.forEach((item) => {
list.push({
id: item.id,
name: item.name || item.id,
data: item.id,
value: item.name || item.id,
});
});
return {
suggestions: list
};
},
onSelect: s => {
forceHide: true,
onSelect: item => {
this.getModelFactory().create(this.foreignScope, model => {
// noinspection JSUnresolvedReference
model.set(s.attributes);
model.set(item.attributes);
this.select([model])
@@ -588,23 +536,20 @@ class LinkMultipleFieldView extends BaseFieldView {
this.$element.focus();
});
},
lookupFunction: query => {
return Espo.Ajax.getRequest(this.getAutocompleteUrl(query), {q: query})
.then(/** {list: Record[]} */response => {
return response.list.map(item => ({
value: item.name,
attributes: item,
}));
});
},
});
this.$element.attr('autocomplete', 'espo-' + this.name);
this.once('render', () => {
$element.autocomplete('dispose');
});
this.once('remove', () => {
$element.autocomplete('dispose');
});
this.once('render remove', () => autocomplete.dispose());
}
$element.on('change', () => {
$element.val('');
});
this.renderLinks();
if (this.isEditMode()) {
@@ -1123,25 +1068,6 @@ class LinkMultipleFieldView extends BaseFieldView {
});
}
/**
* @private
*/
_transformAutocompleteResult(response) {
const list = [];
response.list.forEach(item => {
list.push({
id: item.id,
name: item.name || item.id,
data: item.id,
value: item.name || item.id,
attributes: item,
});
});
return {suggestions: list};
}
actionCreateLink() {
const viewName = this.getMetadata().get(['clientDefs', this.foreignScope, 'modalViews', 'edit']) ||
'views/modals/edit';
+21 -62
View File
@@ -31,6 +31,7 @@
import BaseFieldView from 'views/fields/base';
import RecordModal from 'helpers/record-modal';
import Select from 'ui/select';
import Autocomplete from 'ui/autocomplete';
/**
* A link-parent field (belongs-to-parent relation).
@@ -498,82 +499,40 @@ class LinkParentFieldView extends BaseFieldView {
e.currentTarget.value = this.model.get(this.nameName) || '';
}
}, 100);
if (!this.autocompleteDisabled) {
setTimeout(() => this.$elementName.autocomplete('clear'), 300);
}
});
if (!this.autocompleteDisabled) {
this.$elementName.autocomplete({
serviceUrl: (q) => {
return this.getAutocompleteUrl(q);
},
minChars: this.autocompleteOnEmpty ? 0 : 1,
paramName: 'q',
triggerSelectOnValidInput: false,
const autocomplete = new Autocomplete(this.$elementName.get(0), {
name: this.name,
focusOnSelect: true,
handleFocusMode: 2,
autoSelectFirst: true,
noCache: true,
beforeRender: ($c) => {
if (this.$elementName.hasClass('input-sm')) {
$c.addClass('small');
}
},
formatResult: (/** Record */suggestion) => {
return this.getHelper().escapeString(suggestion.name);
},
transformResult: (response) => {
response = JSON.parse(response);
const list = [];
response.list.forEach(item => {
list.push({
id: item.id,
name: item.name || item.id,
data: item.id,
value: item.name || item.id,
attributes: item,
});
});
return {suggestions: list};
},
onSelect: (/** Record */s) => {
this.getModelFactory().create(this.foreignScope, (model) => {
model.set(s.attributes);
forceHide: true,
minChars: this.autocompleteOnEmpty ? 0 : 1,
onSelect: item => {
this.getModelFactory().create(this.foreignScope, model => {
model.set(item.attributes);
this.select(model);
this.$elementName.focus();
});
},
lookupFunction: query => {
return Promise.resolve(this.getAutocompleteUrl(query))
.then(url => Espo.Ajax.getRequest(url, {q: query}))
.then(/** {list: Record[]} */response => {
return response.list.map(item => ({
value: item.name,
attributes: item,
}));
});
},
});
this.$elementName.off('focus.autocomplete');
this.$elementName.on('focus', () => {
if (this.$elementName.val()) {
this.$elementName.get(0).select();
return;
}
this.$elementName.autocomplete('onFocus');
});
this.$elementName.attr('autocomplete', 'espo-' + this.name);
this.once('render remove', () => autocomplete.dispose());
Select.init(this.$elementType, {});
}
const $elementName = this.$elementName;
this.once('render', () => {
$elementName.autocomplete('dispose');
});
this.once('remove', () => {
$elementName.autocomplete('dispose');
});
}
if (this.isSearchMode()) {
+49 -105
View File
@@ -30,6 +30,7 @@
import BaseFieldView from 'views/fields/base';
import RecordModal from 'helpers/record-modal';
import Autocomplete from 'ui/autocomplete';
/**
* A link field (belongs-to relation).
@@ -604,10 +605,6 @@ class LinkFieldView extends BaseFieldView {
e.currentTarget.value = this.model.get(this.nameName);
}
}, 100);
if (!this.autocompleteDisabled) {
setTimeout(() => this.$elementName.autocomplete('clear'), 300);
}
});
const $elementName = this.$elementName;
@@ -623,111 +620,54 @@ class LinkFieldView extends BaseFieldView {
});
}
this.$elementName.autocomplete({
beforeRender: $c => {
if (this.$elementName.hasClass('input-sm')) {
$c.addClass('small');
}
// Prevent an issue that suggestions are shown and not hidden
// when clicking outside the window and then focusing back on the document.
if (this.$elementName.get(0) !== document.activeElement) {
setTimeout(() => this.$elementName.autocomplete('hide'), 30);
}
},
lookup: (q, callback) => {
if (!this.autocompleteOnEmpty && q.length === 0) {
isEmptyQueryResult = true;
const emptyResult = this.getEmptyAutocompleteResult();
if (emptyResult) {
callback(this._transformAutocompleteResult(emptyResult));
}
return;
}
isEmptyQueryResult = false;
Promise.resolve(this.getAutocompleteUrl(q))
.then(url => {
Espo.Ajax
.getRequest(url, {q: q})
.then(response => {
callback(this._transformAutocompleteResult(response));
});
});
},
minChars: 0,
triggerSelectOnValidInput: false,
const autocomplete = new Autocomplete(this.$elementName.get(0), {
name: this.name,
handleFocusMode: 2,
autoSelectFirst: true,
noCache: true,
formatResult: suggestion => {
// noinspection JSUnresolvedReference
return this.getHelper().escapeString(suggestion.name);
},
onSelect: s => {
this.getModelFactory().create(this.foreignScope, (model) => {
// noinspection JSUnresolvedReference
model.set(s.attributes);
forceHide: true,
onSelect: item => {
this.getModelFactory().create(this.foreignScope, model => {
model.set(item.attributes);
this.select(model);
this.$elementName.focus();
});
},
lookupFunction: query => {
if (!this.autocompleteOnEmpty && query.length === 0) {
isEmptyQueryResult = true;
const emptyResult = this.getEmptyAutocompleteResult();
if (emptyResult) {
return Promise.resolve(this._transformAutocompleteResult({list: emptyResult}));
}
return Promise.resolve([]);
}
isEmptyQueryResult = false;
return Promise.resolve(this.getAutocompleteUrl(query))
.then(url => Espo.Ajax.getRequest(url, {q: query}))
.then(response => this._transformAutocompleteResult(response));
},
});
this.$elementName.off('focus.autocomplete');
this.$elementName.on('focus', () => {
if (this.$elementName.val()) {
this.$elementName.get(0).select();
return;
}
this.$elementName.autocomplete('onFocus');
});
this.$elementName.attr('autocomplete', 'espo-' + this.name);
this.once('render', () => {
$elementName.autocomplete('dispose');
});
this.once('remove', () => {
$elementName.autocomplete('dispose');
});
this.once('render remove', () => autocomplete.dispose());
if (this.isSearchMode()) {
const $elementOneOf = this.$el.find('input.element-one-of');
// noinspection JSCheckFunctionSignatures
$elementOneOf.autocomplete({
beforeRender: $c => {
if (this.$elementName.hasClass('input-sm')) {
$c.addClass('small');
}
},
serviceUrl: () => {
return this.getAutocompleteUrl();
},
const autocomplete = new Autocomplete($elementOneOf.get(0), {
minChars: 1,
paramName: 'q',
noCache: true,
formatResult: suggestion => {
// noinspection JSUnresolvedReference
return this.getHelper().escapeString(suggestion.name);
},
transformResult: response => {
return this._transformAutocompleteResult(JSON.parse(response));
},
onSelect: s => {
focusOnSelect: true,
handleFocusMode: 3,
autoSelectFirst: true,
forceHide: true,
onSelect: item => {
this.getModelFactory().create(this.foreignScope, model => {
// noinspection JSUnresolvedReference
model.set(s.attributes);
model.set(item.attributes);
this.selectOneOf([model]);
@@ -735,17 +675,18 @@ class LinkFieldView extends BaseFieldView {
setTimeout(() => $elementOneOf.focus(), 50);
});
},
lookupFunction: query => {
return Espo.Ajax.getRequest(this.getAutocompleteUrl(query), {q: query})
.then(/** {list: Record[]} */response => {
return response.list.map(item => ({
value: item.name,
attributes: item,
}));
});
},
});
$elementOneOf.attr('autocomplete', 'espo-' + this.name);
this.once('render', () => {
$elementOneOf.autocomplete('dispose');
});
this.once('remove', () => {
$elementOneOf.autocomplete('dispose');
});
this.once('render remove', () => autocomplete.dispose());
this.$el.find('select.search-type').on('change', () => {
this.trigger('change');
@@ -789,7 +730,7 @@ class LinkFieldView extends BaseFieldView {
});
});
return {suggestions: list};
return list;
}
/** @inheritDoc */
@@ -1286,6 +1227,9 @@ class LinkFieldView extends BaseFieldView {
});
}
/**
* @return {Record[]|undefined}
*/
getEmptyAutocompleteResult() {
return undefined;
}
-3
View File
@@ -204,9 +204,6 @@ class VarcharFieldView extends BaseFieldView {
responseParsed.list.forEach(item => {
list.push({
//id: item.id,
//name: item.name || item.id,
//data: item.id,
value: item.name || item.id,
attributes: item,
});