# Keep updating ui-template

**URL:** <https://discourse.nodered.org/t/keep-updating-ui-template/100642>\
**Category:** Dashboard\
**Tags:** dashboard-2\
**Created:** [24 March 2026 22:44 UTC](https://discourse.nodered.org/t/keep-updating-ui-template/100642 "2026-03-24T22:44:56Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![nygma2004](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/nygma2004/32/1308_2.png) [@nygma2004](https://discourse.nodered.org/u/nygma2004)\
**Post date:** [24 March 2026 22:44 UTC](https://discourse.nodered.org/t/keep-updating-ui-template/100642/1 "2026-03-24T22:44:56Z")

</div>

I have a process that takes some time to complete and I wanted to add a Vue Timeline to show which steps are being executed. So the idea was that in the process (long chain of various nodes), at certain steps I branch out to the below ui-template node. So the same message is sent to this UI template, with different content, some properies are getting added as more steps are executed in the process.

The ui-template looks like this:

```auto
<template>
    <v-timeline side="end">
        <v-timeline-item :dot-color="voice_color" size="small">
            <div class="d-flex">
                <strong class="me-4">{{voice_amount}}</strong>
                <div>
                    <strong>Audio recording</strong>
                    <div class="text-body-small">
                        {{voice_text}}
                    </div>
                </div>
            </div>
        </v-timeline-item>

        <v-timeline-item :dot-color="whisper_color" size="small">
            <div class="d-flex">
                <strong class="me-4">{{whisper_amount}}</strong>
                <div>
                    <strong>Transcribe Audio</strong>
                    <div class="text-body-small">
                        {{whisper_text}}
                    </div>
                </div>
            </div>
        </v-timeline-item>

        <v-timeline-item :dot-color="llm_color" size="small">
            <div class="d-flex">
                <strong class="me-4">{{llm_amount}}</strong>
                <div>
                    <strong>Recognize Intent</strong>
                    <div class="text-body-small">
                        {{llm_text}}
                    </div>
                </div>
            </div>
        </v-timeline-item>

    </v-timeline>
</template>

<script>
    export default {
        data() {
            // define variables available component-wide
            // (in <template> and component functions)
            return {
                voice_color: 'grey',
                voice_text: 'No Audio',
                voice_amount: '',
                whisper_color: 'grey',
                whisper_text: 'Not completed yet',
                whisper_amount: '',
                llm_color: 'grey',
                llm_text: 'Not triggered yet',
                llm_amount: '',
            }
        },
        watch: {
            // watch for any changes of "count"

            msg: function(){
                    this.resetDefaults();

                    if (this.msg.rec_start) {
                        this.voice_color = 'red';
                        this.voice_amount = '';
                        this.voice_text = 'Recording...';
                    } 
                    if (this.msg.fname !== undefined) {
                        this.voice_color = 'green';
                        this.voice_amount = 'Saved';
                        this.voice_text = this.msg.fname;
                        this.whisper_color = 'yellow';
                    } 
                    if (this.msg.transcribedtext !== undefined) {
                        this.whisper_color = 'green';
                        this.whisper_amount = this.msg.whisperseconds + "ms";
                        this.whisper_text = this.msg.transcribedtext;
                        this.llm_color = 'yellow';
                    } 
                    if (this.msg.llmoutputstep) {
                        if (!this.msg.payload.done) { 
                            this.llm_color = 'red';
                            this.llm_amount = this.msg.llmseconds + "ms";
                            this.llm_text = "Error";
                        } else {
                            this.llm_color = 'green';
                            this.llm_amount = this.msg.llmseconds + "ms";
                            this.llm_text = this.msg.payload.message.content;
                        }
                    }
                
            }
        },
        computed: {

        },
        methods: {
            // expose a method to our <template> and Vue Application
            resetDefaults() {
                this.voice_color = 'grey';
                this.voice_text = 'No Audio';
                this.voice_amount = '';
                this.whisper_color = 'grey';
                this.whisper_text = 'Not completed yet';
                this.whisper_amount = '';
                this.llm_color = 'grey';
                this.llm_text = 'Not triggered yet';
                this.llm_amount = '';
            }
        },
        mounted() {
            // code here when the component is first loaded
        },
        unmounted() {
            // code here when the component is removed from the Dashboard
            // i.e. when the user navigates away from the page
        }
    }
</script>

```

It sort of works and sort of not:

- when I restart the process, I would expect step 2 and 3 to be grey because the default values, but they seem to show the values from the previous message. Although the new message clearly does not have the properties in the if statements.
- if I send an empty payload, it does not reset the UI to the grey states that I expect.

I have not done much Node-Red work in the past few months, but I am sure I have not forgotten that much, and the basic if logic is correct. If certain attributes do not exists the UI should fall back to the default color/text.

I asked Gemini about this, he said that insteal of `this.msg....` I should change the watch to a `handler: function(val) {` and `deep: true`, but that seem to make no difference at all.

I am looking at this for a few hours now and just can't figure out what I have done wrong.

P.S. ignore some of the comments on the code, it is from an earlier template node.

---

<div class="post-metadata">

**Author:** ![Buckskin](https://avatars.discourse-cdn.com/v4/letter/b/b9e5f3/32.png) [@Buckskin](https://discourse.nodered.org/u/Buckskin)\
**Post date:** [25 March 2026 15:56 UTC](https://discourse.nodered.org/t/keep-updating-ui-template/100642/2 "2026-03-25T15:56:22Z")

</div>

Try putting the msg detection in mounted instead. this.msg seems to retain all previous messages

```H
        watch: {

        },

        mounted() {
            // code here when the component is first loaded
            this.$socket.on('msg-input:' + this.id, (msg) => {
                // do stuff with msg
                // runs only when messages are received
                    this.resetDefaults()
                    
                    this.send({payload: msg.fname === undefined})

                    if (msg.rec_start) {
                        this.voice_color = 'red';
                        this.voice_amount = '';
                        this.voice_text = 'Recording...';
                    } 
                    if (msg.fname !== undefined) {
                        this.voice_color = 'green';
                        this.voice_amount = 'Saved';
                        this.voice_text = msg.fname;
                        this.whisper_color = 'yellow';
                    } 
                    if (msg.transcribedtext !== undefined) {
                        this.whisper_color = 'green';
                        this.whisper_amount = msg.whisperseconds + "ms";
                        this.whisper_text = msg.transcribedtext;
                        this.llm_color = 'yellow';
                    } 
                    if (msg.llmoutputstep) {
                        if (!this.msg.payload.done) { 
                            this.llm_color = 'red';
                            this.llm_amount = msg.llmseconds + "ms";
                            this.llm_text = "Error";
                        } else {
                            this.llm_color = 'green';
                            this.llm_amount = msg.llmseconds + "ms";
                            this.llm_text = msg.payload.message.content;
                        }
                    }

            })
        },

```

---

<div class="post-metadata">

**Author:** ![nygma2004](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/nygma2004/32/1308_2.png) [@nygma2004](https://discourse.nodered.org/u/nygma2004)\
**Post date:** [25 March 2026 20:27 UTC](https://discourse.nodered.org/t/keep-updating-ui-template/100642/3 "2026-03-25T20:27:06Z")

</div>

I tried, but with that change the UI does not render at all: `SyntaxError: Unexpected keyword 'this' (21:12) (at index-B1862Wtn.js:92:9306)`. I can't figure out what is causing it.

---

<div class="post-metadata">

**Author:** ![Buckskin](https://avatars.discourse-cdn.com/v4/letter/b/b9e5f3/32.png) [@Buckskin](https://discourse.nodered.org/u/Buckskin)\
**Post date:** [25 March 2026 20:58 UTC](https://discourse.nodered.org/t/keep-updating-ui-template/100642/4 "2026-03-25T20:58:39Z")

</div>

Apologies, I missed a `this.msg`

```auto
                     if (msg.llmoutputstep) {
                        if (!this.msg.payload.done)

```

should be

```auto
                    if (msg.llmoutputstep) {
                        if (!msg.payload.done) { 
                            this.llm_color = 'red';
                            this.llm_amount = msg.llmseconds + "ms";
                            this.llm_text = "Error";
                        } else {
                            this.llm_color = 'green';
                            this.llm_amount = msg.llmseconds + "ms";
                            this.llm_text = msg.payload.message.content;
                        }

```

---

<div class="post-metadata">

**Author:** ![nygma2004](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/nygma2004/32/1308_2.png) [@nygma2004](https://discourse.nodered.org/u/nygma2004)\
**Post date:** [25 March 2026 21:20 UTC](https://discourse.nodered.org/t/keep-updating-ui-template/100642/5 "2026-03-25T21:20:23Z")

</div>

Thanks, it works perfectly now.

I still don't fully understand why I had to used the mounted method this time, and was OK to use the watch method every other case I was using the ui-template node in the past.

Maybe I should have null-ed the msg object at the end of the watch function?

---

<div class="post-metadata">

**Author:** ![Buckskin](https://avatars.discourse-cdn.com/v4/letter/b/b9e5f3/32.png) [@Buckskin](https://discourse.nodered.org/u/Buckskin)\
**Post date:** [25 March 2026 22:11 UTC](https://discourse.nodered.org/t/keep-updating-ui-template/100642/6 "2026-03-25T22:11:15Z")

</div>

I tried that and it didn't make any difference.

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [8 April 2026 22:12 UTC](https://discourse.nodered.org/t/keep-updating-ui-template/100642/7 "2026-04-08T22:12:09Z")

</div>

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