Boostrap Vue & Vue - Load Form-Select with array - vue.js

I'm working in a Laravel + Vue project. Initially I need to load a Vue component data from the view of Laravel. The idea is send by Prop parameter an array object with this data and from Vue component to load a Html Select element.
Unfortunately it's doesn't work. I'm new in Vue :(
From testing I want to load this Vue component send and static array: ['Customer1', 'Customer2'], I'm not send a variable array as for example {{ $customers }}. The goal will be send a variable from Laravel but for testing not.
I have made this html:
<div class="card-body">
<create-task-jobs v-bind:customers="['Customer1', 'Customer2']">
</create-task-jobs>
</div>
From bootstrap-vue I want to load a Select component(create-task-jobs) from array by Prop(v-bind:customers) parameter.
The code of my Vue component is:
<template>
<div>
<form #submit.prevent="agregar">
<h3>Afegir Tasques</h3>
<b-form-group id="input-group-3" label="Client" label-for="input-3">
<b-form-select
id="input-3"
v-model="form.customer"
:options="customers_load"
required
></b-form-select>
</b-form-group>
<button class="btn btn-primary" type="submit">Agregar</button>
</form>
</div>
</template>
<script>
export default {
props: {
customers: Array
},
data() {
return {
form: {
customer: null,
},
customers_load: [this.customers]
}
}
}
</script>
The current result is wrong because there is only an option separated by comma:
... but the correct behavior would be two option elements:
-> Customer1
-> Customer2
Please Could you help me with this issue?
Thanks.

You needs to use spread operator.
data() {
return {
form: {
customer: null,
},
customers_load: [...this.customers] 👈
}
}

Related

passing object to component using v-for

I am trying to send a series of objects that are in an array to a child component using v-for, but when I try to access them from the child component, it tells me that the props are not defined.
Im using Quasar Framework actually
This is how I pass the data:
<div class="row justify-center">
<foo
v-for="brand in brands"
:key="brand.id"
:brand="brand"
></foo>
</div>
<script>
import foo from "src/components/foo.vue";
export default {
components: {
foo
},
data() {
return {
brands: []
};
},
methods: {
async getData() {
let x = await get.getData();
this.brands = x.data;
console.log(this.brands);
}
},
mounted() {
this.getData();
}
};
</script>
brands is an array that obtains two objects from a request made to a local database, which I have already verified that it receives the data correctly
And this is the component file and how I try to get the properties:
<q-card class="my-card" flat bordered>
<q-img
:src="require(`../assets/${brand.img}`)"
:alt="brand.img + ' Logo'"
/>
<div class="text-h5 q-mt-sm q-mb-xs">{{ brand.name }}</div>
<div class="text-caption text-grey">
<p>
{{ brand.price }}
</p>
</div>
<script>
export default {
name: "foo",
props: ["brand"],
data() {
return {
expanded: false
};
},
};
</script>
but when I try to execute the code it gives me the following error:
Error in render: "Error: Cannot find module './undefined'
I know one way to make it work, and it is by creating a property for each of the object's values, for example:
<component
v-for="brand in brands"
:key="brand.id"
:name="brand.name"
:price="brand.price"
></component>
But I dont think thats the correct way to do this....
try to change
import component from "src/components/component.vue";
to
import foo from "src/components/component.vue";
on your components section you just call foo instead of foo:component
I am not sure, but:
Looks like ${brand} is empty. Your function GetData() is async, so the <foo> is created before the GetData() has its data set/returned.
You can change
<foo v-for="brand in brands" :key="brand.id" :brand="brand"></foo>
To
<foo v-if="brands.length> 0" v-for="brand in brands" :key="brand.id" :brand="brand"></foo>
To make sure that the element is renderd after the data if set.
Note: v-if is when the html is rendered, v-show is just a css display hide, but the html is always renderd

Vue/Vuex Accessing Objects elements

Hi I am getting confused as to how I can access some data within my Object. I am using Vuex and I have a standard page. Here, I use a getter to obtain the Payment
Object and pass it to a component.
<template>
<div>
<div class="container">
<div class="row">
<div class="col-12 flex">
<payment-details :payment="payment"></payment-details>
</div>
</div>
</div>
</div>
</template>
<script>
import {
PaymentDetails
} from "#/components/Payment";
export default {
components: {
'payment-details': PaymentDetails
},
created () {
if (!this.payment.paymentID) {
this.$store.dispatch('paymentById', this.$route.params['id'])
}
},
computed: {
payment () {
return this.$store.getters.paymentById(this.$route.params['id'])
}
}
}
</script>
Now within the component, within the template, I can do something like this
<template>
<div v-if="payment">
<div class="row">
<div class="col-12">
<h3 class="h-100">{{ payment.details }}</h3>
</div>
</div>
</div>
</template>
This all works fine. However, within this component, I need to access some elements of the payment object. This is where I get confused, if I create a mounted or created hook and do this
created() {
console.log(this.payment)
}
I always get an Observer object. If I try accessing an element from this Object e.g.
created() {
console.log(this.payment.details)
}
I get undefined. I basically have a slideshow I am creating in a mounted hook. I need to push some items contained within this Object onto the slideshow array.
So how can I actually get access to the elements of this Object?
Thanks
You should use watcher on your vuex object.
Here is link to documentation https://v2.vuejs.org/v2/guide/computed.html#Computed-vs-Watched-Property
Most probably your this.payment.details is instantiated after your created method was called.
Move your code from created method to:
export default {
watch: {
payment: function (val) {
console.log('-------- this is this.payment.details:');
console.log(val.details);
},
...
Yes it will gave you of undefined because in your props you declare only a payment object alone not like this one below.
payment : {
details: '',
etc: ''
}
But it will still works when you use this payment data in your component, it's like it only gives you an error something like 'calling details on null' like that. I prefer to put condition first if payment has already data before you call in your component. Like below
<div v-if="payment.details">{{payment.details}}</div>

What is the correct way to retrieve data from 2 or more identical components?

Evening. I've created a button which adds a component that has an input field inside. I might need to press that button few times so there would be 2-3 input fields that appear. Whenever I type the text I would like to send a request from the parent component but I don't know how to retrieve the data from every child component that has been created. Is this the time to start using vuex (never used it)?
ParentComponent.vue
<template>
<div>
<button class="btn btn-success" #click="addStep">Add step</button>
<div v-for="i in count">
<recipe-step v-bind:step-number="i"></recipe-step>
</div>
</div>
</template>
<script>
export default {
data() {
return {
count: 0
}
},
methods: {
addStep() {
this.count += 1;
}
}
}
</script>
StepComponent.vue
<template>
<div>
<div class="from-group">
<label for="step-input"></label>
<input id="step-input" v-model="text" type="text">
</div>
</div>
</template>
<script>
export default {
props: {
stepNumber: {
type: Number,
required: true
}
},
data() {
return {
step: this.stepNumber,
text: ""
}
}
}
</script>
No, you really don't need Vuex yet. As long as you are still dealing with parent-child-component communication, you should be fine. Vuex comes into play when components, spread across the hole component hierarchy, need to exchange information.
Now, you should do something like this:
Don't store the text in the child component. When the input changes, send a Custom Event right to the parent component. Note that
<input v-model="text">
is only syntax sugar for
<input :value="text" #input="text = $event">
Both have the same effect. That's way you can send the input event up to the parent, like this:
<input #input="$emit('input', $event)">
Add another prop to your child component called value which should replace text.
And now you can use v-model in the parent component:
<recipe-step v-model="text">
To store multiple values, just use an array in your data properties.
<recipe-step v-model="textArray[i]">
Vuex can help you on that, however if all you want is to get the input text value back to the parent with the minimum effort you can create a prop called value in the children and then pass it as v-model in the parent.
Since you have a v-for you could make it iterate over a list instead a counter and then pass some prop inside each item as v-model

How do I insert object created with document.createElement into template?

I like to know how I can insert a Element that has already been created with the document.createElement method into the template. I am not sure how to proceed here because eventually I would also like to bind the contents of that particular textBox. Here is the (non working) code that I have up till now to illustrate what I like to do:
<template>
<div>
<p id="status">{{ statusMessage }}</p>
<div id="output" v-html="textBox"></div>
</div>
</template>
<script>
export default {
name: 'Result',
data() {
return {
statusMessage: "Status",
textBox: Object,
}
},
mounted() {
this.textBox = this.$someModule.createTextBox()
console.log('textBox should become: '+this.textBox)
// Shows: textbox should become: [object HTMLTextAreaElement]
},
...
}
First of all, v-html is a directive that allow you to use raw html text.
ref: https://v2.vuejs.org/v2/guide/syntax.html#Raw-HTML
Second of all, you can you a ref directive to create a link to you element (ref="someName"):
<div id="output" ref="textBox"></div>
Then:
const el = this.$refs.textBox;
el.appendChild('entity which you want to append');

How to prevent the data/method sharing of looped components in Vue.js

I have the vue component with $emit into component and let it return the data from the component. I will use the component to update current page's data. the codes below
Template:
<Testing
#update="update">
</Testing>
<AnotherComponent
:data="text"
>
</AnotherComponent>
Script:
method(){
update: function(data){
this.text = data.text
}
}
it work perfectly if only this one.
Now , i need to make a button to add one more component.
I use the for loop to perform this.
Template
<div v-for="index in this.list">
<Testing
:name="index"
#update="update">
</Testing>
<AnotherComponent
:data="text"
>
</AnotherComponent>
</div>
Script:
method(){
addList : function(){
this.list +=1;
},
deleteList : function(){
this.list -=1;
},
update: function(data){
this.text = data.text
}
}
The add and delete function run perfectly.
However , they share the "update" method and the "text" data.
so , If I change the second component , the first component will also changed.
I think this is not the good idea to copy the component.
Here are my requirements.
This component is the part of the form, so they should have different name for submit the form.
The another component" will use the data from the "testing component" to do something. the "testing" and "another component" should be grouped and the will not change any data of another group.
Any one can give me the suggestion how to improve these code? Thanks
What happends is that both are using the data form the parent, and updating that same data.
It seems that you are making some kind of custom inputs. In that case in your child component you can use 'value' prop, and 'input' event, and in the parent user v-model to keep track of that especific data data.
Child component BaseInput.vue:
<template>
<div>
<input type="text" :value="value" #keyup="inputChanged">
</div>
</template>
<script>
export default {
props: ['value'],
data () {
return {
}
},
methods: {
inputChanged (e) {
this.$emit('input', e.target.value)
}
}
}
</script>
And this is the code on the parent:
<template>
<div class="container">
<div class="row">
<div class="col-xs-12 col-sm-8 col-sm-offset-2 col-md-6 col-md-offset-3">
<base-input v-model="firstInputData"></base-input>
<p>{{ firstInputData }}</p>
<hr>
<base-input v-model="secondInputData"></base-input>
<p>{{ secondInputData }}</p>
</div>
</div>
</div>
<script>
import BaseInput from './BaseInput.vue'
export default {
components: {BaseInput},
data() {
return{
firstInputData: 'You can even prepopulate your custom inputs',
secondInputData: ''
}
}
}
</script>
In the parent you could really store the diferent models in an object as properties, and pass that object to that "The another component" , pass them as individual props... pass an array ....