Skip to content
Advertisement

Property or method “_” is not defined on the instance but referenced during render

Im a capable react developer, but have inherited a vue.js project from another developer and have maintained it for several years now, unfortunately I haven’t gone through much personal effort to learn vue as i should.

I have a strange error being thrown from using lodash, I believe it doesnt like my _.debounce call

Component:
<script>
import _ from 'lodash'
import CostCodeField from '@/components/workdays/CostCodeField'

// ...
</script>

<template lang='html'>
  <!-- relevant code snippet -->
  <!-- ... -->
  <b-table class="charges-table is-fullwidth" :data="workday.charges" :striped="true" :mobile-cards="false" :row-class="chargeClass">
    <b-table-column label="Cost Code" width="260">
        <b-field expanded="expanded">
          <cost-code-field
            :value="props.row.cost_code.number" :disabled="timecard.is_submitted || locked || isLoading(props)"
            :job="props.row.job"
            @input="set($event, props.index, 'cost_code')"
            @change="_.debounce(submit(props.row, props.index), 100)"
          ></cost-code-field>
          <p class="control">
            <a
              class="button"
              @click="triggerCostCode(props.row, props.index)" :disabled="props.row.job.jd_job_number_id === undefined || timecard.is_submitted || isLoading(props)"
            >
              <b-icon icon="magnify"></b-icon>
            </a>
          </p>
        </b-field>
      </b-table-column>
      <!-- ... -->
  </b-table>
</template>
console.error
[Vue warn]: Property or method "_" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.

found in

---> <ChargesTable> at src/components/workdays/ChargesTable.vue
       <BTabItem>
         <BTabs>
           <WorkdayListItem> at src/components/workdays/WorkdayListItem.vue
             <Timecard> at src/components/timecards/Timecard.vue
               <App> at src/App.vue
                 <Root> vue.esm.js:628
    VueJS 3
    change ChargesTable.vue:127
    VueJS 4
    setCode CostCodeField.vue:108
    VueJS 12
    mutations timecards.js:322
    mutations timecards.js:319
    wrappedMutationHandler vuex.esm.js:844
    commitIterator vuex.esm.js:466
    commit vuex.esm.js:465
    _withCommit vuex.esm.js:624
    commit vuex.esm.js:464
    boundCommit vuex.esm.js:409
    submit CostCodeLookup.vue:134
    submit CostCodeLookup.vue:16
    VueJS 33
[Vue warn]: Error in v-on handler: "TypeError: _vm._ is undefined"

found in

---> <CostCodeField> at src/components/workdays/CostCodeField.vue
       <BField>
         <BTableColumn>
           <BTable>
             <ChargesTable> at src/components/workdays/ChargesTable.vue
               <BTabItem>
                 <BTabs>
                   <WorkdayListItem> at src/components/workdays/WorkdayListItem.vue
                     <Timecard> at src/components/timecards/Timecard.vue
                       <App> at src/App.vue
                         <Root> vue.esm.js:628
TypeError: _vm._ is undefined
    change ChargesTable.vue:127
    VueJS 4
    setCode CostCodeField.vue:108
    VueJS 12
    mutations timecards.js:322
    mutations timecards.js:319
    wrappedMutationHandler vuex.esm.js:844
    commitIterator vuex.esm.js:466
    commit vuex.esm.js:465
    _withCommit vuex.esm.js:624
    commit vuex.esm.js:464
    boundCommit vuex.esm.js:409
    submit CostCodeLookup.vue:134
    submit CostCodeLookup.vue:16
    VueJS 33

Advertisement

Answer

Accessing _ in template

Assuming you’re using the Options API, importing _ does not automatically make it available to the template (as @tao pointed out in his answer). The template can only access fields exposed via the component options (e.g., data, props, methods, computed, etc.) in addition to a few allow-listed globals (Vue 2 allowed globals, Vue 3 allowed globals).

Using _.debounce

_.debounce‘s first argument is a function reference:

_.debounce(submit(props.row, props.index), 100) // ❌ calls `submit()`, and passes the result to _.debounce()

To create a debounced submit, pass the submit-reference as an argument to _.debounce like this:

_.debounce(submit, 100)

You technically could invoke the debounced function immediately:

_.debounce(submit, 100)(props.row, props.index)

…but don’t do that in the template (see reason below).

Using a debounced event handler for v-on

When the value of the v-on directive (@ for shorthand) is an expression (as in your case), the template compiler automatically wraps the expression in a function, so this:

@change="_.debounce(submit, 100)"

…essentially becomes:

@change="($event) => _.debounce(submit, 100)"

…which would have no effect, since debounce doesn’t invoke the wrapped function itself.

You might be tempted to call the function immmediately in:

@change="_.debounce(submit, 100)(props.row, props.index)"

…but that creates a new debounced function on every event, which defeats the debouncing.

Solution

Create a debounced function in the <script> part of the SFC that could then be used as the v-on value:

Options API:

<script>
import { debounce } from 'lodash'

export default {
  created() {
    this.debouncedSubmit = debounce(this.submit, 100)
  },
  methods: {
    submit(row, index) {/*...*/}
  }
}
</script>

Composition API in setup() option:

<script>
import { debounce } from 'lodash'

export default {
  setup() {
    const submit = (row, index) => {/*...*/}

    return {
      debouncedSubmit: debounce(submit, 100),
    }
  }
}
</script>

Composition API in <script setup>:

<script setup>
import { debounce } from 'lodash'

const submit = (row, index) => {/*...*/}
const debouncedSubmit = debounce(submit, 100)
</script>

Template:

<cost-code-field @change="debouncedSubmit(props.row, props.index)" />

demo

8 People found this is helpful
Advertisement