van_folmert
van_folmert

Reputation: 4507

"Property is not defined on the instance" even though it is defined

I wanted to add some own scenarios for new components by forking vue-play.

I'm having problems in more complicated cases of vue-select, particularly Two-Way Value Syncing.

Going into this scenario ends up with warning:

vue.esm.js:571 [Vue warn]: Property or method "syncedVal" is not defined on the instance but referenced during render.

and no option in the dropdown is preselected either. I'm failing to understand why I keep getting this warning, despite defining syncedVal in component's props. I've added two files into vue-play/play:

VSelect.vue:

<template>
    <v-select v-model="selected" :options="options"></v-select>
</template>

<script>
    import Vue from 'vue'
    import vSelect from 'vue-select'

    Vue.component('v-select', vSelect);

    export default {
        props: {
            options: {
                default: function() { return ['one', 'two'] },
                type: Array
            },
            onchangeCallback: {
                default: () => () => null
            },
            // doesn't seem to work:
            syncedVal: {
                default: 'one',
                type: String
            }
        },
        data() {
            return {
                selected: null
            }
        }
    }
</script>

and VSelect.play.js:

import {play} from '../src/play'
import VSelect from './VSelect.vue'

play(VSelect)
    .name('VSelect')
    .displayName('VSelect')
    .add('default', '<v-select />')
    .add('multiple', '<v-select multiple />')
    .add('custom options', `<v-select :options="['custom1','custom2']" />`)
    .add('custom options with labels', `<v-select :options='[{value: "CA", label: "Canada"}, {value: "UK", label: "United Kingdom"}]' />`)
    .add('2-way value sync', `<v-select :value.sync="syncedVal" />`) // doesn't seem to work

Upvotes: 0

Views: 1700

Answers (1)

Paul Tsai
Paul Tsai

Reputation: 1009

please note that the v-select component in VSelect.play.js is VSelect.vue

so there are some mistakes:

  1. .add('multiple', '<v-select multiple />')
  • VSelect.vue do not have multiple props, so this multiple will not work as you expectd
  • FIX: add props to your component, and bind it to v-select
  1. .add('2-way value sync', )
  • you define syncedVal in component's props, BUT you use it on other component (vue-play's component), they have different scope!
  • FIX: to use vue-play to demo this functionality, you need to write a full component, so you can have data to bind(see below for example code)
  • VSelect.vue do not implement sync (https://v2.vuejs.org/v2/guide/components.html#sync-Modifier), so nothing will happen here

I make an example from your component and play, I hope this will help you :)

here is how I fix them:

SelectFramework.vue:

<template>
  <v-select
    v-model="selected"
    :options="options"
    :multiple="multiple">
  </v-select>
</template>

<script>
export default {
  name: "SelectFramework",
  props: {
    options: {
      default: () => ["Vue.js", "React", "Angular"],
      type: Array
    },
    value: String, // to support v-model
    foo: String, // to support :foo.sync
    multiple: false // to support multiple select
  },
  data() {
    return {
      selected: this.value,
    };
  },
  watch: {
    selected () {
      this.$emit('input', this.selected) // update v-model
      this.$emit('update:foo', this.selected) // update foo.sync
    },
    value () {
      this.selected = this.value // update from v-model
    },
    foo () {
      this.selected = this.foo // update from foo.sync
    }
  }
};
</script>

play/index.js:

import { play } from 'vue-play'
import Vue from 'vue'
import vSelect from 'vue-select'
Vue.component('v-select', vSelect)


import SelectFramework from '../src/SelectFramework.vue'

play(SelectFramework)
  .name('SelectFramework')
  .displayName('Select Framework')
  .add('default', '<select-framework />')
  .add('multiple', '<select-framework multiple />')
  .add('custom options', `<select-framework :options="['custom1','custom2']" />`)
  .add('custom options with labels', `<select-framework :options='[{value: "CA", label: "Canada"}, {value: "UK", label: "United Kingdom"}]' />`)
  // full component to demo v-model and :foo.sync
  .add('v-model', {
    data() {
      return {
        selected: null,
        syncedVal: null
      }
    },
    template: `
      <div>
        <p>selected: {{selected}} </p>
        <p>syncedVal: {{syncedVal}} </p>
        <select-framework
          v-model="selected"
          :foo.sync="syncedVal">
        </select-framework>
        <p>
          <button @click="selected = 'Vue.js'">Set selected to Vue.js</button>
          <button @click="syncedVal = 'React'">Set syncedVal to React</button>
        </p>
      </div>
    `
  })
  // .add('2-way value sync', `<select-framework :value.sync="syncedVal" />`) // doesn't seem to work

Upvotes: 3

Related Questions