vue.js passing data from parent single file component to child - javascript

Using single file architecture I'm trying to pass data (an object) from a parent component to a child:
App.vue
<template>
<div id="app">
<app-header app-content={{app_content}}></app-header>
</div>
</template>
<script>
import appHeader from './components/appHeader'
import {content} from './content/content.js'
export default {
components: {
appHeader
},
data: () => {
return {
app_content: content
}
}
}
</script>
appHeader.vue
<template>
<header id="header">
<h1>{{ app_content }}</h1>
</header>
</template>
<script>
export default {
data: () => {
return {
// nothing
}
},
props: ['app_content'],
created: () => {
console.log(app_content) // undefined
}
}
</script>
Seems to be such a trivial task and probably the solution is quite simple. Thanks for any advice :)

You're almost there.
In order to send the app_content variable from App.vue to the child component you have to pass it as an attribute in the template like so:
<app-header :app-content="app_content"></app-header>
Now, in order to get the :app-component property inside appHeader.vue you will have to rename your prop from app_component to appComponent (this is Vue's convention of passing properties).
Finally, to print it inside child's template just change to: {{ appContent }}

Related

Vue 3 pass data in <slot>

What I am trying to achieve:
Display an image from dynamic link in Post.vue, which follows the layout of PostLayout.vue
In PostLayout.vue, I have a <slot> named postFeaturedImage, and inside the slot, there is a <div>, I want to use the image as the background of it.
What I am using:
Laravel, InertiaJS, Vue 3
My codes are:
Post.vue:
<template>
<PostLayout>
<template #postfeaturedImage>
<!-- Here I want to display the image -->
</template>
</PostLayout>
</template>
<script>
import PostLayout from '#/Layouts/PostLayout'
export default {
data() {
return {
featured_image: ''
}
},
components: {
PostLayout,
},
props: {
post: Object /* Passed the prop from Controller */
},
mounted () {
this.featured_image = this.post.featured_image
}
}
</script>
PostLayout.vue:
<template>
<slot name="postfeaturedImage" :bgImage="bgImage">
<div :style="`background-image:url(${bgImage}); height: 75vh;`"></div>
</slot>
</template>
<script>
export default {
}
</script>
I've removed all irrelevant codes. I am a beginner in Vue 3 and Inertia and in need of help!
An alternative approach will be creating a FeaturedImage component. Also, you can reference the post image directly from the props you receiving. There's no need for the data method and the mounted in this case.
<template>
<PostLayout>
<template #postfeaturedImage>
<FeaturedImage :src="post.featured_image" />
</template>
</PostLayout>
</template>
<script>
import PostLayout from '#/Layouts/PostLayout'
import FeaturedImage from '#/Layouts/FeaturedImage'
export default {
components: {
PostLayout,
FeaturedImage
},
props: {
post: Object
}
}
</script>
Add a props to your PostLayout.vue
<script>
export default {
props: {
bgImage: { type: String },
},
};
</script>
And give a value to that props in your Post.vue
<template>
<PostLayout :bgImage="featured_image"> </PostLayout>
</template>
And if you ever want to have a post without an image and a different layout you should do :
<template>
<PostLayout>
<template #postfeaturedImage> post without background image</template>
</PostLayout>
</template>

Vue.js passing data between components

I want to store input-value from App.vue, and use it in another component. How can I do it? I don't need the show the value in the template, I just need the value inside other components function. In JS I could just use a global var, but how can I achieve it in Vue?
App.vue:
<template>
<div id='app'>
<!-- App.vue has search bar -->
<b-form-input #keydown='search' v-model='input'></b-form-input>
<div>
<!-- Here's my other components -->
<router-view />
</div>
</div>
</template>
<script>
export default {
name: 'App',
data () {
return {
input: '',
value: ''
}
},
methods: {
search () {
this.value = this.input
this.input = ''
}
}
}
</script>
Another component:
<template>
<div>
<p>I'm another component</p>
<p>App.vue input value was: {{value}} </p>
</div>
</template>
<script>
export default {
props: ['value'],
data () {
return {
value: ''
}
}
}
</script>
This is the basic logic I'm trying to achieve. Input value in App.vue --> anotherComponent.vue
If components are not parent and child you can use store for this:
More advanced vuex store that should be your default GO TO - NPM.
Or simple solution with js object.
a. Create store.js file and export object with property in which you will store value.
b. Import store.js object to vue scripts and use it simply like:
import Store from 'store.js'
Store.value

Vue.js - append variable to component

I am currently using Algolia instantsearch for Vue, which is working fine. However, I am using multiple indexes, so I would like to be able to set a custom Title to each of my indexes.
This is my files:
Home.vue:
<ais-index :appId="angoliaAppId" :apiKey="angoliaAppKey" indexName="contacts" :query="query">
<search-results></search-results>
</ais-index>
<ais-index :appId="angoliaAppId" :apiKey="angoliaAppKey" indexName="users" :query="query">
<search-results></search-results>
</ais-index>
import SearchResults from "../search/Results";
export default {
data() {
return {
query: '',
angoliaAppId: process.env.MIX_ALGOLIA_APP_ID,
angoliaAppKey: process.env.MIX_ALGOLIA_SECRET,
};
},
components: {
SearchResults
}
};
And my component file, looks like this:
../search/Results:
<template>
<ais-results class="ais-Hits__root" v-if="searchStore.query.length > 0" :data="category">
<template slot-scope="{ result }">
<div>
<ais-highlight :result="result" attribute-name="name"></ais-highlight>
</div>
</template>
</ais-results>
</template>
import SearchResults from "../search/Results";
import {
Component
} from "vue-instantsearch";
export default {
mixins: [Component]
};
Now, as said, I would very much like to be able to set a custom title name to each of my <search-results> components, like this:
<search-results :title="My Contacts"></search-results>
Which would then for example add this in the component file:
<h1>{{ title }}</h1>
Seems like you'll have to use props
https://v2.vuejs.org/v2/guide/components.html#Passing-Data-to-Child-Components-with-Props

Vue.js - Dynamic component import in data and computed properties

I have component 'Page' that should display a component which is retrieved via its props.
I managed to get my component loads when I harcode my component path in my component data like this :
<template>
<div>
<div v-if="includeHeader">
<header>
<fv-header/>
</header>
</div>
<component :is="this.componentDisplayed" />
<div v-if="includeFooter">
<footer>
<fv-complete-footer/>
</footer>
</div>
</div>
</template>
<script>
import Header from '#/components/Header/Header';
import CompleteFooter from '#/components/CompleteFooter/CompleteFooter';
export default {
name: 'Page',
props: {
componentPath: String,
includeHeader: Boolean,
includeFooter: Boolean
},
data() {
componentDisplayed: function () {
const path = '#/components/my_component';
return import(path);
},
},
components: {
'fv-header': Header,
'fv-complete-footer': CompleteFooter,
},
}
</script>
But with the data I cannot refer to my props within my function as this is undefined.
I tried to used computed properties instead of data but I have the error "src lazy?0309:5 Uncaught (in promise) Error: Cannot find module '#/components/my_component'. But the module exists! But maybe not at that time ?
computed: {
componentDisplayed: function () {
const path = `#/components/${this.componentPath}`;
return import(path);
},
},
There must be away to deal with that but I am quite a beginner to vue.js :)
Instead of trying to import the component in your child component, instead import it in the parent component and pass the entire component as a prop.
<template>
<div :is="component" />
</template>
<script>
export default {
name: "page",
props: {
component: {
required: true
}
}
};
</script>
And in the parent
<page :component="component" />
and
import Page from './components/Page';
// and further down
data () {
return {
component: HelloWorld
}
}

Use slot-scoped data in the component script in Vue

In vue, I have a component A with a slot that returns an object as the slot-scoped in the component B using it:
component A template:
<template>
<div>
<slot :myObject="myObject" />
</div>
</template>
component B template:
<template>
<component-a>
<template slot-scope="{myObject}">
<!-- uses myObject -->
</template>
</component-a>
</template>
<script>
module.exports={
data(){
return {
myObject: null // This never updates with the new value
}
}
}
</script>
Everything works fine in the html template of component B, however, I cannot access to myObject in the script of component B. I could create a child component (C) that accepts myObject as a prop and have all the needed logic there, but I would like to avoid that.
If you use slot-scope you are basically passing data to the slot, from the component, which is hosting the slot (not the with the content of the slot).
In your case if you want to use data slot-scope, you have to pass the data from component A. So the data-source myObject must exist in component A.
So the right approach would look something like this:
Component A
<template>
<div>
<slot :myObject="myObject" />
<button #click="changeMyObject">Change MyObject</button>
</div>
</template>
<script>
export default {
name: "slot-scope-component",
data(){
return {
myObject: {
value: "ABC"
}
}
},
methods:{
changeMyObject() {
this.myObject = {
value: "XYZ"
};
}
}
}
</script>
Component B
<template>
<ComponentA>
<template slot-scope="props">
{{props.myObject}}
</template>
</ComponentA>
</template>
<script>
import ComponentA from '#/components/ComponentA';
export default {
components: {
ComponentA
},
}
</script>
As well there was a little spelling mistake: You wrote slot-scoped instead of slot-scope
You can improve that code further by using destructuring:
slot-scope="{myObject}"

Categories