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>
Related
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
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
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}"
In Vue2, I have a string along the lines of the following in my component.
<template>
<div><h1>Hello World</h1>
<div v-html="testString"></div>
</div>
</template>
<script>
export default {
name: "test-component",
props: ['incoming'],
data: function() {
return {
testString: "";
}
},
created() {
this.testString = this.incoming;
}
}
</script>
And then when I do the following (with all the imports done correctly)
<template>
<text-component :incoming="mycontent"></text-component>
</template>
<script>
import 'test-component' from './path/to/test-component.vue'
export default { // etc, just presume this bit is right, it's only psudo code
components: ['test-component'],
data() { return { mycontent: '' }},
created() {
this.mycontent="I just want to <router-link to='/home' v-html='Go Home'></router-link>"
</script>
So now I want the first template with testString to render the <router-link> as if I had put it in myself directly.
I've tried v-html and {{ }} , in my test-component but I think i'm missing something. I'm pretty sure in Vue1 I would use {{{ }}}.
Can anyone help out? Thanks.
From the documentation on v-html:
Note that the contents are inserted as plain HTML - they will not be compiled as Vue templates.
You should be using a slot instead.
Add the slot to your testComponent:
<template>
<div><h1>Hello World</h1>
<slot></slot>
</template>
And then just put the content right in the test-component tag:
<template>
<test-component>
I just want to <router-link to='/home' v-html='Go Home'></router-link>
</test-component>
</template>
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 }}