Home > OS >  Dynamically add buttons and add onclick function to it
Dynamically add buttons and add onclick function to it

Time:12-17

I'm trying to create a table and for each row add a button, which will then call a custom function. However, whatever I have tried has not worked and the only function I am able to call is alert(). I am doing this in Vuejs and using java script functions. Here is my code:

<template>
    <div >
        <component :is="checkJWT()"/>
        <h3>{{organization_name}}</h3>

        <div> 
            <table id="workflowTable" style="width:100%"> <!-- the id can also be named organizationCaseTable -->
                <tr>
                    <th>ID</th>
                    <th>Title</th>
                </tr>
            </table>
        </div>
    </div>
</template>

<script>
import jwt_decode from "jwt-decode";
    export default{
        data () {
            return {
                organization_name: ""
            }
        },

        methods: {
            checkJWT: function(){
                var access_token = document.cookie.split("=")[1];
                var decoded = jwt_decode(access_token)
                this.organization_name = decoded.azp

                this.getCaseInformation(this.organization_name)
            }, 

            getCaseInformation: async function(){
                fetch('http://localhost:3000/workflow-page/'   this.organization_name, {
                    method: "GET",
                    headers: {
                        "Access-Control-Allow-Origin": "*",
                        "Access-Control-Allow-Methods": "DELETE, POST, GET, OPTIONS",
                        "Access-Control-Allow-Headers": "Content-Type, Authorization, X-Requested-With",
                        "Content-Type": "text/plain",
                        "Authorization": "Bearer "   document.cookie["access_token"]
                    }
                })
                .then(response => response.json())
                .then(result => result.forEach(rec => {
                    var rowCol = "<tr><td style='border: 1px solid;text-align:center'>"   rec.id   
                        "</td><td style='border: 1px solid;text-align:center'>"   rec.title   "</td>"   
                        "<td><button id='viewWorkflow"   String(rec.id)   "' v-on:click='myFunction()'>View</button></td></tr>"
                    document.getElementById('workflowTable').innerHTML  = rowCol
                }))
            }, 

            myFunction(){
                console.log("HERE")
            }
        }
    }
</script>

The attribute is being set when I inspect the button element, but when I click it, nothing happens. I also realized that .innerHTML adds it as plain text so I tried the following:

After the line document.getElementById('workflowTable').innerHTML = rowCol I called a function called this.makeClickable(rec.id) and that function looks like this:

 makeClickable(id){
                document.getElementById('viewWorkflow'   String(id)).setAttribute('onclick', 'myFunction');
            },

Even with this I am not able to call a custom function and I don't know why or how to fix/get around it.

CodePudding user response:

Avoid mutating the DOM directly. It's something that is rarely, if ever a good idea. This goes for all frontend frameworks; they all work on the same principle of the DOM being a function of data. I assume you are looking to do some thing like this...

<script>
export default{
  data () {
    return {
      organization_name: "",
      apiResponseData: null
    }
  },
  methods: {
    getCaseInformation(){
      fetch(myUrl)
        .then(d => d.json())
        .then(data => this.apiResponseData = data)
    },
    myFunction(record){
      console.log("selected", record)
    }
  }
}
</script>
<template>
  <div >
    <h3>{{organization_name}}</h3>

    <div>
      <span v-if="!apiResponseData">LOADING</span>
      <table v-if="apiResponseData" id="workflowTable" style="width: 100%">
        <thead>
          <tr>
            <th>ID</th>
            <th>Title</th>
          </tr>
        </thead>
        <tbody>
          <tr v-for="rec in apiResponseData" :key="rec.id">
            <td style="border: 1px solid; text-align: center">{{rec.id}}</td>
            <td style="border: 1px solid; text-align: center">{{rec.title}}</td>
            <td>
              <button @click="myFunction(rec)">View</button>
            </td>
          </tr>
        </tbody>
      </table>
    </div>
  </div>
</template>

I removed a bunch of stuff there to keep it simple, but here are some things to note.

  • apiResponseData will be null until the data loads, so you need to use v-if="apiResponseData" to only render the table or the table rows when that value is set. You can use this also to show a loading indicator
  • v-for directive is used to loop over the data, it should also use a key. (not mandatory, but important in many cases) docs
  • the :key is defined with a colon before it, this marks the content for parsing, otherwise it is treated as a string value
  • you can pass the record to your function in the button myFunction(rec).

Also, you don't need to define the function as async since you are treating it as a promise (using then)

  • Related