Iterate on a list and output the id

I've really tried hard to get an answer in the general vue community. It seems theres issues running @change within the FFDB2 implementation of vue.
I want to input a json containing n number of tasks.
I want to change a tasks status.
I want to out put that status with the tasks id.

The input json:

{
    "tasks": [
        {
            "id": 1,
            "name": "Task 1",
            "text": "Details about task 1",
            "status": "Not Started"
        },
        {
            "id": 2,
            "name": "Task 2",
            "text": "Details about task 2.",
            "status": "Testing"
        },
        {
            "id": 3,
            "name": "Task 3",
            "text": "Details about task 3.",
            "status": "Complete"
        }
    ]
}

The HTML. I am aware that the v-model applies across everything and not per iteration. I've tried task.status but that doesn't work.

<template>
  <v-app>
    <v-container>
      <div v-for="task in msg.payload" :key="task.id">
        <v-select
          :label="`${task.name}`"
          :items="['Not Started', 'Started', 'In Progress', 'Stuck', 'Testing', 'Complete']"
          v-model="taskStatus"
        ></v-select>
      </div>
    </v-container>
  </v-app>
</template>

The very crappy script that I'm trying to learn from..

<script>
export default {
  data() {
    return {
      taskStatus: [],
    };
  },
  watch: {
    taskStatus(newVal, oldVal) {
      if (newVal !== oldVal) {
        this.send({ status: newVal });
      }
    },
  },
}
</script>

This will output a status object but it changes all of the tasks v-select (of course being a simple v-model) and I don't know how to call the task id - which I assume is in the parent..

This seems to work for me

<template>
  <v-app>
    <v-container>
      <div v-for="task in msg.payload.tasks" :key="task.id">
        <v-select v-model="task.status" :label="task.name"
          :items="['Not Started', 'Started', 'In Progress', 'Stuck', 'Testing', 'Complete']"
          @update:model-value="send({ payload:{ id: task.id, status: task.status }})">
        </v-select>
      </div>
    </v-container>
  </v-app>
</template>

The send command can be used inline without the need of a script section

Test Flow :

[{"id":"fe1b74cba6ca339d","type":"inject","z":"54efb553244c241f","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"tasks\":[{\"id\":1,\"name\":\"Task 1\",\"text\":\"Details about task 1\",\"status\":\"Not Started\"},{\"id\":2,\"name\":\"Task 2\",\"text\":\"Details about task 2.\",\"status\":\"Testing\"},{\"id\":3,\"name\":\"Task 3\",\"text\":\"Details about task 3.\",\"status\":\"Complete\"}]}","payloadType":"json","x":190,"y":2980,"wires":[["f332963bc60e072d"]]},{"id":"f332963bc60e072d","type":"ui-template","z":"54efb553244c241f","group":"12caf9e6968092fd","page":"","ui":"","name":"","order":0,"width":0,"height":0,"head":"","format":"<template>\n  <v-app>\n    <v-container>\n      <div v-for=\"task in msg.payload.tasks\" :key=\"task.id\">\n        <v-select v-model=\"task.status\" :label=\"task.name\"\n          :items=\"['Not Started', 'Started', 'In Progress', 'Stuck', 'Testing', 'Complete']\"\n          @update:model-value=\"send({ payload:{ id: task.id, status: task.status }})\">\n        </v-select>\n      </div>\n    </v-container>\n  </v-app>\n</template>\n\n<!-- <script>\nexport default {\n  data() {\n    return {\n      taskStatus: [],\n    };\n  },\n  watch: {\n    taskStatus(newVal, oldVal) {\n      if (newVal !== oldVal) {\n        this.send({ status: newVal });\n      }\n    },\n  },\n}\n</script> -->","storeOutMessages":true,"passthru":false,"resendOnRefresh":true,"templateScope":"local","className":"","x":380,"y":2980,"wires":[["05b95dd9b1009de3"]]},{"id":"05b95dd9b1009de3","type":"debug","z":"54efb553244c241f","name":"debug 59","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":560,"y":2980,"wires":[]},{"id":"12caf9e6968092fd","type":"ui-group","name":"Group 1","page":"1a89c4c21097111f","width":"26","height":"8","order":-1,"showTitle":true,"className":""},{"id":"1a89c4c21097111f","type":"ui-page","name":"Page 1","ui":"d726187aa6c1921a","path":"/","layout":"grid","theme":"b5afc19a78309829","order":1,"className":""},{"id":"d726187aa6c1921a","type":"ui-base","name":"UI Name","path":"/dashboard"},{"id":"b5afc19a78309829","type":"ui-theme","name":"Theme Name","colors":{"surface":"#ffffff","primary":"#008000","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"}}]
1 Like

Can't thank you enough!

1 Like

I've noticed though that it sends the existing value and not the new selected value.
I'll look at it again in the morning with fresh eyes and brain.

It's not linked to our implementation of it, it's linked to Vuetify inconsistently implementing it in their widgets. @update:model-value is a far more reliable technique here to react to any changes.

The old value I think (although I'm surprised to see it) occurs because the input to the send is driven by the task.id, task.status, which a that time is the old value.

You can instead define a new function, and utilise the fact that the @update method should (not tested) be given the new value as input, so:

<v-select v-model="task.status" :label="task.name"
    :items="['Not Started', 'Started', 'In Progress', 'Stuck', 'Testing', 'Complete']"
    @update:model-value="onUpdate">
</v-select>

then have a method in your Vue component:

onUpdate: function (value) {
    this.send({ payload:{ id: value.id, status: value.status }})
}

I might be wrong there, but fairly sure that's a sure fire way of doing it

Thanks Joe, I mean no offence with the vue implementation.

It's really a simple CRUD op that i'm trying to achieve here.
A payload from a database api call in a HTTP Request node injects the payload when the list is loaded. When I update a v-select dropdown, I then send that back to the database.
In Node-Red this is very straight forward and easy to replicate. Because I'm not a front end dev it's difficult for me to understand in js/vue/html/css/.

The answer you gave puts out a payload but the array is empty.

Example flow:

[{"id":"da7c3035a6cd5d80","type":"tab","label":"Testing","disabled":false,"info":"","env":[]},{"id":"6abf6894425f5049","type":"inject","z":"da7c3035a6cd5d80","name":"Simulated API GET response","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"tasks\":[{\"id\":1,\"name\":\"Task 1\",\"text\":\"Details about task 1\",\"status\":\"Not Started\"},{\"id\":2,\"name\":\"Task 2\",\"text\":\"Details about task 2.\",\"status\":\"Testing\"},{\"id\":3,\"name\":\"Task 3\",\"text\":\"Details about task 3.\",\"status\":\"Complete\"}]}","payloadType":"json","x":200,"y":140,"wires":[["74ccef7d5332c492"]]},{"id":"74ccef7d5332c492","type":"ui-template","z":"da7c3035a6cd5d80","group":"","page":"69899b9aa555c7ec","ui":"","name":"","order":0,"width":0,"height":0,"head":"","format":"<template>\n    <div v-for=\"task in msg.payload.tasks\" :key=\"task.id\">\n        <v-card flat variant=\"flat\" class=\"ma-3\">\n            <v-card-title>{{ task.name }}</v-card-title>\n            <v-card-text> {{ task.text }}</v-card-text>\n            <v-card-actions>\n                <v-select \n                    v-model=\"task.status\"\n                    :items=\"['Not Started', 'Started', 'In Progress', 'Stuck', 'Testing', 'Complete']\"\n                    @update:model-value=\"onUpdate\"></v-select>\n            </v-card-actions>\n        </v-card>\n    </div>\n</template>\n\n<script>\n    export default {\n    methods: {\n      onUpdate: function (value) {\n        this.send({ payload: { id: value.id, status: value.status } })\n      },\n    },\n  }\n</script>","storeOutMessages":true,"passthru":false,"resendOnRefresh":true,"templateScope":"widget:page","className":"","x":400,"y":140,"wires":[["e487ccdd5f2aaf5f"]]},{"id":"e487ccdd5f2aaf5f","type":"debug","z":"da7c3035a6cd5d80","name":"debug 4","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":540,"y":140,"wires":[]},{"id":"69899b9aa555c7ec","type":"ui-page","name":"Projects","ui":"22e2f5c865718f73","path":"/page1","icon":"home","layout":"grid","theme":"c7c753dd7138d5cc","order":-1,"className":"","visible":"true","disabled":"false"},{"id":"22e2f5c865718f73","type":"ui-base","name":"Kimchi","path":"/dashboard","includeClientData":true,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false},{"id":"c7c753dd7138d5cc","type":"ui-theme","name":"Kimchi Theme","colors":{"surface":"#ffffff","primary":"#077dab","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"pagePadding":"2px","groupGap":"0px","groupBorderRadius":"0px","widgetGap":"0px"}}]

@UnborN was correct. That solution is working.
Where I had it wrong was calling:
v-for="task in msg.payload"
Instead of:
v-for="task in msg.payload.tasks"

Flow sample:

[{"id":"da7c3035a6cd5d80","type":"tab","label":"Testing","disabled":false,"info":"","env":[]},{"id":"6abf6894425f5049","type":"inject","z":"da7c3035a6cd5d80","name":"Simulated API GET response","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"{\"tasks\":[{\"id\":1,\"name\":\"Task 1\",\"text\":\"Details about task 1\",\"status\":\"Not Started\"},{\"id\":2,\"name\":\"Task 2\",\"text\":\"Details about task 2.\",\"status\":\"Testing\"},{\"id\":3,\"name\":\"Task 3\",\"text\":\"Details about task 3.\",\"status\":\"Complete\"}]}","payloadType":"json","x":200,"y":140,"wires":[["74ccef7d5332c492"]]},{"id":"74ccef7d5332c492","type":"ui-template","z":"da7c3035a6cd5d80","group":"","page":"69899b9aa555c7ec","ui":"","name":"","order":0,"width":0,"height":0,"head":"","format":"<template>\n    <div v-for=\"task in msg.payload.tasks\" :key=\"task.id\">\n        <v-card flat variant=\"flat\" class=\"ma-3\">\n            <v-card-title>{{ task.name }}</v-card-title>\n            <v-card-text> {{ task.text }}</v-card-text>\n            <v-card-actions>\n                <v-select \n                    v-model=\"task.status\"\n                    :items=\"['Not Started', 'Started', 'In Progress', 'Stuck', 'Testing', 'Complete']\"\n                    @update:model-value=\"send({ payload:{ id: task.id, status: task.status }})\"></v-select>\n            </v-card-actions>\n        </v-card>\n    </div>\n</template>\n\n<script>\n    export default {\n  }\n</script>","storeOutMessages":true,"passthru":false,"resendOnRefresh":true,"templateScope":"widget:page","className":"","x":400,"y":140,"wires":[["e487ccdd5f2aaf5f"]]},{"id":"e487ccdd5f2aaf5f","type":"debug","z":"da7c3035a6cd5d80","name":"debug 4","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":540,"y":140,"wires":[]},{"id":"69899b9aa555c7ec","type":"ui-page","name":"Projects","ui":"22e2f5c865718f73","path":"/page1","icon":"home","layout":"grid","theme":"c7c753dd7138d5cc","order":-1,"className":"","visible":"true","disabled":"false"},{"id":"22e2f5c865718f73","type":"ui-base","name":"Kimchi","path":"/dashboard","includeClientData":true,"acceptsClientConfig":["ui-notification","ui-control"],"showPathInSidebar":false},{"id":"c7c753dd7138d5cc","type":"ui-theme","name":"Kimchi Theme","colors":{"surface":"#ffffff","primary":"#077dab","bgPage":"#eeeeee","groupBg":"#ffffff","groupOutline":"#cccccc"},"sizes":{"pagePadding":"2px","groupGap":"0px","groupBorderRadius":"0px","widgetGap":"0px"}}]
2 Likes

Just to check, that's working with the @update:model-value too?

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