JSONata input is validated as JSON

Hi there, I am creating a custom node with an editable list:


But I am having some trouble with the 'Response' JSONata field:
image
Im trying to get 'greeting' from msg like you would do in any JSONata input, but here the validator seems to think this is a JSON and since 'greeting' doesnt have quotes it throws an error.

As I mentioned before this is an editable list so I need to create the fields dynamically(I have no problem when the JSONata input is "static"), this is how I create the JSONata input inside oneditprepare( ):

let row5_jsonata = $('<input/>', { class: "node-input-jsonata-response",style:"width:81%;"})
	.appendTo(row5)
    .typedInput({ 
        default: "jsonata",
        types: ['jsonata'] 
    });

row5_jsonata.typedInput('value', options.customMsg);

Is this wrong? Thanks in advance

You didn't put "greeting" in quotes.

yeah thats the point, I want to set 'hi' to the value I assign previously in msg.greeting, this should work in JSONata

Without seeing everything, it is hard to guess what has happened. But my guess is that you need something like $$.greeting in the JSONata. At the moment, it not recognising greeting as a property.

Not working either
image

This is the entire HTML file:

<script src="resources/@scg-scts-dc/node-red-contrib-scf-utils/constants.js"></script>

<script type="text/javascript">
    RED.nodes.registerType('test-ui', {
        category: 'function',
        color: '#59C6CE',
        defaults: {
            name: { value: "", required: false },
            outputs: { value: 2, required: true },
            previousOutputs: { value: 1 }, // value does nothing
            configs: { value: [{ statusIn: '*', output: 2, statusOut: '500', format: "simple", customMsg: null}] }
        },
        inputs: 1,
        icon: "font-awesome/fa-info",
        label: function() {
            return this.name || "test-ui";
        },
        oneditprepare: function() {
            let node = this;
            node.previousOutputs = node.outputs;

            $("#node-input-outputs").css('width', '60px').spinner({
                min: 1,
                change: function (event, ui) {
                    let value = this.value;
                    if (!value.match(/^\d+$/)) { //not a number
                        value = node.previousOutputs; 
                    }
                    else if (value < this.min) { // less than min
                        value = this.min; 
                    }
                    else { //valid
                        node.previousOutputs = value;
                    }


                    if (value !== this.value) { //value changed
                        $(this).spinner("value", value); 
                    }
                }
            });

            $('#node-input-rule-list').editableList({
                addItem: function (container, index, options) {
                    //If it has own property is from array and already has values, if not we put default values
                    if (!options.hasOwnProperty('output')) {
                        //Default values status in * and out 500
                        options = { statusIn: "2XX", output: 1, statusOut: null, format: "simple", customMsg: null };
                    }

                    container.css({
                        overflow: 'hidden',
                        whiteSpace: 'nowrap'
                    });

                    //HTML container creation 
                    let fragment = document.createDocumentFragment();

                    //Creation of rows, one per attribute
                    let row1 = $('<div/>', { style: "display:flex; align-items: baseline" }).appendTo(fragment);
                    let row2 = $('<div/>', { style: "display: flex;align-items: baseline;margin-top:8px;" }).appendTo(fragment);
                    let row3 = $('<div/>', { style: "display: flex;align-items: baseline;margin-top:8px;" }).appendTo(fragment);
                    let row4 = $('<div/>', { style: "display: flex;align-items: baseline;margin-top:8px;" }).appendTo(fragment);
                    let row5 = $('<div/>', { style: "display: flex;align-items: baseline;margin-top:8px;" }).appendTo(fragment);

                    //Row 1: STATUS IN
                    let row1_label = $('<div/>', { style: "margin-right:10px; width:70px; text-align:right;" })
                        .text("Status in:")
                        .appendTo(row1);
                    let row1_statusSelect = $('<select/>', { class: "node-input-statusSelect", style: "width:40%; margin-right:10px;" })
                        .appendTo(row1);
                    let row1_statusCodeInput = $('<input/>', { class: "node-input-statusCode", style: "width:40%; box-sizing:border-box;" })
                        .appendTo(row1)
                        .typedInput({ types: ['num'] });
                    let row1_statusGroupSelect = $('<select/>', { class: "node-input-statusGroupSelect", style: "width:40%;" })
                        .appendTo(row1);

                    let statusOptions = [{ value: "code", label: "Status code" }, { value: "group", label: "Status group" }, { value: "otherwise", label: "Anything else" }];
                    for (let i = 0; i < statusOptions.length; i++) {
                        row1_statusSelect.append($("<option></option>").val(statusOptions[i].value).text(statusOptions[i].label));
                    }

                    let statusGroupOptions = [{ value: "1XX", label: "1XX" }, { value: "2XX", label: "2XX" }, { value: "3XX", label: "3XX" }, { value: "4XX", label: "4XX" }, { value: "5XX", label: "5XX" }];
                    for(let i = 0; i < statusGroupOptions.length; i++) {
                        row1_statusGroupSelect.append($("<option></option>").val(statusGroupOptions[i].value).text(statusGroupOptions[i].label));
                    }

                    //Set values from options object
                    let statusInChange = function(status) {
                        if(status === "code") {
                            row1_statusCodeInput.typedInput('show');
                            row1_statusGroupSelect.hide();
                        }
                        else if (status === "group") {
                            row1_statusCodeInput.typedInput('hide');
                            row1_statusGroupSelect.show();
                        }
                        else if(status === "otherwise") {
                            row1_statusCodeInput.typedInput('hide');
                            row1_statusGroupSelect.hide();
                        }
                    };

                    if(options.statusIn === "*") { //otherwise(*)
                        statusInChange("otherwise");
                        row1_statusSelect[0].value = "otherwise";
                    } 
                    else if(options.statusIn.toLowerCase().endsWith("xx")) { //group(2XX)
                        statusInChange("group");
                        row1_statusSelect[0].value = "group";
                        row1_statusGroupSelect[0].value = options.statusIn.toUpperCase();
                    } 
                    else { //code(201)
                        statusInChange("code");
                        row1_statusSelect[0].value = "code";
                        row1_statusCodeInput.typedInput('value', options.statusIn);
                    }

                    row1_statusSelect[0].addEventListener('change', (event) => {
                        statusInChange(event.target.value);
                    });

                    //Row 2: OUTPUT
                    let row2_label = $('<div/>', { style: "margin-right:10px; width:70px; text-align:right;" })
                        .text("Output:")
                        .appendTo(row2);

                    let row2_output = $('<input/>', { class: "node-input-output", style: "width:81%;"})
                        .appendTo(row2)
                        .typedInput({ types: ['num'] });

                    row2_output.typedInput('value', options.output);

                    //Row 3: STATUS OUT
                    let row3_label = $('<div/>', { style: "margin-right:10px; width:70px; text-align:right;" })
                        .text("Status out:")
                        .appendTo(row3);

                    let row3_statusOut = $('<input/>', { class: "node-input-statusOut", placeholder: "Leave empty to mantain current status code", style: "width:81%;"})
                        .appendTo(row3)
                        .typedInput({ types: ['num'] });

                    row3_statusOut.typedInput('value', options.statusOut);

                    //Row 4: FORMAT
                    let row4_blankLabel = $('<div/>', { style: "margin-right:10px; width:70px; text-align:right;" })
                        .text("")
                        .appendTo(row4);
                    let row4_formatSelect = $('<select/>', { class: "node-input-formatSelect", style: "width:81%;" })
                        .appendTo(row4);

                    let formatOptions = [{ value: "none", label: "No format" }, { value: "simple", label: "Simple format" }, { value: "moreInfo", label: "More information format" }, { value: "custom", label: "Custom format" }];
                    for (let i = 0; i < formatOptions.length; i++) {
                        row4_formatSelect.append($("<option></option>").val(formatOptions[i].value).text(formatOptions[i].label));
                    }

                    row4_formatSelect.val(options.format);

                    //Row 5: CUSTOM FORMAT
                    let row5_label = $('<div/>', { style: "margin-right:10px; width:70px; text-align:right;" })
                        .text("Response:")
                        .appendTo(row5);
                    let row5_jsonata = $('<input/>', { class: "node-input-jsonata-response",style:"width:81%;"})
                        .appendTo(row5)
                        .typedInput({ 
                            default: "jsonata",
                            types: ['jsonata'] 
                        });

                    row5_jsonata.typedInput('value', options.customMsg);

                    let formatInChange = function (format) {
                      if(format === "custom") {
                        row5.show();
                        let jsonataVal = row5_jsonata.typedInput('value');
                        if((jsonataVal === undefined || jsonataVal === null || jsonataVal === "")) {
                            let statusForJsonata;
                            switch(row1_statusSelect[0].value) {
                                case "code": 
                                    statusForJsonata = HTTP_CODE_MAP[row1_statusCodeInput.typedInput('value')] ? row1_statusCodeInput.typedInput('value') : undefined;
                                    break;
                                case "group":
                                    switch(row1_statusGroupSelect[0].value) {
                                        case "2XX":
                                            statusForJsonata = 200;
                                            break;
                                        case "4XX":
                                            statusForJsonata = 400;
                                            break;
                                        case "5XX":
                                            statusForJsonata = 500;
                                            break;
                                    }
                                    break;
                                case "otherwise":
                                    statusForJsonata = 500;
                                    break;
                            }
                            if(statusForJsonata) {
                                console.log(JSON.stringify({
                                    "httpCode": statusForJsonata,
                                    "httpMessage": HTTP_CODE_MAP[statusForJsonata].message,
                                    "moreInformation": HTTP_CODE_MAP[statusForJsonata].moreInfo
                                }, null, "\t"));
                                row5_jsonata.typedInput('value', JSON.stringify({
                                    "httpCode": statusForJsonata,
                                    "httpMessage": HTTP_CODE_MAP[statusForJsonata].message,
                                    "moreInformation": HTTP_CODE_MAP[statusForJsonata].moreInfo
                                }, null, "\t"));
                            }
                        }
                      }
                      else {
                        row5.hide();
                      }  
                    };

                    formatInChange(options.format);

                    row4_formatSelect[0].addEventListener('change', (event) => {
                        formatInChange(event.target.value);
                    });

                    //Add fragment to container
                    container[0].appendChild(fragment);
                },
                removable: true,
                sortable: true
            });

            //Store currents configs in container when is opens
            for (let i = 0; i < this.configs.length; i++) {
                let config = this.configs[i];
                $("#node-input-rule-list").editableList('addItem', config);
            }

            //Bigger editable list
            $('#node-input-rule-list').css('min-width', '400px').css('height', '100%');
            $('#node-input-rule-list')[0].parentNode.style.height = '100%';
            $('#node-input-rule-list')[0].parentNode.parentNode.style.height = "85%";
        },
        oneditsave: function() {
            let configs = $("#node-input-rule-list").editableList('items');
            let node = this;
            node.configs = [];
            configs.each(function () {
                let statusIn;
                let statusSelect = $(this).find(".node-input-statusSelect").val();

                if(statusSelect === "otherwise") {
                    statusIn = "*";
                } 
                else if(statusSelect === "code") {
                    statusIn = $(this).find(".node-input-statusCode").typedInput('value');
                }
                else if(statusSelect === "group") {
                    statusIn = $(this).find(".node-input-statusGroupSelect").val();
                }

                node.configs.push({
                    statusIn: statusIn,
                    output: $(this).find(".node-input-output").typedInput('value'),
                    statusOut: $(this).find(".node-input-statusOut").typedInput('value'),
                    format: $(this).find(".node-input-formatSelect").val(),
                    customMsg: $(this).find(".node-input-jsonata-response").typedInput('value')
                });
            });
        }
    });
</script>

<script type="text/x-red" data-template-name="test-ui">
    <div class="form-row">
        <label for="node-input-name"><i class="icon-tag"></i> Name</label>
        <input type="text" id="node-input-name" placeholder="test-ui">
    </div>
    <div class="form-row">        
        <label for="node-input-outputs"><i class="icon-tag"></i>Outputs</label>        
        <input id="node-input-outputs">    
    </div>
    <ol id="node-input-rule-list"></ol>
</script>

<script type="text/x-red" data-help-name="test-ui">
    <p>Node to store functions that facilitate development</p>
</script>

I just noticed the problem is inside the .js file and not in the .html file, I was so sure that it was an HTML validation kinda thing, but it seems I was wrong, my bad, sorry for the trouble.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.