0

i have a Component "CDataTable" which renders Columns in a for loop. inside the loop there is a template:

<template v-if="typeof col.template !== 'undefined'" #body="{data}">
    <component :is="compile(col.template)" :data="data" :value="getColValue(data, col.field)" />
</template>

in the parent component "LocationList" i can define the column definitions in an array of objects in data():

columns: [
    {field: 'test', header: "test", width: 12, template: `<span v-if="typeof value !== 'undefined'">{{value}} <i class="pi pi-search" @click="console.log(this)"></i></span>`}
]

i managed to get the rendering working like shown above, but now i want to call a function of the Parentcomponent "LocationList" in the click handler, obviously i have no access to the methods of "LocationList" so i thought i can emit an Event and listen to it there, but if i put "this.$emit" in the click handler, it shows an error that i $emit is undefined.

Then i put a console.log(this) there to get a clue why. The reason is "this" is the window object.

the question is: how can i call a function of the "LocationList" Component in the click handler?

1 Answers1

0

Do not use this in Vue templates, especially not in inline event handlers.

If you take column template (<span v-if="typeof value !== 'undefined'">{{value}} <i class="pi pi-search" @click="console.log(this)"></i></span>) and put it in the online template compiler you will get something like this (doesnt matter it is Vue 2 compiler, it will look almost same in Vue 3):

function render() {
    with(this) {
        return (typeof value !== 'undefined') ? _c('span', [_v(_s(value)),
            _c('i', {
                staticClass: "pi pi-search",
                on: {
                    "click": function($event) {
                        return console.log(this)
                    }
                }
            })
        ]) : _e()
    }
}

The problem is that anonymous function used as a handler. If you don't understand why, read How to access the correct this inside a callback

Anyway, this is implicit in the templates thanks to with(this) so you can just use $emit() in the handler...

Note The way you are doing the column rendering is very strange. I do not know how your compile function works but I'm pretty sure it is unnecessary complicated. If you need to pass a template into a child component, you should use slots

tony19
  • 125,647
  • 18
  • 229
  • 307
Michal Levý
  • 33,064
  • 4
  • 68
  • 86
  • thank you for the quick answer, the compile function is just vues compile function (in Vue2 it was Vue.compile, now in Vue3 i have to import it). yeah i also thought this is strange but i have no idea how to do it different. how can i pass the template via string to the child component? – Markus Gauwatz Jul 26 '21 at 13:24
  • actually im just stupid... :( now i did the (i guess) correct way with slots, its way easier, but i didn't knew how it worked. – Markus Gauwatz Jul 26 '21 at 13:43