How to capture focus and blur events on a typedInput element

ref: Node 18.12.1 and Node-red 3.0.1

I can't seem to capture the onfocus and onblur events for a typedInput in the node edit dialog. I use this to show/hide a tip field at the bottom of the form. It works for text input fields but not typedInputs.

Here's a subsection of my custom node HTML with examples of a simple text input field and a typedInput field (i.e. JSON and JSONata types) ...

<div class="form-row">
    <label for="node-input-stat"><i class="fa fa-tag"></i> <span data-i18n="broker.label.stat"></span></label>
    <input type="text" id="node-input-stat" data-i18n="[placeholder]broker.placeholder.stat">
</div>
<div class="form-row" id="form-row-input-custom">
    <label id="node-input-custom-label" for="node-input-custom"><i class="fa fa-tag"></i> <span data-i18n="broker.label.custom"></span></label>
    <input type="text" id="node-input-custom" data-i18n="[placeholder]broker.placeholder.custom">
    <input type="hidden" id="node-input-customType" />
</div>

<div class="form-tips" id="tip-stat" hidden><span data-i18n="broker.tips.stat"></span></div>
<div class="form-tips" id="tip-custom" hidden><span data-i18n="broker.tips.custom"></span></div>

In the JavaScript file within the oneditprepare function I have

            var addTipHandlers = (sel,tip)=>{
                $(sel).on('focus', function () { $(tip).show(); });
                $(sel).on('blur', function () { $(tip).hide(); });
            };
            addTipHandlers("#node-input-stat","#tip-stat"); // works fine
            // none of the following work...
            addTipHandlers("#form-row-input-custom","#tip-custom");
            addTipHandlers("#node-input-custom-label","#tip-custom");
            addTipHandlers("#node-input-custom","#tip-custom");
            addTipHandlers("#red-ui-typedInput-container","#tip-custom");
            addTipHandlers("#red-ui-typedInput-input-wrap","#tip-custom");
            addTipHandlers("#red-ui-typedInput-input","#tip-custom");
            addTipHandlers("#red-ui-typedInput-value-label","#tip-custom");
            addTipHandlers("#node-input-customType","#tip-custom");

This works fine for all the plain text inputs but not the custom typedInput element. As shown, I've tried matching all the different fields in the rendered HTML, but none seem to work. From a little console probing I'm guessing there is another layer or JQuery reference I'm missing.

Hi, I think you need to have a look in your browser's dev tools to see what is actually created.

While you create an ordinary input in your html file, when you apply typedInput, the standard input field is hidden and a more complex element is dynamically created. So to capture those events, you need to do so on the dynamic elements and not on your standard input field.

I was aware that the input text field gets dynamically replaced for the typedInput. I had looked at the resolved HTML in the console. That is where I got the various "#red-ui-typedInput-..." element references that I tried. I should have included that HTML in my original post. Here it is for the custom typedInput property example...

<div class="form-row" id="form-row-input-custom">
    <label id="node-input-custom-label" for="node-input-custom">
        <i class="fa fa-tag"></i> 
        <span data-i18n="@canyoncasa/node-red-cootie-broker/cootie-broker:broker.label.custom">Custom</span>
    </label>
    <input type="hidden" id="node-input-custom" 
        data-i18n="[placeholder]@canyoncasa/node-red-cootie-broker/cootie-broker:broker.placeholder.custom" 
        autocomplete="off" dir="" class="red-ui-typedInput" value="" placeholder="Optional custom payload object">
    <div class="red-ui-typedInput-container input-error" style="width: 345.02px; margin-right: 0px; margin-left: 0px;">
        <button type="button" class="red-ui-typedInput-type-select" tabindex="0" title="JSON">
        <i class="red-ui-typedInput-icon fa fa-caret-down"></i>
        <span class="red-ui-typedInput-type-label">
          <i class="red-ui-typedInput-icon" style="mask-image: url(red/images/typedInput/json.svg); 
            -webkit-mask-image: url(red/images/typedInput/json.svg); margin-right: 4px;height: 18px;width:13px"></i>
        </span>
        </button>
        <div class="red-ui-typedInput-input-wrap">
            <input class="red-ui-typedInput-input" type="text" autocomplete="off" 
              data-i18n="[placeholder]@canyoncasa/node-red-cootie-broker/cootie-broker:broker.placeholder.custom" 
              placeholder="Optional custom payload object" style="margin-right: 0px; margin-left: 0px;">
        </div>
        <div class="red-ui-typedInput-value-label" style="display: none;"></div>
        <button type="button" tabindex="0" class="red-ui-typedInput-option-trigger" style="display: none;">
          <span class="red-ui-typedInput-option-label"></span>
          <span class="red-ui-typedInput-option-caret">
          <i class="red-ui-typedInput-icon fa fa-caret-down"></i>
        </span>
        </button>
        <button type="button" tabindex="0" class="red-ui-typedInput-option-expand" style="display:inline-block">
          <i class="red-ui-typedInput-icon fa fa-ellipsis-h"></i>
        </button></div>
        <input type="hidden" id="node-input-customType" autocomplete="off" value="json" dir="" style="display: none;">
    </div>

Note too that the "red-ui-typedInput-container input-error" shows an error because it is empty, but I have tried it with valid input and it makes no difference.

I guess I didn't read all the details previously. So focus and blur will only trigger on input/button elements. And only on keyboard or mouse/touch entry/exit. I think anyway. Would need to test.

To be honest, to apply custom tooltips, which I think is what you are attempting to do? I use hover CSS. I use the aria-label attribute to hold the tooltips then css something like this:

<style>
    #uib-el *[aria-label] {
        position:relative;
    }
    #uib-el *[aria-label]::after {
        content: attr(aria-label);
        position:absolute;
        top:100%;left:50px;
        box-shadow: 0px 0px 24px rgba(0, 0, 0, 0.2);
        border: 1px solid var(--red-ui-form-input-border-color);
        padding: 10px;
        z-index: 999;
        background-color: var(--red-ui-popover-background);
        color: var(--red-ui-popover-color);
        max-width: 350px;
        text-decoration: none;
        text-align: center;
        border-radius: 6px;
        white-space: break-spaces;
        
        visibility: hidden;
        opacity: 0;
        transition: all 0.5s ease-out;
    }
    #uib-el *[aria-label]:hover::after {
        visibility: visible;
        opacity: 1;
        transition: all 0.5s ease-in 1s !important;
    }
</style>

My config panel html is all wrapped in a div with id set to uib-el. Not perfect but better than the default tooltips.

Looks like this:

image

Thanks @TotallyInformation for your comment. Not exactly what I was doing. (I copied the approach used by the serial-in node and some other nodes that places a single tip field at the bottom of the dialog.) If I had it to do over I would consider your approach. Certainly more stylish, but more work at this point.

Solved!

Turns out I was on the right track but I made an error in the element specificity that I discovered after letting it sit for 2 days. I had specified id's (i.e. #) for the red-ui-typedInput elements I tried instead of a class. The following works:

addTipHandlers("#form-row-input-custom input.red-ui-typedInput-input","#tip-custom");

The first part, #form-row-input-custom, is needed to differentiate the input element from other typedInput elements in the same dialog since the input has only a class and no id.

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