PASOE/REST/DOH Custom .map file

Posted by jts-law on 18-Apr-2018 15:14

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

Posted by jts-law on 19-Apr-2018 16:53

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

All Replies

Posted by jts-law on 18-Apr-2018 16:12

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

Posted by Peter Judge on 19-Apr-2018 12:27

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"}
    ]
},

Posted by jts-law on 19-Apr-2018 16:53

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

Posted by Peter Judge on 19-Apr-2018 17:18

I’m glad you managed to get past this issue.
 
We have some issues (that you logged, I think) relating to mapping parts-of-multipart that will have fixes in this area (arrays and parts and individual properties are conceptually quite similar). So I expect to have fixes for this but not in the very short term (ie not the next 11.7 SP).
 
 

This thread is closed