I am working on a KUIB app and want to implement a ComboBox with virtual scrolling. Based on the documentation (https://docs.telerik.com/kendo-ui/controls/editors/combobox/virtualization), I need to setup a mapper service. The mapper service needs to have a signature like:
http://demos.telerik.com/kendo-ui/service/Orders/ValueMapper?values[0]=10661
I've been struggling to implement a REST/DOH service with this signature. The following is what I'm currently trying and it's returning a "Service not found" error.
CustList.cls (basic stub method until I see what Kendo sends for data):
METHOD PUBLIC INT CustValueMapper(INPUT search_values AS CHARACTER EXTENT, OUTPUT matched_data AS Progress.Json.ObjectModel.JsonObject): MESSAGE "search_values: " search_values[1]. matched_data = NEW JsonObject(). RETURN 200. END METHOD.
UI.map (this service only):
"/CustValueMapper": { "GET": { "contentType": "application\/json", "entity": { "name": "CustList", "function": "CustValueMapper", "arg": [ { "ablName": "", "ablType": "INTEGER", "ioMode": "RETURN", "msgElem": {"type": "StatusCode", "name": null} }, { "ablName": "search_values", "ablType": "CHARACTER EXTENT", "ioMode": "INPUT", "msgElem": {"type": "QUERY", "name": "values"} }, { "ablName": "matched_data", "ablType": "Progress.Json.ObjectModel.JsonObject", "ioMode": "OUTPUT", "msgElem": {"type": "BODY", "name": null} } ] } } }
Test Call:
http://localhost:8810/JTS/web/pdo/UI/CustValueMapper?values[0]=%22Testing%22
Response:
[ { _retVal: "", _errors: [ { _errorMsg: "Not Found", _errorNum: 404 } ] }, { _retVal: "", _errors: [ { _errorMsg: "Service not found for "GET http://localhost:8810/JTS/web/pdo/UI/CustValueMapper?values[0]="Testing""", _errorNum: 0 } ] } ]
Anybody have a clue how to configure my method and map file entry to accept this URL?
Thanks.
Louis
Peter,
Today I figured out how to get around this. Since my combo box is a single select, I will only ever have 1 value passed to the mapper service. This means I don't need the extent. I changed my map, method, and javascript convert method as follows and this looks to be working (although having just got it going today I haven't tested much). Note, as I continued testing I also found I had to change the contentType and add another query parameter.
.map file:
"/CustValueMapper": { "GET": { "contentType": "application/x-javascript", "entity": { "name": "CustList", "function": "CustValueMapper", "arg": [ { "ablName": "", "ablType": "INTEGER", "ioMode": "RETURN", "msgElem": {"type": "StatusCode", "name": null} }, { "ablName": "callback", "ablType": "CHARACTER", "ioMode": "INPUT", "msgElem": {"type": "QUERY", "name": "callback"} }, { "ablName": "search_value", "ablType": "CHARACTER", "ioMode": "INPUT", "msgElem": {"type": "QUERY", "name": "value"} }, { "ablName": "response", "ablType": "CHARACTER", "ioMode": "OUTPUT", "msgElem": {"type": "BODY", "name": null} } ] } } }
ABL method:
METHOD PUBLIC INT CustValueMapper(INPUT callback AS CHARACTER, INPUT search_value AS CHARACTER, OUTPUT response AS CHARACTER): oJTSConfig:Logit(5, "CustValueMapper() search_value: " + search_value). response = callback + "([0])". RETURN 200. END METHOD.
JS method:
convertValues(value) { let data = {}; // value = $.isArray(value) ? value : [value]; // for (let idx = 0; idx < value.length; idx++) { // data["values[" + idx + "]"] = value[idx]; // } data["value"] = value; // Not a multiselect so return single value return data; }
I'm still working out the details for the actual ABL mapper method but basically it needs to find the record and return the index of it within the full temp table data used for the combo box.
It would still be nice to figure out how to pass an array of data to an ABL extent field. Somebody will eventually need to use this for pre-fetching data for a combo box, dropdown, grid, etc.
Louis
EDIT: I found a typo that was causing the 404. The output type was wrong.
"Progress.Json.ObjectModel.JsonObject" should have been "CLASS Progress.Json.ObjectModel.JsonObject"
Now my method is getting called but the input extent field that is mapped to the "values" query parameter does not contain any extents. If I put a "MESSAGE EXTENTS(search_values)" it displays a null (?).
I guess now the question is how to map the query parameter (which is an array) to an ABL extent field?
Louis
Louis,
It looks like the current implementation for input char arrays only accepts values from JSON arrays. Ideally you'd be able to specify the mapping like the below snippet, but this isn't working.
// snippet { "ablName": "search_values", "ablType": "CHARACTER EXTENT", "ioMode": "INPUT", "msgElem": [ {"type": "QUERY","name": "first"}, {"type": "QUERY","name": "second"}, {"type": "QUERY","name": "third"} ] },
Peter,
Today I figured out how to get around this. Since my combo box is a single select, I will only ever have 1 value passed to the mapper service. This means I don't need the extent. I changed my map, method, and javascript convert method as follows and this looks to be working (although having just got it going today I haven't tested much). Note, as I continued testing I also found I had to change the contentType and add another query parameter.
.map file:
"/CustValueMapper": { "GET": { "contentType": "application/x-javascript", "entity": { "name": "CustList", "function": "CustValueMapper", "arg": [ { "ablName": "", "ablType": "INTEGER", "ioMode": "RETURN", "msgElem": {"type": "StatusCode", "name": null} }, { "ablName": "callback", "ablType": "CHARACTER", "ioMode": "INPUT", "msgElem": {"type": "QUERY", "name": "callback"} }, { "ablName": "search_value", "ablType": "CHARACTER", "ioMode": "INPUT", "msgElem": {"type": "QUERY", "name": "value"} }, { "ablName": "response", "ablType": "CHARACTER", "ioMode": "OUTPUT", "msgElem": {"type": "BODY", "name": null} } ] } } }
ABL method:
METHOD PUBLIC INT CustValueMapper(INPUT callback AS CHARACTER, INPUT search_value AS CHARACTER, OUTPUT response AS CHARACTER): oJTSConfig:Logit(5, "CustValueMapper() search_value: " + search_value). response = callback + "([0])". RETURN 200. END METHOD.
JS method:
convertValues(value) { let data = {}; // value = $.isArray(value) ? value : [value]; // for (let idx = 0; idx < value.length; idx++) { // data["values[" + idx + "]"] = value[idx]; // } data["value"] = value; // Not a multiselect so return single value return data; }
I'm still working out the details for the actual ABL mapper method but basically it needs to find the record and return the index of it within the full temp table data used for the combo box.
It would still be nice to figure out how to pass an array of data to an ABL extent field. Somebody will eventually need to use this for pre-fetching data for a combo box, dropdown, grid, etc.
Louis