Skip to content
Snippets Groups Projects
Verified Commit 932ae06e authored by Volker Schukai's avatar Volker Schukai :alien:
Browse files

feat: implement lookup for lazyload #248

parent cc30f6a3
No related branches found
No related tags found
No related merge requests found
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>reloading the selections for lazy load #248</title>
<script src="./248.mjs" type="module"></script>
</head>
<body>
<h1>reloading the selections for lazy load #248</h1>
<p>With lazyload, only the keys are displayed and not the values. It would be good if the values were displayed.</p>
<ul>
<li><a href="https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/248">Issue #248</a></li>
<li><a href="/">Back to overview</a></li>
</ul>
<main>
<script type="application/json" data-monster-role="translations">
{
"51": "xyz",
"52": "abc",
"53": "def"
}
</script>
<monster-select
data-monster-option-features-lazyload="true"
value="2001,2004"
data-monster-option-mapping-labeltemplate="${name} (${id})"
data-monster-option-lookup-url="/issue-248-lookup?q={filter}"
data-monster-option-lookup-
data-monster-option-mapping-valuetemplate="${id}"
data-monster-option-url="/issue-248" >
</monster-select>
</main>
</body>
</html>
/**
* @file development/issues/open/248.mjs
* @url https://gitlab.schukai.com/oss/libraries/javascript/monster/-/issues/248
* @description reloading the selections for lazy load
* @issue 248
*/
import "../../../source/components/style/property.pcss";
import "../../../source/components/style/color.pcss";
import "../../../source/components/style/link.pcss";
import "../../../source/components/style/normalize.pcss";
import "../../../source/components/style/typography.pcss";
import "../../../source/components/tree-menu/tree-menu.mjs";
import "../../../source/components/layout/split-panel.mjs";
import "../../../source/components/layout/panel.mjs";
import "../../../source/components/form/select.mjs";
const json =
`[
{
"id": 2000,
"name": "order 21",
"fieldA": "value 2A1",
"fieldB": "value 2B1"
},
{
"id": 2001,
"name": "order 22",
"fieldA": "value 2A2",
"fieldB": "value 2B2"
},
{
"id": 2002,
"name": "order 23",
"fieldA": "value 2A3",
"fieldB": "value 2B3"
},
{
"id": 2003,
"name": "order 24",
"fieldA": "value 2A4",
"fieldB": "value 2B4"
},
{
"id": 2004,
"name": "order 25",
"fieldA": "value 2A5",
"fieldB": "value 2B5"
},
{
"id": 2005,
"name": "order 26",
"fieldA": "value 2A6",
"fieldB": "value 2B6"
}
]`;
const json2 =
`[
{
"id": 2004,
"name": "order 25",
"fieldA": "value 2A5",
"fieldB": "value 2B5"
},
{
"id": 2001,
"name": "order 22",
"fieldA": "value 2A2",
"fieldB": "value 2B2"
}
]`;
// check if JSON is valid
JSON.parse(json)
JSON.parse(json2)
const requestDelay = 0
export default [
{
url: '/issue-248',
method: 'get',
rawResponse: async (req, res) => {
res.setHeader('Content-Type', 'application/json')
res.statusCode = 200
setTimeout(function() {
res.end(json)
}, requestDelay);
},
},
{
url: '/issue-248-lookup',
method: 'get',
rawResponse: async (req, res) => {
res.setHeader('Content-Type', 'application/json')
res.statusCode = 200
setTimeout(function() {
res.end(json2)
}, requestDelay);
},
}
];
\ No newline at end of file
...@@ -341,7 +341,8 @@ class Select extends CustomControl { ...@@ -341,7 +341,8 @@ class Select extends CustomControl {
const result = convertValueToSelection.call(this, value); const result = convertValueToSelection.call(this, value);
setSelection setSelection
.call(this, result.selection) .call(this, result.selection)
.then(() => {}) .then(() => {
})
.catch((e) => { .catch((e) => {
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
}); });
...@@ -364,6 +365,9 @@ class Select extends CustomControl { ...@@ -364,6 +365,9 @@ class Select extends CustomControl {
* @property {string} type=radio Multiple (checkbox) or single selection (radio) * @property {string} type=radio Multiple (checkbox) or single selection (radio)
* @property {string} name=(random id) Name of the form field * @property {string} name=(random id) Name of the form field
* @property {string} url Load options from server per url * @property {string} url Load options from server per url
* @property {string} lookup Load options from server per url
* @property {boolean} lookup.url=null Load options from server per url
* @property {boolean} lookup.individually=false Load options individually
* @property {Object} fetch Fetch [see Using Fetch mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) * @property {Object} fetch Fetch [see Using Fetch mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
* @property {String} fetch.redirect=error * @property {String} fetch.redirect=error
* @property {String} fetch.method=GET * @property {String} fetch.method=GET
...@@ -422,6 +426,10 @@ class Select extends CustomControl { ...@@ -422,6 +426,10 @@ class Select extends CustomControl {
useStrictValueComparison: false, useStrictValueComparison: false,
}, },
url: null, url: null,
lookup: {
url: null,
grouping: false,
},
labels: { labels: {
"cannot-be-loaded": "Cannot be loaded", "cannot-be-loaded": "Cannot be loaded",
"no-options-available": noOptionsAvailableMessage, "no-options-available": noOptionsAvailableMessage,
...@@ -513,11 +521,16 @@ class Select extends CustomControl { ...@@ -513,11 +521,16 @@ class Select extends CustomControl {
}); });
} }
if (self.getOption("url") !== null && !lazyLoadFlag) { if (self.getOption("url") !== null) {
if (lazyLoadFlag) {
lookupSelection.call(self);
} else {
self.fetch().catch((e) => { self.fetch().catch((e) => {
addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `${e}`); addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `${e}`);
}); });
} }
}
let lastValue = self.value; let lastValue = self.value;
self[internalSymbol].attachObserver( self[internalSymbol].attachObserver(
...@@ -529,7 +542,8 @@ class Select extends CustomControl { ...@@ -529,7 +542,8 @@ class Select extends CustomControl {
lastValue = n; lastValue = n;
setSelection setSelection
.call(self, n) .call(self, n)
.then(() => {}) .then(() => {
})
.catch((e) => { .catch((e) => {
addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `${e}`); addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, `${e}`);
}); });
...@@ -638,14 +652,21 @@ class Select extends CustomControl { ...@@ -638,14 +652,21 @@ class Select extends CustomControl {
fetchData fetchData
.call(this, url) .call(this, url)
.then((map) => { .then((map) => {
this[isLoadingSymbol] = false;
if ( if (
isObject(map) || isObject(map) ||
isArray(map) || isArray(map) ||
map instanceof Set || map instanceof Set ||
map instanceof Map map instanceof Map
) { ) {
try {
this.importOptions(map); this.importOptions(map);
} catch (e) {
setStatusOrRemoveBadges.call(this, "error");
reject(e);
return;
}
this[lastFetchedDataSymbol] = map; this[lastFetchedDataSymbol] = map;
let result; let result;
...@@ -658,11 +679,11 @@ class Select extends CustomControl { ...@@ -658,11 +679,11 @@ class Select extends CustomControl {
} }
result = setSelection.call(this, newValue); result = setSelection.call(this, newValue);
setTimeout(() => { requestAnimationFrame(() => {
checkOptionState.call(this); checkOptionState.call(this);
setStatusOrRemoveBadges.call(this, "closed"); setStatusOrRemoveBadges.call(this, "closed");
resolve(result); resolve(result);
}, 10); });
return; return;
} }
...@@ -671,7 +692,6 @@ class Select extends CustomControl { ...@@ -671,7 +692,6 @@ class Select extends CustomControl {
reject(new Error("invalid response")); reject(new Error("invalid response"));
}) })
.catch((e) => { .catch((e) => {
this[isLoadingSymbol] = false;
setStatusOrRemoveBadges.call(this, "error"); setStatusOrRemoveBadges.call(this, "error");
reject(e); reject(e);
}); });
...@@ -680,6 +700,7 @@ class Select extends CustomControl { ...@@ -680,6 +700,7 @@ class Select extends CustomControl {
.catch((e) => { .catch((e) => {
setStatusOrRemoveBadges.call(this, "error"); setStatusOrRemoveBadges.call(this, "error");
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
reject(e);
}); });
}); });
} }
...@@ -806,6 +827,45 @@ class Select extends CustomControl { ...@@ -806,6 +827,45 @@ class Select extends CustomControl {
} }
} }
function lookupSelection() {
const self = this;
setTimeout(() => {
const selection = self.getOption("selection");
if (selection.length === 0) {
return;
}
if (self[isLoadingSymbol] === true) {
return;
}
if (self[lazyLoadDoneSymbol] === true) {
return;
}
let url = self.getOption("url");
let lookupUrl = self.getOption("lookup.url");
if (lookupUrl !== null) {
url = lookupUrl;
}
if(this.getOption("lookup.grouping") === true) {
filterFromRemoteByValue.call(self, url, selection.map((s) => s?.["value"]));
return;
}
for (const s of selection) {
if (s?.["value"]) {
filterFromRemoteByValue.call(self, url, s?.["value"]);
}
}
}, 100);
}
/** /**
* This attribute can be used to pass a URL to this select. * This attribute can be used to pass a URL to this select.
* *
...@@ -1076,10 +1136,20 @@ function initOptionObserver() { ...@@ -1076,10 +1136,20 @@ function initOptionObserver() {
new Processing(() => { new Processing(() => {
try { try {
self.updateI18n(); self.updateI18n();
} catch (e) {} } catch (e) {
console.error(e);
requestAnimationFrame(() => {
setStatusOrRemoveBadges.call(self, "error");
});
}
try { try {
areOptionsAvailableAndInit.call(self); areOptionsAvailableAndInit.call(self);
} catch (e) {} } catch (e) {
console.error(e);
requestAnimationFrame(() => {
setStatusOrRemoveBadges.call(self, "error");
});
}
setSummaryAndControlText.call(self); setSummaryAndControlText.call(self);
}).run(); }).run();
...@@ -1095,7 +1165,8 @@ function getDefaultTranslation() { ...@@ -1095,7 +1165,8 @@ function getDefaultTranslation() {
try { try {
const doc = getDocumentTranslations(); const doc = getDocumentTranslations();
translation.locale = doc.locale; translation.locale = doc.locale;
} catch (e) {} } catch (e) {
}
return translation; return translation;
} }
...@@ -1470,15 +1541,26 @@ function filterFromRemote() { ...@@ -1470,15 +1541,26 @@ function filterFromRemote() {
return; return;
} }
return filterFromRemoteByValue.call(this, optionUrl, this[inlineFilterElementSymbol].value);
}
/**
* @private
*/
function filterFromRemoteByValue(optionUrl, value) {
return new Processing(() => { return new Processing(() => {
const filterValue = encodeURI( const filterValue = encodeURI(
this[inlineFilterElementSymbol].value.toLowerCase(), value
); );
let url = optionUrl; let url = optionUrl;
if (filterValue.length > 0) { if (filterValue.length > 0) {
const formatter = new Formatter({filter: filterValue}); const formatter = new Formatter({filter: filterValue});
const openMarker = this.getOption("formatter.marker.open"); const openMarker = this.getOption("filter.marker.open");
let closeMarker = this.getOption("formatter.marker.close"); let closeMarker = this.getOption("filter.marker.close");
if (!closeMarker) { if (!closeMarker) {
closeMarker = openMarker; closeMarker = openMarker;
} }
...@@ -1691,7 +1773,8 @@ function gatherState() { ...@@ -1691,7 +1773,8 @@ function gatherState() {
setSelection setSelection
.call(this, selection) .call(this, selection)
.then(() => {}) .then(() => {
})
.catch((e) => { .catch((e) => {
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`); addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
}); });
...@@ -1720,7 +1803,8 @@ function clearSelection() { ...@@ -1720,7 +1803,8 @@ function clearSelection() {
setSelection setSelection
.call(this, []) .call(this, [])
.then(() => {}) .then(() => {
})
.catch((e) => { .catch((e) => {
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`); addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, `${e}`);
}); });
...@@ -2001,6 +2085,7 @@ function setSelection(selection) { ...@@ -2001,6 +2085,7 @@ function setSelection(selection) {
* @throws {TypeError} unsupported response * @throws {TypeError} unsupported response
*/ */
function fetchData(url) { function fetchData(url) {
const self = this;
if (!url) url = this.getOption("url"); if (!url) url = this.getOption("url");
if (!url) return Promise.resolve(); if (!url) return Promise.resolve();
...@@ -2019,10 +2104,12 @@ function fetchData(url) { ...@@ -2019,10 +2104,12 @@ function fetchData(url) {
url, url,
); );
self[isLoadingSymbol] = true;
const global = getGlobal(); const global = getGlobal();
return global return global
.fetch(url, fetchOptions) .fetch(url, fetchOptions)
.then((response) => { .then((response) => {
self[isLoadingSymbol] = false;
delayWatch = true; delayWatch = true;
const contentType = response.headers.get("content-type"); const contentType = response.headers.get("content-type");
if (contentType && contentType.indexOf("application/json") !== -1) { if (contentType && contentType.indexOf("application/json") !== -1) {
...@@ -2039,6 +2126,7 @@ function fetchData(url) { ...@@ -2039,6 +2126,7 @@ function fetchData(url) {
} }
}) })
.catch((e) => { .catch((e) => {
self[isLoadingSymbol] = false;
delayWatch = true; delayWatch = true;
throw e; throw e;
}); });
...@@ -2080,9 +2168,10 @@ function show() { ...@@ -2080,9 +2168,10 @@ function show() {
checkOptionState.call(this); checkOptionState.call(this);
requestAnimationFrame(() => { requestAnimationFrame(() => {
show.call(this); show.call(this);
}); })
}) })
.catch((e) => { .catch((e) => {
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
setStatusOrRemoveBadges.call(this, "error"); setStatusOrRemoveBadges.call(this, "error");
}); });
...@@ -2090,6 +2179,7 @@ function show() { ...@@ -2090,6 +2179,7 @@ function show() {
.run() .run()
.catch((e) => { .catch((e) => {
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message); addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
setStatusOrRemoveBadges.call(this, "error");
}); });
return; return;
...@@ -2131,8 +2221,8 @@ function toggle() { ...@@ -2131,8 +2221,8 @@ function toggle() {
/** /**
* @private * @private
* @fires Monster.Components.Form.event:monster-selection-removed * @fires monster-selection-removed
* @fires Monster.Components.Form.event:monster-selection-cleared * @fires monster-selection-cleared
*/ */
function initEventHandler() { function initEventHandler() {
const self = this; const self = this;
...@@ -2335,6 +2425,13 @@ function setStatusOrRemoveBadges(suggestion) { ...@@ -2335,6 +2425,13 @@ function setStatusOrRemoveBadges(suggestion) {
const current = this.getOption("classes.statusOrRemoveBadge"); const current = this.getOption("classes.statusOrRemoveBadge");
if (suggestion === "error") {
if (current !== "error") {
this.setOption("classes.statusOrRemoveBadge", "error");
}
return;
}
if (this[isLoadingSymbol] === true) { if (this[isLoadingSymbol] === true) {
if (current !== "loading") { if (current !== "loading") {
this.setOption("classes.statusOrRemoveBadge", "loading"); this.setOption("classes.statusOrRemoveBadge", "loading");
...@@ -2343,7 +2440,6 @@ function setStatusOrRemoveBadges(suggestion) { ...@@ -2343,7 +2440,6 @@ function setStatusOrRemoveBadges(suggestion) {
} }
if (suggestion === "loading") { if (suggestion === "loading") {
this[isLoadingSymbol] = true;
if (current !== "loading") { if (current !== "loading") {
this.setOption("classes.statusOrRemoveBadge", "loading"); this.setOption("classes.statusOrRemoveBadge", "loading");
} }
...@@ -2382,7 +2478,8 @@ function setStatusOrRemoveBadges(suggestion) { ...@@ -2382,7 +2478,8 @@ function setStatusOrRemoveBadges(suggestion) {
} }
return; return;
} }
}); })
} }
/** /**
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment