简体   繁体   中英

Vue.js 2.x Passing function to component

I need to render the same component several times with different information and when someone selects something it should load a function in the main Vue instance.

Until now I wasn't able to pass a dynamic function as a property like @change="onchange" :

[Vue warn]: Invalid handler for event "change": got undefined

found in

---> at resources\\assets\\js\\components\\GeographyField.vue

The component:

<template>
    <fieldset class="form-group col-md">
        <label :for="name" class="control-label" v-html="label"></label>
        <select class="form-control" :name="name" :id="name" :model="_default" :disabled="disabled" @change="onchange">
            <option :value="0" v-html="placeholder"></option>
            <option v-for="object in collection" :value="object.id">{{ object.name }}</option>
        </select>
    </fieldset>
</template>

<script>
    module.exports = {
        props: {
            label: {
                type: String,
                default: 'Options'
            },
            _default: {
                type: Number,
                default: 0
            },
            disabled: {
                type: Boolean,
                default: false
            },
            placeholder: {
                type: String,
                default: 'Choose an option'
            },
            name: {
                type: String,
                required: true,
            },
            collection: {
                type: Array,
                required: true
            },
            onchange: {

            }
        },
        data: function() {
            return {

            }
        },
        methods: {

        }
    }
</script>


The rendering:

<div class="row">
    <!-- Country -->
    <geography-field
            label="Pa&iacute;s"
            :_default="selectedCountry"
            placeholder="Choose a country"
            name="country"
            :collection="countries"
            :onchange="selectCountry()"
    ></geography-field>
    <!-- Department -->
    <geography-field
            label="Departamento"
            :_default="selectedDepartment"
            :disabled="selectedCountry < 1"
            placeholder="Choose a department"
            name="department"
            :collection="departments"
            :onchange="selectDepartment()"
    ></geography-field>
    <!-- Location -->
    <geography-field
            label="Localidades"
            :_default="selectedLocation"
            :disabled="selectedDepartment < 1"
            placeholder="Choose a location"
            name="location"
            :collection="localities"
            :onchange="selectLocation()"
    ></geography-field>
    <!-- Zone -->
    <geography-field
            label="Zonas"
            :_default="selectedZone"
            :disabled="selectedLocation < 1"
            placeholder="Choose a zone"
            name="zone"
            :collection="zones"
    ></geography-field>
</div>

Edit: Including selectCountry() :

selectCountry: function() {
        if(this.selectedCountry < 1) { return; }
        axios.get('/get_country/' + this.selectedCountry)
            .then(function (response) {
                var data = response.data;
                if(data.departments.length > 0) {
                    var departments = [];
                    $.each(data.departments, function (index, value) {
                        departments.push(value);
                    });
                    app.departments = departments;
                }
            });
    },

How I should do to pass a function to the component properly? Any suggestions are appreciated

Edit 2: Something I might cleared up is that the components are being rendered well. Just in case I will add the component registration:

Vue.component('geography-field', require('./components/GeographyField'));
...
const app = new Vue({

To pass a function as a prop to the component, you need to strip off the trailing parentheses of the function name. Otherwise, Vue will evaluate the function. For example:

<geography-field
  label="Pa&iacute;s"
  :_default="selectedCountry"
  placeholder="Choose a country"
  name="country"
  :collection="countries"
  :onchange="selectCountry" // strip off the parentheses
></geography-field>

But, I would also suggest you use $emit instead of passing a function. You can do that like so:

The component definition:

<template>
  <fieldset class="form-group col-md">
    <label :for="name" class="control-label" v-html="label"></label>
    <select class="form-control" :name="name" :id="name" :model="_default" :disabled="disabled" @change="onchange">
      <option :value="0" v-html="placeholder"></option>
      <option v-for="object in collection" :value="object.id">{{ object.name }}</option>
    </select>
  </fieldset>
</template>

<script>
module.exports = {
  props: {
    label: { type: String, default: 'Options' },
    _default: { type: Number, default: 0 },
    disabled: { type: Boolean, default: false },
    placeholder: { type: String, default: 'Choose an option' },
    name: { type: String, required: true },
    collection: { type: Array, required: true }
  },
  methods: {
    onchange() {
      this.$emit("onchange"); 
    }
  }
}
</script>

The component tag in the parent scope:

<geography-field
  label="Pa&iacute;s"
  :_default="selectedCountry"
  placeholder="Choose a country"
  name="country"
  :collection="countries"
  @onchange="selectCountry" // use @
></geography-field>

eg :onchange="selectCountry"

Don't put () when you pass the function. It will trigger the function execution and whatever the function return will be pass into onchange .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM