widgets-toolbox icon indicating copy to clipboard operation
widgets-toolbox copied to clipboard

Unable to use focus() for wt.PasswordField

Open versionbayjc opened this issue 1 year ago • 2 comments

In my user interface, I'm using a wt.PasswordField, but I can't use the focus() function (since R2022a) to get the keyboard focus in the password field. Can this be somehow added? I couldn't find any documentation in MATLAB on how you're supposed to add support for focus for custom components...

image

I'm not a fan of a UI with a single field for entering data, that I have to click on with my mouse, or use TAB to get to.

versionbayjc avatar Jan 09 '25 13:01 versionbayjc

Hi @versionbayjc, I played around with this a bit and could not come up with anything that worked. I submitted an enhancement request to the development team which is number g3624772.

rjackey avatar Mar 31 '25 16:03 rjackey

Hi @versionbayjc , I got some input on how to achieve this. I don't have time to implement it right now, but if you want to play around with it I am including the example below:

fig = uifigure('Name','Testing Focus');
htmlComp = uihtml(fig);
htmlComp.HTMLSource = 'focusEx.html';
htmlComp.Position = [10 10 300 300];
b = uibutton(fig); b.Position = [350 350 100 20];
b.ButtonPushedFcn = @(~,~)sendEventToHTMLSource(htmlComp, 'focusInput', '');

focusEx.html:

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript">		
    var myComponent;
    function setup(htmlComponent) {
    myComponent = htmlComponent;
    htmlComponent.addEventListener("DataChanged", updateData);
    htmlComponent.addEventListener("focusInput", focusInputField);
    // MATLAB side 'DataChangedFcn' callback will be triggered
    document.getElementById("myInput").addEventListener("change", updateDataToMatlab);   
    document.getElementById("mainBody").onload = function () {
        htmlComponent.dispatchEvent("BODYLOADED");
    };
    }
    function updateData(e) {
        var changedData = e.Data;
        // Update your HTML or JavaScript with the new data
        var dom = document.getElementById("Content");
        dom.textContent = changedData;
    }
    function updateDataToMatlab(e) {
        // newData can be passed directly to this function for debug purpose
        var newData = document.getElementById("myInput").value;
        // Triggering MATLAB DataChangedFcn and change the MATLAB Data
        myComponent.Data = newData;
    }
    function focusInputField(e) {
        // Get the input element
        const inputElement = document.getElementById('myInput');
        // Focus the input element
        if (inputElement) {
            inputElement.focus();
        }
    }
</script>
</head>
<body id="mainBody">
    <div id ="Content"></div>
    </div>
    <br/><br/>
    <div style="font-family:sans-serif;">
        <span style="font-weight:bold;"> 
        The data entered here will be updated to MATLAB:
        <br/>
        Also when focus event will focus this Input Field
        </span><br />
        <input type="text" id ="myInput" tabindex="0"></input>
    </div>
</body>
</html>

rjackey avatar Apr 17 '25 17:04 rjackey

Hi @rjackey, nice input, it works indeed. However, it is only compatible for MATLAB R2023a and later, as the sendEventToHTMLSource method is not available in earlier releases.

This got me thinking about how to solve it for earlier releases as well. I came up with the following solution: if the HTML Data is a structure that contains fields Value and DoFocus, the focus function can be triggered by setting DoFocus in the Data to TRUE instead of triggering a separate event. See example below:

fig = uifigure('Name','Testing Focus');
htmlComp = uihtml(fig);
htmlComp.Data = struct('Value', 'password', 'DoFocus', false);
htmlComp.HTMLSource = 'focusEx.html';
htmlComp.DataChangedFcn = @(s,e) fprintf('Data value changed to: %s\n', e.Data.Value);
htmlComp.Position = [10 10 300 300];
b = uibutton(fig); b.Position = [350 350 100 20];
b.ButtonPushedFcn = @(~,~)set(htmlComp, 'Data', struct('Value', htmlComp.Data.Value, 'DoFocus', true));

focusEx.html:

<input type="text" id="value" style="width:100%;height:100%">
<script type="text/javascript">
	
    function setup(htmlComponent) {
            
        // Code response to data changes in MATLAB
        htmlComponent.addEventListener("DataChanged", dataFromMATLABToHTML);

        // Update the Data property of the htmlComponent object
        // This action also updates the Data property of the MATLAB HTML object
        // and triggers the DataChangedFcn callback function
        let dataInput = document.getElementById("value")
        dataInput.addEventListener("change", dataFromHTMLToMATLAB);

        // Trigger a DataChangedFcn callback when enter is pressed.
        document.addEventListener("keyup", onKeyPressed);

        function dataFromMATLABToHTML(event) {
            let changedData = htmlComponent.Data;
            console.log("New data from MATLAB:", changedData);
            
            // Update your HTML or JavaScript with the new data
            let domValue = document.getElementById("value");
            domValue.value = changedData.Value;

            // Focus on the input element
            if (changedData.DoFocus){

                // Focus on input field
                domValue.focus();
                domValue.select();

                // Revert value for focus event
                changedData.DoFocus = false;
                htmlComponent.Data = changedData;
            }
        }

        function dataFromHTMLToMATLAB(event) {
            let newValue = event.target.value;
            let newData = htmlComponent.Data;

            newData.Value = newValue;
            
            htmlComponent.Data = newData;
            console.log("New data in HTML:", newData)
        }

        function onKeyPressed(event) {

            // Get data to change
            let newData = htmlComponent.Data;
            let domValue = document.getElementById("value");
            
            // ENTER key?
            if (event.keyCode === 13) { 
                newData.Value = domValue.value + "\n";
                htmlComponent.Data = newData;
            }
        }
    }
</script>

slootsjj avatar May 14 '25 18:05 slootsjj

@versionbayjc we believe this is fixed by @slootsjj. If any issues, reopen this.

rjackey avatar Aug 06 '25 20:08 rjackey