Styling of the dashboard text input node question

I have been playing around with the style of the text input node. A couple of things I cannot understand / get to work properly.
I have tried to shift my target temperature entry (in yellow) to the right. That has worked. I also magaged to changed the colour. But, under the yellow target temperature is a blue line. I tried to shorten it so its just under the yellow target temp. Now, after playing with the width, its worked in Chrome. In Firefox, it doesnt !
So thats the main problem.
Then, (if possible) I'd like the target temp (in blue) in a bigger font and centered in the middle (height) of the display, so its the same height and font size as the yellow target temp.
Using Chrome inspect I could not find anything useful, so I'm not sure thats possible.

So here is what the input looks like in Chrome:

image

Here it is in Firefox:

image

And this is what I currently have in this widgets style sheet (this is not just for the input node)

<style id="dashboard-styles-override">
   .nr-dashboard-theme md-select-menu md-option {
        background-color: var(--nr-dashboard-groupBorderColor);
        color: #eeeeee;
        height: 29px;
       /* border-radius: 14px;*/
        margin-left: 10px;
        margin-right: 10px;
        margin-top: 2px;
        box-shadow: 0 0 6px 6px #24202133;
        transition: 0.3s;
    }
    input {
        width: 50px;
        margin: 0 22px 0 120px;

    }
    .nr-dashboard-textinput md-input-container .md-input {
    color: yellow
    }
    .nr-dashboard-theme md-select-menu md-option[selected] {
        color: var(--color-blue-3) !important;
        background-color: var(--color-mikered) !important;
    }
    .nr-dashboard-theme md-select-menu md-option:nth-child(even) {
        background-color: var(--nr-dashboard-groupBorderColor);
        opacity:0.8;
    }
    .nr-dashboard-theme md-select-menu md-option:last-child {
       margin-bottom: 8px;
    }
    .nr-dashboard-theme md-select-menu md-option:hover {
        background-color: var(--nr-dashboard-widgetBackgroundColor) !important;
        padding-left: 24px;
    }
    .nr-dashboard-theme md-select-menu md-option > .md-ripple-container{
        /* border-radius: 14px;*/
    }

    .nr-dashboard-theme md-select .md-select-placeholder {
    color: slateblue !important;
    background-color: var(--color-yellow) !important;
    }

</style>

I just used the input node somewhere else, and I can see what happened. Its moving it right, but width seems to be ignored. Its now overlapping with the next column

image

Turn off all style overrides you have added and then turn them on one by one. Every time see result. This way you can identify the rule which affects. Then let's see what is wrong with that specific rule.

I have turned off every override except for the input node

This is all I have turned on at the moment

input {
        width: 50px;
        margin: 0 22px 0 120px;

    }
    .nr-dashboard-textinput md-input-container .md-input {
    color: yellow
    }

Its still showing as it did before. I guess that the parameters I am trying to change are the wrong ones. I wanted to move the figure I input to the middle, so that part is working.
What is not working is getting rid of the up/down buttons at the end of the input line (I cannot see it at the moment as its blocked by the next column) and ultimately the width of that blue line (with the up down buttons at the end)

Try this to get rid of the spinners

<style>
       input::-webkit-outer-spin-button,
       input::-webkit-inner-spin-button {
              display: none;
       }
       
</style>

The text input is very complicated widget. To make it behave and look different just with CSS it takes to know a lot and apply very heavy override. Just not reasonable.

If you want just label and input field side by side, do it yourself using the ui_template. It is simple enough. I do recommend to practice more with them. Do simple things like this is and you'll find that it much easier to do them from scratch rather than fighting with the CSS of ready made widgets.

[{"id":"de6f6d0003c8f83c","type":"ui_template","z":"bf0d83d32eec75c2","group":"674712f8d915bcc0","name":"text-input","order":6,"width":"6","height":"1","format":"<style>\n    .input-container{\n        display: flex;\n        gap: 1em;\n        flex-direction: row;\n        justify-content: space-between;\n        align-items: center;\n    }\n    .input-container > p {\n        color:red !important;\n        user-select:none;\n    }\n    .input-container > input{\n        background-color: transparent;\n        border: unset;\n        border-bottom: 1px solid #00a9ff;\n        outline: unset;\n        color: #e2ff00;\n        text-align: end;\n    }\n    \n</style>\n\n<p class='input-label'>INPUT</p>\n<input type=\"text\" ng-model=\"inputChange\"></input>\n\n<script>\n    (function(scope) {\n\n    scope.$watch('inputChange', function(data) {\n    if (data) {\n        console.log('inputChange: ',data)\n        if(data.length > 2){\n            scope.send({payload:data,topic:\"input-changed\"})\n        }    \n    }\n    });\n    \n    scope.$watch('msg', function(msg) {\n    if (msg) {\n      // Do something when msg arrives     \n    }\n  });\n})(scope);\n</script>\n","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":true,"templateScope":"local","className":"input-container","x":460,"y":1080,"wires":[["a27e62a699d480f9"]]},{"id":"a27e62a699d480f9","type":"debug","z":"bf0d83d32eec75c2","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":640,"y":1080,"wires":[]},{"id":"674712f8d915bcc0","type":"ui_group","name":"Default","tab":"62083694d0eab7ca","order":1,"disp":true,"width":"6","collapse":false,"className":""},{"id":"62083694d0eab7ca","type":"ui_tab","name":"Home","icon":"dashboard","disabled":false,"hidden":false}]
1 Like

This is exactly what I want. That seems to be a lot easier than the input node. One thing, can the input be changed that it only takes it after a enter ? Otherwise it would trigger my flow multiple times

Rather than the solution I'll write here some hints what to search from internet.
angularjs input keypress keycode enter

And then if you have tried and it does not work, let's see how to make it working.

1 Like

I am afraid I failed. I think I need to change the ng-model from inputChabge to keypress, and then evaluate if the key pressed is 13. But thats as far as I got. I tried a few things, but without really understand what you are doing, its hopeless...
I found a cheat which sort of works, if I change the if(data.length > 2){ to if(data.length > 3){ , it will only send after I entered the last digit. Still, not exactly what I wanted. I am not even sure how the keypress looking for key 13 would work in my case.
Sometimes, I control the dashboard from my PC (Firefox), but also equally important from my Android tablet.
I use this input field to set target temperatures for AC and Hot Water temperature in conjunction with my home automation system

Ok. Let's try this then.

The ng-model stays as is. That is bound to the change in the input field and you can "listen" those changes in scope with dedicated watcher scope.$watch('inputChange', function(data) { ...

To listen key presses it takes to add a directive <element ng-keypress="expression"></element>
The element is still same - the input.
The expression can be whatever you like it to do. It can be written very smart but can be just a function which will be called.

To get back on track here's one possible way to make such expression:

<input type="text" ng-model="inputChange" ng-keypress="$event.keyCode === 13 && sendInput()"></input>

It does 2 things. It filters key presses down to "Enter" only and if so - it calls a function.

That function must be available in scope.

 scope.sendInput = function() { ...

Now try to figure out how it all comes together.

I cant figure it out. I tried many ways of adding the scope.sendInput to the code, but either it still sent while I was typing, or nothing at all.

This was my last attempt

<input type="text" ng-model="inputChange" ng-keypress="$event.keyCode === 13 && sendInput()"></input>

<script>
    (function(scope) {    

    scope.$watch('inputChange', function(data) {

        scope.sendInput = function() {
    
       scope.send({payload:data,topic:"input-changed"})
        }  
    }
    
    });

Think that way - the scope.$watch('inputChange' is fired only if you type (or delete) something at the input field. If you place another function inside it, it can do it's job only at that moment when some changes happening.

The key press does not happen at the same time. It is independent event - thus the function must be also independent.

Now there is another problem. The data. The keypress event doesn't know anything about the input field content. So in the function scope.sendInput = function() ... the data to send is not directly available.

But as the scope.$watch('inputChange', function(data) {.. function has the data - it can be written into scope variable so the another function can then use that data from that variable. (send to the server side)

Try one more time :slight_smile: You are close

Hmmm. I thought I had it. The data is stored, then the seperate function to send on enter. But it isnt...

<script>
    (function(scope) {    

    scope.$watch('inputChange', function(data) {
        console.log('inputChange: ',data)
    })

        scope.sendInput = function() {        
        scope.send({payload:data,topic:"input-changed"})
    }
    
    });

Ok. Here's the thing.

<script>
(function(scope) {

    //define a variable to hold and share the content of the input field
    //so it can be used in any function in scope
    let inputData = ''

    // function to be called on keyboard "Enter"
    scope.sendInput = function() {
        //if the data is empty string, dont send anything        
        if(inputData == ''){
            return
        }       
        //console.log('sending: ',data)
        // send last know inputData to the server
        scope.send({payload: inputData, topic: "input-changed"})        
    }

    scope.$watch('inputChange', function(data) {
        if (data) {
            //console.log('inputChange: ',data)
            // every time something is typed, store the data so it can be used whenever needed
            inputData = data; 
        }
    });
    // this can be deleted if you don't need to react on any input message.
    scope.$watch('msg', function(msg) {
        if (msg) {
        // Do something when msg arrives     
        }
    });
})(scope);
</script>

Ok that obviously works. I get it with the exception I am not sure why the scope.sendInput is before the scope.$watch. I am trying to understand that. For me it should be at the end, but still thinking...
And I am using all the //comments, as that will help in the future when I look at it. Very useful.

Move it to the end. The order of those is not important. They are defined functions (let's say static block of logic) which then do their job when called.

Ok I was just thinking that the order might not matter. Ok, then it all makes sense. I need to find some youtube videos on ui nodes, I think I have seen some out there. Far better for me than trying to understand the docs.
And I think its easier to manage than the input node as you pointed out earlier, especially if you want to customise which I want. Will play around now to adapt it to my use.

Very nice. :slight_smile:

Is the width of the input label adjustable ? I added this to the style template but didnt work

 .input-label{
        width: 100px
    }

Styles with comments

<style>
    /*the container class defined as additional class for ui_template*/
    .input-container{
        display: flex;
        gap: 1em;
        flex-direction: row;
        justify-content: space-between;
        align-items: center;
    }
    /* a paragraph which is direct child of the input-container*/
    .input-container > p {
        color:red !important;
        user-select:none;
    }
    /* an input element which is direct child of the input-container*/
    .input-container > input{
        background-color: transparent;
        border: unset;
        border-bottom: 1px solid #00a9ff;
        outline: unset;
        color: #e2ff00;
        text-align: end;
    }
    
</style>

As you see - the ui_template contains a paragraph and the input element
Those are direct children of the ui_template fro which you have added the class .input-container

<p>INPUT</p>
<input type="text" ng-model="inputChange" ng-keypress="$event.keyCode === 13 && sendInput()"></input>

So the label is that paragraph.