3
votes

I'm new in VueJS and I am trying to create a custom form component.

I am using http://element.eleme.io elements. So I created a new Form.vue file

<template>
    <el-form :model="data">
        <slot></slot>
    </el-form>
</template>

<script>
  import { FormItem, Input } from 'element-ui';
  export default {
    name: 'general-form',
    components: {
        FormItem,
        Input
    },
    props: ['data'],
    mounted: function() {
        console.log(this.data);
    }
  }

</script>

Here is my app.js

// Element.io
import { Form, FormItem, Input } from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';

// Custom
import GeneralForm from '../../components/presentational-subsystem/form/Form.vue';

Vue.use(Form);
Vue.use(FormItem);
Vue.use(Input);

Vue.config.devtools = true;

var contactsPage = new Vue({
  el: '#contacts-page',
  components:  {
    GeneralForm
  }
});

And here is my view:

<div id="contacts-page">

<general-form id="contacts-form" :data="{subject: 'abc'}" action="/contacts" method="post">
  <el-form-item label="Subject" prop="subject">
    <el-input v-model="data.subject"></el-input>
  </el-form-item>       
</general-form>

</div>

But I get this error in the console:

[Vue warn]: Property or method "formData" 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.

I know that if I change Vue object to this:

var contactsPage = new Vue({
  el: '#contacts-page',
  data: { formData: {} }
  components:  {
    GeneralForm
  }
});

the error disappears, but then form is not reactive any more. I tried to follow this example:

http://element.eleme.io/#/en-US/component/form

and my markup is actually the same, but when I use Vue dev tools, I can see that my formData variable inside my Form.vue component is different from the shared formData variable in my Vue instance.

My question would be how can I make <el> elements use formData from my Form component that I created?

1

1 Answers

3
votes

When you use a slot, its scope -- where its data comes from -- is the parent. The contents of your slot refer to formData, which you define in the child. You can pass child data to slots using scoped slots

Alternatively, you could fully define formData in the parent and pass it as a prop to the child, which passes it on as a prop to el-form.

This structure:

<el-form :model="formData">
    <slot></slot>
</el-form>

has you passing formData from your Form component to the el-form component. It does not pass to the slot. Slots are not children, they are injected code from the parent.

The parent code:

<general-form id="contacts-form" action="/contacts" method="post">
  <el-form-item label="Subject" prop="subject">
    <el-input v-model="formData.subject"></el-input>
  </el-form-item>       
</general-form>

is creating an instance of your Form component and injecting an el-form-item as slot content. The error you are getting is in referring to formData in that slot content, because the slot's context is the parent. A slot does not know anything about what it's being injected into (unless you use scoped slots).

In the updated code:

<general-form id="contacts-form" :data="{subject: 'abc'}" action="/contacts" method="post">
  <el-form-item label="Subject" prop="subject">
    <el-input v-model="data.subject"></el-input>
  </el-form-item>       
</general-form>

You are passing a data prop to the Form child here, but trying to use it in the slot content. the el-input is looking in the parent for data. Try this:

var contactsPage = new Vue({
  el: '#contacts-page',
  data: {
    data: { subject: 'abc' }
  },
  components:  {
    GeneralForm
  }
});

and

<general-form id="contacts-form" :data="data" action="/contacts" method="post">
  <el-form-item label="Subject" prop="subject">
    <el-input v-model="data.subject"></el-input>
  </el-form-item>       
</general-form>