How to use one component in another component vuejs - vue.js

<my-comp
title="title"
craps="one->two->three"
/>
<bread :record="record">
data(){
return {
record = [{title: 'name', item: 'one'}, {title: 'name', item:'two'}];
}
}
I wanted to use <bread component in component under craps like this
<my-comp
title="title"
craps=<bread :record="record">
/>
what is the process to use of it please guide
Thank you

Related

shopware custom admin config component doesn't save sales channel id

For a shopware 6 plugin , in config.xml I have a custom component
<card>
<title>My Plugin</title>
<title lang="de-DE">My Plugin</title>
<component name="config-component">
<name>configComponent</name>
</component>
</card>
In the twig of this component i have a simple field
<sw-text-field :label="Test" size="medium" required />
I saw that for components, if i want to change the sales channel and save the data, the sales channel id is not saved in the system_config table for that text field.
What can i do so my inputs from components be dependent on sales channels? Thank you
The following component and template should work as intended.
import template from './config-component.html.twig';
const { Component } = Shopware;
Component.register('config-component', {
template,
props: {
value: {
required: true,
}
},
methods: {
onChange(value) {
this.$emit('change', value || '');
},
onInput(value) {
this.$emit('input', value);
}
}
});
<sw-text-field
v-model="value"
label="Test"
size="medium"
required
#input="onInput"
#change="onChange"
/>

Check if data/prop are passed or not?

I got a component that i pass in some data to. I want to check if "title" is passed or not, and conditionally set its value. As it works now, the value i pass just overrides. How would i do that?
<Meta title="test" />
Component
<template>
<vue-headful
:title="this.title"
/>
</template>
<script>
import vueHeadful from "vue-headful";
export default {
name: "Meta",
components: { vueHeadful },
data() {
return {
title: "default val"
};
}
};
In your Meta component you are not defining the prop, but a variable in data. You should delete the title from data and add a prop:
props:
{title: {
type: String,
default: 'default val'
}},
See documentation on props
You also do not need this. before title in your template.
<vue-headful :title="title" /> will be enough.

2 Way Databind components within Components

I am struggling to reuse my components.
I want to pass the data passed to my component as a prop to another component.
If I do that vue complains about a mutation of the prop.
Example:
I have contacts that I want to show on multiple location of my app.
For that I created a contact component to reuse it:
<template>
<div>
<input :value="contact.firstName" #input="$emit('update:contact', {...contact, firstName: $event.target.value})">
<Mother v-model:mother="contact.mother"/>
</div>
</template>
<script>
import Mother from '#/components/Mother'
export default {
name: 'Contact',
components: {
Mother
},
props: {
contact: Object,
},
emit: ['update:contact'],
methods: {
}
}
</script>
Every contact has a mother, mother are shown in other places not only in the contact component.
That is why I created a mother component, that is used by the contact.
<template>
<div>
<input :value="mother.lastName" #input="$emit('update:mother', {...mother, lastName: $event.target.value})">
</div>
</template>
<script>
export default {
name: 'Mother',
props: {
mother: Object,
},
emit: ['update:mother'],
methods: {
}
}
</script>
Now I want to be able to mutate the contact an the mother as well, and I want to be able to use two contact components on the same site.
If I use it the way explained I get this error:
ERROR Failed to compile with 1 error 09:17:25
error in ./src/components/Contact.vue
Module Error (from ./node_modules/eslint-loader/index.js):
/tmp/vue-example/src/components/Contact.vue
4:27 error Unexpected mutation of "contact" prop vue/no-mutating-props
✖ 1 problem (1 error, 0 warnings)
I have an example project showing my problem:
https://gitlab.com/FirstWithThisName/vue-example.git
Thanks for your help
First I need to assume a few points.
You wanted to use v-model.
You wanted the component to be chained.
Working Example here on Vue SFC Playground.
*Note that the import path is different on the example site.
App.vue
<template>
<Contact v-model="contact" />
{{ contact }}
</template>
... remaining code omitted
Contact.vue
<template>
<div>
<input v-model="localValue"/>
<Mother v-model="childValue" />
</div>
</template>
<script>
import Mother from "./Mother.vue"
export default {
name: "Contact",
components: {
Mother
},
props: {
modelValue: Object,
},
mounted(){
this.childValue = this.modelValue.mother
},
data: () => ({
localValue: "",
childValue: null
}),
watch:{
updatedData(){
this.$emit('update:modelValue', this.updatedData)
}
},
computed: {
updatedData() {
return { firstName: this.localValue, mother: this.childValue };
},
},
};
</script>
Mother.vue
<template>
<div>
<input
v-model="localValue"
#input="$emit('update:modelValue', updatedData)"
/>
</div>
</template>
<script>
export default {
name: "Mother",
props: {
modelValue: Object,
},
data: () => ({
localValue: "",
}),
computed: {
updatedData() {
return { ...this.modelValue, lastName: this.localValue };
},
},
};
</script>
As you might know, props cannot be mutated, so you will need to "make a copy" of the value on each component to process locally.
If Mother component are never going to be used separately, v-model can be split into v-on and v-bind instead.
Lastly, as for recommendation, chaining like this can become very messy if the data starts to grow or the depth level increases. You could just make another Wrapper component that contains Contact and Mother component that scales horizontally instead.
Depends on how complex your application will get.
One option is two-way data-binding as explained here:
https://v3.vuejs.org/guide/component-basics.html#using-v-model-on-components
So you basically emit the changes to the parent.
For more complex applications I wouldn't pass data that are used in multiple components as props, but use a store. Either a simple reactive object; with provide/inject or use something like Vuex.

Why can't apollo get data in first request?

I am using props to get the Id of birds.
When I first start the app and click to enter the second-page, data won't load.
It gives the following error;
JS: [Vue warn]: Error in render: "TypeError: Cannot read property 'name' of undefined"
JS:
JS: found in
JS:
JS: ---> <Detail> at components/Detail.vue
JS: <Frame>
JS: <Root>
But after I click on button second time it loads properly.
I have created a repo showing the problem. Please check it here:
github repo
Working graphql playground
<template>
<Page>
<StackLayout>
<Label :text="bird.name" textWrap="true" />
<Button text="get data" #tap="getData" />
</StackLayout>
</Page>
</template>
<script>
import { gql } from "apollo-boost";
export default {
props: ["birdID"],
apollo: {
bird: {
query: gql`
query($id: ID!) {
bird(id: $id) {
id
name
}
}
`,
variables() {
return {
id: this.birdID,
};
},
},
},
methods: {
getData() {
console.log("bird data: ", this.bird);
},
},
mounted() {},
};
</script>
<style></style>
Is there a better way to get data?
Answer was correct
I have updated github repo with solution.
https://github.com/kaanguru/query-data-from-prop
The issue is that your template
<Label :text="bird.name" textWrap="true" />
attempts to display bird.name before your query has completed.
The Vue Apollo documentation shows a simple work-around by defining some initial defaults
You can initialize the property in your vue component's data hook
data: () => ({
bird: {
name: null
}
}),
Alternately, make use of the Loading state feature to conditionally render your components
<Label v-if="$apollo.loading" text="loading" textWrap="true" />
<StackLayout v-else>
<Label :text="bird.name" textWrap="true" />
<Button text="get data" #tap="getData" />
</StackLayout>

How to replace component when v-bind is already used and it's inside loop

The problem I'm encountering is like this.
<div v-for="(obj, index) in objects">
<button #click="changeComponent(index, 'A')>Change to A</button>
<button #click="changeComponent(index, 'B')>Change to B</button>
<ComponentA v-bind:obj="obj" />
</div>
...
components: {
ComponentA,
ComponentB,
}
data() {
return {
objects: [
{ name: 'A' }
]
}
},
methods: {
changeName(index, name) {
this.objects[index].name = name
}
}
What I want to do is to replace component depending on the obj's name.
However there are some problems. First I thought I could use v-bind:is but I already used v-bind to pass value to child component. Second even if I can use v-bind:is I still don't know how to access to its index in computed method. Is there other good way to do it? How can I solve this problem?
You need to use :is to set your component. You can also bind props with this. Something like this should work
<div v-for="(obj, index) in objects">
<button #click="changeComponent(index, 'A')>Change to A</button>
<button #click="changeComponent(index, 'B')>Change to B</button>
<component :is="objToComponent[obj.name]" v-bind:obj="obj" />
</div>
...
components: {
ComponentA,
ComponentB,
}
data() {
return {
objects: [
{ name: 'A' }
],
objToComponent: {
'A': 'ComponentA',
'B': 'ComponentB'
}
}
},
methods: {
changeName(index, name) {
this.objects[index].name = name
}
}
The main changes are:
added an object that maps names to component names, so Vue know what you want to render
used :is so you are able to change the component based on obj.name
Well, to do so, you can use :is for making the dynamic component.
Used for dynamic components and to work around limitations of in-DOM templates.
Here is the working JsFiddle
Here is the official docs
Hope this helps