Home > Software design >  Checking if a value or multiple values inside an array of objects have changed and then rerun a meth
Checking if a value or multiple values inside an array of objects have changed and then rerun a meth

Time:08-24

EDIT: I've updated my watcher and recall the function to update the percentage live, but it's still not verbose enough to check and update all changed objs.

 watch: {
    tableData(newVal, oldVal) {
      const changedObjIndex = this.tableData.findIndex((obj) => {
        return obj.status === "In Progress"
      })
      console.log(`changed obj`, changedObjIndex)
      this.handleDisplayStatus(changedObjIndex)
      console.log(
        `obj that changed`,
        this.tableData[changedObjIndex].completion_progress
      )
    },
  },

Problem

I have a table that shows the details and progress of a video(s) upload. The progress bar is where I am having trouble updating it live (more on this below).

I have a blank tableData array in my data that is filled when the component is rendered with a handleDisplayStatus function. This method only runs once obviously, so I was planning on putting a watcher on the tableData array and then rerunning the handleDisplayStatus function if there is a change. I initially went with:

this.tableData.every((item) =>
        console.log(
          `completion progress from watcher`,
          item.completion_progress
        )
      )

However .every only returns a boolean and while it would rerun the handleDisplayStatus function, that function takes an index, _row so that doesn't seem to be the fix.

Also putting this.handleDisplayStatus(index, _row) in the watcher will give this error in the console Error in callback for watcher "tableData": "ReferenceError: index is not defined". Which makes sense because that function needs the indexes (_row param is not being used I think).

From there I went with .findIndex, but again that just gives me the first element that satisfies the condition. Since the table can have multiple videos loading at the same time, this is not the correct fix either.

 tableData(newVal, oldVal) {
      const changedObjIndex = this.tableData.findIndex((obj) => {
        return obj.status === "In Progress"
      })
      console.log(changedObjIndex)
    }

As I mentioned, everything works fine, but I need a page refresh to show the updated number. We are purposely not using socket.io for this; even though I think it's probably a good idea.

Any ideas of how I can get this function to call properly and get the percentages to update in real time? Even the old :key to force a rerender doesn't want to work here.

Any help or guidance would be greatly appreciated!

NOTE:

my progress bar just takes in a percentage prop as a number to render and is pretty straightforward. If you need to see that code as well I can edit this post!

tableData Array of Objs with key/values (NOTE: the task_status should be: "IN PROGRESS", but I couldn't edit that on the mySQL workbench)

enter image description here

Method that needs to be recalled

handleDisplayStatus(index, _row) {
      if (this.tableData[index].task_status == "IN PROGRESS") {
        let trainingProcessId = this.tableData[index].training_process_id
        this.tableData[index].intervalId = setInterval(() => {
          if (
            this.tableData[index].completion_progress != 100 &&
            this.tableData[index].task_status == "IN PROGRESS"
          ) {
            getTrainingProcessInfo({
              trainingProcessId: trainingProcessId,
            }).then((res) => {
              let jsonObj = JSON.parse(JSON.stringify(res.data))
              this.tableData[index].completion_progress =
                jsonObj.completion_progress
            })
          } else {
            clearInterval(this.tableData[index].intervalId)
          }
        }, 6000)
      }
      return this.tableData[index].task_status
    }

template (fwiw)

<template>
  <div>
    <el-card >
      <div style="margin-left: 5px" >
        <el-table
          ref="multipleTable"
          v-loading="listLoading"
          :data="tableData"
          id="el-table"
        >
          <el-table-column
            :label="$t('training_monitor_content.table_column_5')"
            align="center"
          >
            <template slot-scope="scope">
              <ProgressBar
                :key="scope.row.user"
                style="width: 100%; height: 20px; flex-shrink: 0"
                :percentage="scope.row.completion_progress"
              />
            </template>
          </el-table-column>
        </el-table>
      </div>
    </el-card>
  </div>
</template>

CodePudding user response:

If I understood you correctly try with deep watch:

watch: {
  tableData: {
    handler(newValue) {
      newValue.forEach((obj, idx) => {
        if (obj.status ===  'In Progress') this.handleDisplayStatus(idx)
      });
    },
    deep: true
  }
}
  • Related