Reusable Vue component props passing - vue.js

I'm trying to reuse the searchselect multiple times in the same vue file:
<SearchSelect :options="item in brandList"></SearchSelect>
<SearchSelect :options="item in modelTypes"></SearchSelect>
brandList: [
{ value: "A", text: "A" },
{ value: "B", text: "B" },
{ value: "C", text: "C" },
{ value: "D", text: "D" }
],
In my searchselect.vue i'm writing as:
<template>
<div>
<!-- object value -->
<model-select
:options="options"
v-model="item"
placeholder="select item"
></model-select>
</div>
</template>
export default {
props: ["itemOption"],
data() {
return {
options: [],
item: {
value: "",
text: ""
}
};
},
Can someone guide me what i did wrong on passing values from my vue.file data?

From a first glance, it looks like you are using the wrong name for your prop.
In SearchSelect, define the prop as follows.
export default {
props: {
options: Array
},
data: () => ({
item: { value: '', text: '' }
}),
}
The name of the prop is what you'll use to bind brandList and modelTypes to the component when you call it as:
<SearchSelect :options="item in brandList"></SearchSelect>
Note that options matches the name of the prop in the component above

Related

Unable to update Apexchart's category (x-axis label) dynamically in vue

I am using Apexchart's bar chart and noticed that I am not able to change the x-axis's labels, ie the categories. Below is the component:
<template>
<div>
{{magnitudeByFreq}}
{{chartOptions}}
<apex-chart width="500" type="bar" :options="chartOptions" :series="series"></apex-chart>
</div>
</template>
<script>
export default {
props: {
processedMouseData: null,
gradientCountByType: null,
magnitudeByFreq: null,
},
data: function() {
return {
chartOptions: {
chart: {
id: 'vuechart-example'
},
xaxis: {
categories: []//['Positive', 'Neutral', 'Negative']
}
},
series: [{
name: 'series-1',
data: []
}]
}
},
mounted() {
},
watch: {
gradientCountByType: function() {
console.log(this.series.data)
this.gradientCountByType ? this.series[0].data = this.gradientCountByType : console.log("Not working")
this.gradientCountByType ? this.chartOptions.xaxis.categories = ['Positive', 'Neutral', 'Negative'] : console.log("No xaxis")
},
magnitudeByFreq: function() {
this.magnitudeByFreq ? this.series[0].data = Object.values(this.magnitudeByFreq) : console.log("ABX")
this.magnitudeByFreq ? this.chartOptions.xaxis.categories = Object.keys(this.magnitudeByFreq) : console.log("ABA")
}
}
};
</script>
Currently the categories is set to []. This is because I want it to be filled by different data depending on which prop is using it. ie gradientCountByType or magnitudeByFreq.
The two lines below which are supposed to set the category:
this.gradientCountByType ? this.chartOptions.xaxis.categories = ['Positive', 'Neutral', 'Negative'] : console.log("No xaxis")
this.magnitudeByFreq ? this.chartOptions.xaxis.categories = Object.keys(this.magnitudeByFreq) : console.log("ABA")
They don't seem to update the category at all. I should however mention that what gets displayed in the template {{magnitudeByFreq}} and {{chartOptions}}, do reflect there is a change in the category variable:
{{chartOptions}} shows:
{ "chart": { "id": "vuechart-example" }, "xaxis": { "categories": [ "Positive", "Neutral", "Negative" ], "convertedCatToNumeric": false } }
and
{ "chart": { "id": "vuechart-example" }, "xaxis": { "categories": [ "+0", "+100", "+1000", "+2000" ], "convertedCatToNumeric": false } }
Why is the categories attribute not displaying correctly? For whatever reason, the categories are showing numbers.
My guess is by changing the data attribute doesn't actually update the chart.
Instead we should create a reference to the chart:
<apex-chart ref="radar" type="radar" height="350" :options="chartOptions" :series="series"></apex-chart>
Then we can update the data with updateSeries method and update the chartOptions with updateOptions method:
this.$refs.radar.updateSeries([{
name: 'Series 1',
data: [your_new_data_here] //ie [1,2,3,4]
}])
this.$refs.radar.updateOptions({
xaxis: {
categories: [your_new_categories_here] //ie ["a","b","c","d"]
}
})
<apex-chart ref="chart" :options="options" :series="series"/>
Chart component has refresh function. So we can re-render the chart.
this.series[0].data = [yourData];
this.options.xaxis.categories = [yourCategories]
this.$refs.chart.refresh();

How to make nested properties reactive in Vue

I hava a component with complex nested props:
<template>
<div>
<a-tree :tree-data="data" :selected-keys="[selectedKey]" #select="onSelect" />
<div>
<a-input v-model="sheet[selectedKey].tableName" />
<ux-grid ref="previewTable">
<ux-table-column v-for="field in sheet[selectedKey].fields"
:key="field.name" :field="field.name">
<a-input slot="header" v-model="field.label" />
</ux-table-column>
</ux-grid>
</div>
</div>
</template>
<script>
export default {
props: {
previewData: { type: Array, default: () => [] }
},
data () {
return {
data: this.previewData,
selectedKey: '0-0-0',
sheet: { 'none': { tableName: null, fields: [] } }
}
},
created () {
this.data.forEach((file, fid) => {
file.sheets.forEach((sheet, sid) => {
this.$set(this.sheet, `0-${fid}-${sid}`, {
tableName: sheet.label,
fields: sheet.fields.map(field => ({ ...field }))
})
})
})
},
mounted () {
this.$refs.previewTable.reloadData(this.data[0].sheets[0].data)
},
methods: {
onSelect ([ key ], { node }) {
if (key !== undefined && 'fields' in node.dataRef) {
this.selectedKey = key
this.$refs.previewTable.reloadData(node.dataRef.data)
} else {
this.selectedKey = 'none'
this.$refs.previewTable.reloadData()
}
}
}
}
</script>
And previewData props is something like:
{
name: "example.xlsx",
filename: "80b8519f-f7f1-4524-9d63-a8b6c92152b8.xlsx",
sheets: [{
name: "example",
label: "example",
fields:[
{ label: "col1", name: "col1", type: "NUMBER" },
{ label: "col2", name: "col2", type: "STRING" }
]
}]
}
</script>
This component allows user to edit the label properties. I have to make Object sheet reactive to user input, and I tried $set and Object.assign, it works for sheets.label but fields[].label is still not reactive.
I wish to know what would be the declarative (and optimal) solution for it
You might need a watcher or computed property in React for previewData to be changed.

How to use customRender in a table cell with Antd and VueJS

I'm using antd in my app and I'm trying to do a customRender to show an image in a cell.
My columns array looks like this:
columns: [
{ title: 'Design',
dataIndex: 'designImage.fileUrl',
customRender () { // h will be injected
return '<div id="foo">bar</div>'
}
},
]
So, as you might imagine, it turns out like this:
I also tried this way:
{ title: 'Design',
dataIndex: 'designImage.fileUrl',
customRender: (text, record, index) => {
return {
children: '<img src="https://via.placeholder.com/300.png/09f/fff">'
}
}
},
Unfortunately, that ended up like this:
Can someone please help me figure out what I'm doing wrong?
You can take advantage of the scopedSlots property within columns, and use it to define a scoped slot for the customRender property.
Here is an example:
const columns = [
{
title: "Image",
dataIndex: "image",
key: "image",
scopedSlots: { customRender: "image-column" },
},
];
Now, in your template, you can use the image-column named slot, like this:
<a-table :columns="columns" :data-source="tableData">
<template slot="image-column" slot-scope="image">
<img :src="image" /> <!-- Add your custom elements here -->
</template>
</a-table>
And here is a component example:
<template>
<a-table :columns="columns" :data-source="tableData">
<template slot="image-column" slot-scope="image">
<img :src="image" />
</template>
</a-table>
</template>
<script>
const columns = [
{
title: "Image",
dataIndex: "image",
key: "image",
scopedSlots: { customRender: "image-column" },
},
];
const tableData = [
{
image: "https://picsum.photos/200",
},
{
image: "https://picsum.photos/200",
},
];
export default {
data() {
return {
columns,
tableData,
};
},
};
</script>
When you use antd's Table, customRender should return a vnode but not a string, so you can try it like this
columns: [
{ title: 'Design',
dataIndex: 'designImage.fileUrl',
customRender () {
return <div id="foo">bar</div>
}
}
]

How to set dynamic v-model for input and set value to this v-model in Vue 2

I have a component for creating dynamic input fields. I have a prop - fields.
fields: [
{
label: 'Question Text',
placeholder: 'Enter Text',
isRequired: true,
editable: true,
name: 'question',
value: '123',
},
{
label: 'Button Text',
placeholder: 'Enter Text',
isRequired: true,
editable: true,
name: 'button',
value: '',
},
],
Than I pass this to component SettingsViewFields.vue
<template>
<div>
<e-form-group v-for="(field, index) in fields" :key="index" :error="getInputError[field.name]">
<template v-slot:label>
{{ field.label }}
</template>
<e-textarea
v-model="form[field.name]"
:name="field.name"
size="small"
#input="onInput($event, field.name)"
></e-textarea>
</e-form-group>
</div>
</template>
<script>
export default {
name: 'SettingsViewFields',
props: {
fields: {
type: Array,
default: () => [],
},
},
data: () => ({
form: [],
}),
};
</script>
I want that reactive data for input calls from field.name that the reactive data will be form: {question: '', button: ''} But the problem I have to set correct value for input, but if I set field.name the value will be not correct because for first input it's value: '123'.
You can't Change the data passed by the parent component directly, when you receive the prop data from parent that you want update, you can make a copy of this,eg
computed: {
fieldsCopy: function () {
return this.fields
},
}
and use fieldsCopy in your template, that may work.
if you also want to pass the updated data to parent , use emit.

Rendering multiple components dynamically from an array

I am trying to render components dynamically within my child component named ChildTabs. I would like to render the components based on the array that passed into the component from the parent view named Contatcs.
So for example if I pass the the form_type from the contact_type named "Big" it would render on my tabs vue. However I have other data that contains more than one component I am trying to render, such as medium which contains multiple forms such as Red Green & Blue.
I have an idea of creating a for loop in my method using the prop data form_type, so I can retrieve my list of forms I am trying to call, but that is where I do not know what to do next. I am already importing the forms, I am not sure how to render them.
Any suggestions are welcomed.
Contacts.vue
<template>
<div class="row">
<ChildTabs
:form_type="contact_types"
/>
</div>
</template>
<script>
'use strict';
import ChildTabs from '../tabs';
export default {
name: 'contacts-view',
data: function () {
return {
form_data: {},
failed_validations: [],
contact_type: '',
contact_types: [
{
label: 'Big',
value: 'big',
form_type: [
'Red'
]
},
{
label: 'Medium',
value: 'medium',
form_type: [
'Red',
'Green',
'Blue'
]
},
{
label: 'Small',
value: 'small',
form_type: [
'Blue',
'Green'
]
},
],
}
},
props: {
},
computed: {
},
methods: {
},
components: {
ChildTabs
}
}
</script>
Tabs.vue
<template>
<!--=============================================================-->
<!-- Contact Forms -->
<!--=============================================================-->
</template>
<script>
'use strict';
import Red from './forms/red';
import Green from './forms/green';
import Blue from './forms/blue';
export default {
name: 'forms-tab',
data: function () {
return {
}
},
props: {
form_type: {
type: Array,
required: false,
default: []
},
},
computed: {
},
methods: {
RenderComponent: function ()
{
this.$props.form_type
}
},
created: function () {
this.RenderComponent();
},
components: {
Red,
Blue,
Green
}
}
</script>
You can use dynamic component in Vue
<template>
<div>
<div v-for="type in form_type" :key="type">
<component :is="getCompentName(type)"/>
</div>
</div>
</template>
<script>
export default {
...
methods: {
getCompentName(type) {
switch (type) {
case 'red':
return 'red'
case 'blue':
return 'blue'
case 'green':
return 'green'
default:
return 'red'
}
}
}
}
</script>