Creating Dynamic To-Do List?

I am working on something similar to a To-Do list. In all aspects, it is exactly the same function. Except for one thing. A user is not physically adding new tasks with an input box and an Add button. Likewise, the user is not physically checking off the completed tasks.

Instead, the user is using a barcode scanner to scan a code. With the help of Node-Red, the scanned code is then used to fetch a To-Do list from a Sql Database, then the tasks are displayed on node-red-dashboard.
The user is now tasked to go complete each of the listed tasks in the generated To-Do list. In order to complete a task, the user must scan a barcode associated with a task. Each time a task is completed it should be visually checked off in the to-do list until all tasks are completed. Once all tasks are completed, the To-List is cleared and now the application is waiting for the user to scan a code to load a new To-List.

I have got this application working up to being able to check off individual tasks.
The hump I am not able to get over is checking off more than one individual task. I am able to check off one task, however, when the next task is scanned, the previous completed task becomes unchecked and the recent completed task is checked.
I understand why this method does not work, the function is overwriting the previous checked item with the most recent checked item. Is there some other way to accomplish this? I want to think that I could call a function in the ui template to accept a index then add a css style to a particular row.

var html = ""
var obj = flow.get('list')

for (var i = 0; i < obj.length; i++) {
    
    //if scanned code equals current item in index, construct html to turn item green
    if(msg.payload === obj[i].Value) {
            
            html += "<tr style=\"background:green\">"+
                    "<td style=\"text-align: left; vertical-align: middle;\">"+obj[i].Type+"</td>"+
                    "<td style=\"text-align: center; vertical-align: middle;\">"+obj[i].Value+"</td>"+
                    "</tr>"
                
            obj[i].Checked = "Yes"
            continue
    }
    
    //if scanned code does not match current item in index, contruct html to keep item red
    html += "<tr style=\"background:red\">"+
            "<td style=\"text-align: left; vertical-align: middle;\">"+obj[i].Type+"</td>"+
            "<td style=\"text-align: center; vertical-align: middle;\">"+obj[i].Value+"</td>"+
            "</tr>"
}

flow.set('list',obj)
msg.html = html
return msg;

Template HTML:

<div>
    <table class="componentTable">
      <thead>
        <tr>
          <th>Type</th>
          <th>Part Number</th>
        </tr>
      </thead>
        <tbody ng-bind-html="msg.html | trusted">
    </tbody>
    </table>
  </div>

So there are ways to cause a ui_template node to react to a msg being sent to it.
From there you can do some jQuery to change colors of elements.

If I had looked at the info tab with the ui_template node highlighted, I would have seen this little jewel.

<script>
(function(scope) {
  scope.$watch('msg', function(msg) {

    for (var i = 0; i < msg.payload.length; i++) {
  
    //if scanned code equals current item in index, turn item green
    if(msg.scan === msg.payload[i].Value) {
            $("#part"+i).css({"background-color": "green"})
                
            continue
    }
    
    }
      
});
})(scope);
</script>
1 Like

The one issue with this is that if you are watching for changes on the msg object, and you want to send a msg back to Node-Red from the ui_template, you will actually receive two duplicate msg objects.
This is because the function is watching for changes to the msg object and by calling to send a msg back to Node-Red, you are essentially changing the msg object again which fires the event off again.

In some cases this will cause an infinite loop of msgs being sent to Node-Red.

<script>
(function(scope) {
  scope.$watch('msg', function(msg) {
    
    var table = $("table")[0]
    var obj = msg
    for (var i = 0; i < msg.payload.length; i++) {
    //if scanned code equals current item in index, turn item green
    if(msg.scan === msg.payload[i].Value) {
            $("#part"+i).css({"background-color": "green"})
            var cell = table.rows[i+1].cells[2]
            $(cell).html('<i class="fa fa-check-square-o" aria-hidden="true"></i>')
            scope.send({payload:obj.payload,scan:obj.scan,html:obj.html,audio:"valid"})
            break;
            
    }
    }
    
});
})(scope);
</script>

This sounds like something in which I am interested.

Alas I am not as up to speed with the lingo' to understand and make a working flow from what is here.

Could you please post a working flow?

See if this helps you.
I was not able to test to see if it works because I don't have an application that is not in production right now.

[{"id":"4dad43a1.71c8ec","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"afa7b941.abe598","type":"inject","z":"4dad43a1.71c8ec","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":650,"y":490,"wires":[["e7bd7418.6c4688"]]},{"id":"e7bd7418.6c4688","type":"change","z":"4dad43a1.71c8ec","name":"Set Color Of Text","rules":[{"t":"set","p":"textColor","pt":"msg","to":"green","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":860,"y":490,"wires":[["9188d0c2.a2c28"]]},{"id":"9188d0c2.a2c28","type":"ui_template","z":"4dad43a1.71c8ec","group":"19e219f2.53bcd6","name":"","order":0,"width":0,"height":0,"format":"<style>\n \n .myDiv {\n \n background-color: red;\n color: white;\n width: 100%\n height: 300px;\n text-align:center;\n \n \n }\n \n</style>\n\n\n<div class=\"myDiv\">\n Testing The Script\n</div>\n\n<script>\n(function(scope) {\n scope.$watch('msg', function(msg) {\n\n if(msg.textColor === \"green\"){\n \n $(\"myDiv\").css({\"color\":\"green\"})\n \n }\n else if(msg.textColor === \"white\"){\n $(\"myDiv\").css({\"color\":\"white\"})\n }\n \n }\n }\n \n});\n})(scope);\n</script>","storeOutMessages":true,"fwdInMessages":true,"templateScope":"local","x":1090,"y":490,"wires":[[]]},{"id":"19e219f2.53bcd6","type":"ui_group","z":"","name":"Status","tab":"2eadfffe.f75d2","disp":false,"width":"8","collapse":false},{"id":"2eadfffe.f75d2","type":"ui_tab","z":"","name":"Main","icon":"dashboard","order":2}]

Thanks.

Not wanting to sound dumb - but I'm good at doing that - I loaded the flow and it puts a "Testing the script" message on the GUI side of things.

The INJECT node..... Ok. Then there is the "Set colour of text" node. Ok.

So I change the INJECT to inject "This is a test", deploy and press the inject.

Look at the GUI...... Not seeing it. (Nothing has changed from the initial look)

Sorry.

Sorry I should have explained more.
This should set the text color of the text in the ui. You can change the color by specifying it in the Set Text Color node.

The way the script is wrote it will only look for either green or white.

You shouldn’t have to set anything in the inject node.

Ok, but even that isn't working.

As given the flow opens a window and I get a box with "Testing the Script" in it with a RED background and white text.

I press the INJECT node and go back to the GUI.

Still red background and white text.