@click from vuex does not work on the vue component

Viewed 475

This is from my store.

getters: {
  getFormattedUsers (state) {
    state.users.forEach(v => {
      v.fullname = `${capitalize(v.fname)} ${capitalize(v.lname)}`
      v.created_from_now = moment(v.created_at).fromNow()
      v.approve_button = `<button @click="openApproveModal" class="btn btn-primary">Approve</button>`     
    })

    return state.users
  }
}

Now in my component (mounted property),

async mounted () {
  await this.initializeUsers()

  $('#dataTable').DataTable({
    data: this.getFormattedUsers(),
    columns: [
      {data: 'fullname'},
      {data: 'username'},
      {data: 'is_approved'},
      {data: 'created_from_now'},
      {data: 'approve_button'}
    ]
  })
}

Supposedly, when you click on the Approve Button

methods: {
  openApproveModal (id) {
    console.log('Approved!')
  }
}

But turns out, it logged nothing. The function was not called at all.

Moreover, this is what my component's table look like:

 <table class="table table-bordered" id="dataTable">
   <thead>
     <tr>
       <th>Name</th>
       <th>Username</th>
       <th>Status</th>
       <th>Registration Date</th>
       <th width="5">Action</th>
     </tr>
   </thead>
 </table>
1 Answers

Firstly, you shouldn't be modifying reactive state inside a getter. This can lead to infinite loops and in general is just a bad idea.

This is a red flag:

v.approve_button = `<button @click="openApproveModal" class="btn btn-primary">Approve</button>`

I suppose you're injecting that into the DOM with v-html? That won't work. v-html only works with HTML but what you have is a Vue template.

I don't know what the full template is so I can't suggest a solution, but you should always avoid v-html at all costs (not only for the XSS concerns, but it usually indicates you're doing something against the "Vue way").


Here's a simplified demo of what you're trying to do:

// Try to create a Vue button

function handleClick() {
  alert('You will not see this')
}

const app = document.querySelector('#app')
app.innerHTML = '<button @click="handleClick">Not Working</button>'

// Do it properly

const componentInstance = new Vue({
  template: '<button @click="handleClick">Working</button>',
  methods: {
    handleClick() {
      alert('Works!')
    }
  }
})

componentInstance.$mount()
app.appendChild(componentInstance.$el)
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app"></div>

Related