Is it possible to change content of layout thought props? - vue.js

I have that layout:
<template>
...navigation for all pages..
<h1>content for X??</h1>
<slot />
...footer for all pages...
</template>
For pages/index.vue:
<template>
index is here ok :)
</template>
and pages/about.vue:
<template>
about is here ok :)
</template>
I wish I could render h1 in layout for different pages and not print same text for all.
I know I can move h1 from layout to pages and edit each page.
But there are a lot of content between h1 and slot and I just want to change text.

There would be many ways of achieving what you are asking but the simplest would be the usage of named slots.
In the vue documentation (please take some time digging into it, the amount of deftail and explanation available is very appreciable) :
The <slot> element has a special attribute, name, which can be used to assign a unique ID to different slots so you can determine where content should be rendered.
The process of using named slots in the nuxt layouts is documented in the nuxt layout documentation.
You could create a TitleLayout.vue component in the layouts folder of your nuxt project that would look like this:
<!-- layouts/TitleLayout.vue -->
<template>
<div>
<nav>
<nuxt-link to="/"> index </nuxt-link>
<nuxt-link to="about"> about </nuxt-link>
</nav>
<main>
<h1>
<slot name="heading">
a default title
</slot>
</h1>
<slot/>
</main>
</div>
</template>
and that you could use it like this in your pages/About.vue (or in any other page)
<!-- pages/About.vue -->
<template>
<div>
<NuxtLayout name="with-title">
<template #heading> Hello from the about title </template>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quibusdam eius
rem, sit repellendus reiciendis explicabo? Dolorum totam molestias
adipisci cupiditate distinctio, libero dolorem iusto, quidem esse
excepturi voluptatem repellendus facere.
</NuxtLayout>
</div>
</template>
<script setup>
definePageMeta({
layout: false,
});
</script>

Related

Selenium Find Only the "Deepest" Elements Containing a Specific String

I am trying to retrieve a list of elements from a webpage that contain a specific string. I'm evaluating the XPath using a selenium ISearchContext.FindElement(By.XPath(...)), so the XPath engine is the one supported by the browser.
Below is a minimal sample page created by me, but in a real world scenario I cannot modify the page's structure:
<html lang="en">
<head>
<title></title>
</head>
<body>
<nav>
<ul>
<li>Nav Item 1</li>
<li>Nav Item 2</li>
</ul>
</nav>
<main>
<div class="content">
<p class="description">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Ab deserunt dolore eius est
facere incidunt magni
minus molestiae natus, nesciunt nostrum, officia perspiciatis placeat provident reiciendis saepe sed, sit
voluptates.</p>
<p class="price">1.150<span class="comma">,</span><sup>00</sup> <span class="currency">EUR</span></p>
</div>
<aside>
<p class="price">1.150<span class="comma">,</span><sup>00</sup> <span class="currency">EUR</span></p>
</aside>
<footer>
1<span>.</span>150<span class="comma">,</span><sup>00</sup> <span class="currency">EUR</span>
</footer>
</main>
</body>
</html>
The elements I'm looking for are [p.price, p.price, footer]; basically only the "deepest" elements containing the string 1.150,00 EUR.
If I evaluate the following XPath in Chrome's Developer Tools Console
$x("//*[contains(., '1.150,00 EUR')][contains(ancestor::*, '1.150,00 EUR')][not(contains(child::*, '1.150,00 EUR'))]")
the result I get is [body, div.content, p.price, p.price, footer].
I'm looking for a solution that still lets me remain in the Selenium context so I can further access element properties (such as element position). It doesn't necessarily have to involve XPath and I am also open to using another browser.
//*[contains(., '1.150,00 EUR')]
[not(
*[contains(., '1.150,00 EUR')]
)]
= "all elements whose text value contains '1.150,00 EUR' and don't have a child element whose text value contains '1.150,00 EUR'"
Given that HTML tree, this xpath selects the requested elements
$x("//*[.='EUR']/parent::*[contains(., '1.150,00 EUR')]")
Result
Array(3) [ p.price, p.price, footer ]

Carousel component from bootstrap-vue3 not working

I am creating Vue app with vue3 and using the bootstrap-vue3 package for Frontend.
I followed Bootstrap-Vue docs and copied the following code but Carousel doesn't work.
Of course, I can use another package for Carousel, but almost works already was done with this package. So I am looking for a solution to use this package.
Kindly let me know please if you folks how to fix this issue.
<template>
<div>
<b-carousel
id="carousel-1"
v-model="slide"
:interval="4000"
controls
indicators
background="#ababab"
img-width="1024"
img-height="480"
style="text-shadow: 1px 1px 2px #333;"
#sliding-start="onSlideStart"
#sliding-end="onSlideEnd"
>
<!-- Text slides with image -->
<b-carousel-slide
caption="First slide"
text="Nulla vitae elit libero, a pharetra augue mollis interdum."
img-src="https://picsum.photos/1024/480/?image=52"
></b-carousel-slide>
<!-- Slides with custom text -->
<b-carousel-slide img-src="https://picsum.photos/1024/480/?image=54">
<h1>Hello world!</h1>
</b-carousel-slide>
<!-- Slides with image only -->
<b-carousel-slide img-src="https://picsum.photos/1024/480/?image=58"></b-carousel-slide>
<!-- Slides with img slot -->
<!-- Note the classes .d-block and .img-fluid to prevent browser default image alignment -->
<b-carousel-slide>
<template #img>
<img
class="d-block img-fluid w-100"
width="1024"
height="480"
src="https://picsum.photos/1024/480/?image=55"
alt="image slot"
>
</template>
</b-carousel-slide>
<!-- Slide with blank fluid image to maintain slide aspect ratio -->
<b-carousel-slide caption="Blank Image" img-blank img-alt="Blank image">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse eros felis, tincidunt
a tincidunt eget, convallis vel est. Ut pellentesque ut lacus vel interdum.
</p>
</b-carousel-slide>
</b-carousel>
<p class="mt-4">
Slide #: {{ slide }}<br>
Sliding: {{ sliding }}
</p>
</div>
</template>
<script>
export default {
data() {
return {
slide: 0,
sliding: null
}
},
methods: {
onSlideStart(slide) {
this.sliding = true
},
onSlideEnd(slide) {
this.sliding = false
}
}
}
</script>
You need a active prop in any one of the b-carousel-slide tag to display the slide.
It is something not mentioned in the documentation.

How to customize image size for card in vue bootstrap

I am working on a NuxtJS project, with BootstrapVue as front-end framework. I am trying to edit the size of an image inserted inside the title of a card, with the following code:
<b-card
bg-variant="primary"
text-variant="white"
img-alt="Image"
img-src="~/assets/images/house.png"
header="The house"
class="text-center position-relative"
>
<b-card-text>
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
</b-card-text>
<b-button variant="primary" class="paragraph stretched-link"
>Click here</b-button
>
</b-card>
Does anyone know if is possible to customize the style of the image through the b-card properties (without CSS)? The documentation did not helped me.
You could use img-height and img-width to provide the image size inside the card, they accepts a string or a number as values :
<b-card
bg-variant="primary"
text-variant="white"
img-alt="Image"
img-src="~/assets/images/house.png"
img-height="200"
img-width="200"
header="The house"
class="text-center position-relative"
>

How to pass imageUrl as props?

Here is my component. It takes a props imageUrl which is String referring either an image from a URL or a reference to a local asset from the assets folder
<template>
<div class="flex" style="height: 155px;align-items: center">
<div class="avatar" style="height: 130px;width: 130px">
<img :src="require(`imageUrl`)" height="130" width="130" style="border-radius: 50%"/>
</div>
<div class="flex flex-column" style="margin-left: 31px">
<div class="flex" style="font-weight: bold">
{{fullName}}
</div>
<div class="flex" style="">
{{title}}
</div>
<div style="height: 20px"></div>
<div class="flex" style="text-align: start">
{{content}}
</div>
</div>
</div>
</template>
<script>
export default {
name: "ReviewTile",
props: {
imageUrl: String,
fullName: String,
title: String,
content: String
}
}
</script>
<style scoped>
</style>
I use it like this:
<ReviewTile
image-url="../assets/Eugene.png"
full-name="Eugene B.
"
title="UI/UX Designer."
content=" Christabel is one of the business world’s truly great deal makers and strategists, easily on par with
the best of the strategy consultants and designers I have worked with at SOS-HGIC and Kleio. She is also
a world-class human being."
></ReviewTile>
<div style="background-color: #b7b7b7;height: 1px; margin: 33px 0px"></div>
<ReviewTile
image-url="../assets/headshot_black1.png"
full-name="Gilliam D."
title="Web designer/Developer"
content="Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo."
></ReviewTile>
But images are not loading.
There is a strange JS bug that breaks proper image loading (sry, I forgot what it was, but I found the solution on stackoverflow a while ago).
What helps is breaking the image request up like this:
:src="require('#/assets/' + imageName + '')"
So you only have your image name in the prop and load it without the curly brackets. Now you also don't have to worry about the correct path. The # will find the correct folder.
If anyone can explain the technicalities of this better or finds the other thread with the solution, please feel free to expand on my answer.
Edit: First part of the explanation: Webpack can't work with only a variable as path, because then it would have to go over potentially thousands of files. So you have to have the #/assets/ part as text. Explained more nicely here: Vue.js dynamic image src with webpack require() not working
Couldn't find yet why the curly brackets don't work.
If all your images are in the same folder your can just pass the file name as props:
<ReviewTile
image-url="Eugene.png"
...
></ReviewTile>
<ReviewTile
image-url="headshot_black1.png"
...
></ReviewTile>
Then in the ReviewTitle component, require the imageUrl with the assets path:
<div class="avatar">
<img :src="require(`../assets/${imageUrl}`)" />
</div>
Note:
If all the images have the same extension .png you can even just write the file name like image-url="Eugene" and in the component: <img :src="require(`../assets/${imageUrl}.png`)" />
if you are sending the path of the image in the url, then you can use the props directly,
but make sure you are providing the right path to the image.
<img :src="imageUrl" height="130" width="130" style="border-radius: 50%"/>
also change your prop name in the other component
// Wrong
<ReviewTile
image-url="../assets/Eugene.png"
full-name="Eugene B.
// correct one would be something like this
<ReviewTile
:imageUrl="../assets/Eugene.png"
full-name="Eugene B.
For those using Nuxt.js for the Vue apps - there is simple solution using static folder instead of assets.
The key difference between these two folders is that static is not compiled by Webpack - therefore you are free to use variables as you please.
See the docs:
https://nuxtjs.org/docs/2.x/directory-structure/static

How can we show multiple items with Bootstrap-Vue Carousel?

I think boostrap-vue carousel not so detailed. For this reason i can't reach to nice solution.
I wanna just show 3 items (like in image) in my app and i didnt find the solution and i searched other package and there was no solution for me.
All i want to do like this;
data() {
return {
slide: 0,
sliding: null
};
},
methods: {
onSlideStart(slide) {
this.sliding = true;
},
onSlideEnd(slide) {
this.sliding = false;
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div>
<b-carousel id="carousel-1" v-model="slide" :interval="0" controls indicators background="white" img-width="650" img-height="480" #sliding-start="onSlideStart" #sliding-end="onSlideEnd">
<b-carousel-slide caption="First slide" text="Nulla vitae elit libero, a pharetra augue mollis interdum." img-src="https://picsum.photos/1024/480/?image=52"></b-carousel-slide>
<b-carousel-slide img-src="https://picsum.photos/1024/480/?image=54">
<h1>Hello world!</h1>
</b-carousel-slide>
<b-carousel-slide img-src="https://picsum.photos/1024/480/?image=58"></b-carousel-slide>
<b-carousel-slide>
<img slot="img" class="d-block img-fluid w-100" width="1024" height="480" src="https://picsum.photos/1024/480/?image=55" alt="image slot">
</b-carousel-slide>
</b-carousel>
<p class="mt-4">
Slide #: {{ slide }}<br> Sliding: {{ sliding }}
</p>
</div>
If you have any other library suggestion i would appreciate.
Thanks for help.
BootstrapVue <b-carousel> is designed to only show a single slide at a time (as is the standard bootstrap V4.x carousel component). There are never more than 2 slides visible at once (during the slide or fade transition, all other slides are hidden. CSS transforms are used to make the appearance of the slides moving)
You would need to either find a 3rd party component that supports multiple slides showing, or generate your own custom component.
I'm not familiar with this specific component, but this is from its documentation:
<!-- Slide with blank fluid image to maintain slide aspect ratio -->
<b-carousel-slide caption="Blank Image" img-blank img-alt="Blank image">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse eros felis, tincidunt
a tincidunt eget, convallis vel est. Ut pellentesque ut lacus vel interdum.
</p>
</b-carousel-slide>
I would try using a blank image as the default and inserting whatever other images/content you want as children of the slide:
<!-- Slide with blank fluid image to maintain slide aspect ratio -->
<b-carousel-slide caption="Blank Image" img-blank img-alt="Blank image">
<img class="my-img" src="img1.jpg"/>
<img class="my-img" src="img2.jpg"/>
<img class="my-img" src="img3.jpg"/>
</b-carousel-slide>
And use absolute positioning or flexbox to display them the way you want.
I did the same thing using b-card-group. Because b-carousel does not support showing multiple items.
In template area
<div>
<!-- carousel area -->
<b-card-group deck class="mb-0">
<b-card v-for="(item,index) in currentPageCards" :key="index" class="mr-0">
<!-- card content -->
</b-card>
</b-card-group>
<!-- pagination area -->
<div class="pagination" v-if="cards.length>cardsPerPage">
<div class="index" v-for="i in pageCount" :key="i" #click="next(i)" :class={active:currentPage(i)}></div>
</div>
</div>
In script area
data() {
return {
cards: [{
//Data in the card as objects
},{},{},{},{}],
paginatedCards:[],
pageCount:0,
cardsPerPage:4,
currentPageIndex:0
}
},
computed: {
currentPageCards(){
this.createPages();
return this.paginatedCards[this.currentPageIndex];
}
},
methods:{
currentPage(i){
return i-1===this.currentPageIndex;
},
createPages() {
let cardsLength = this.cards.length;
let fullPagesCount = Math.floor(cardsLength/this.cardsPerPage);
if(cardsLength>this.cardsPerPage) {
this.pageCount = 0;
for (let i = 0; i < fullPagesCount * this.cardsPerPage; i += this.cardsPerPage) {
this.paginatedCards[this.pageCount] = this.cards.slice(i,i + this.cardsPerPage);
this.pageCount++;
}
this.paginatedCards[this.pageCount] = this.cards.slice(cardsLength-this.cardsPerPage,cardsLength);
this.pageCount = this.pageCount+1;
} else {
this.paginatedCards[0] = this.cards;
}
},
next(i){
this.currentPageIndex=i-1;
}
}
In style area
.pagination{
display:flex;
align-items: center;
justify-content: center;
padding:10px;
}
.index{
margin-left:10px;
width:10px;
height:10px;
background:#000000
}
.active{
width:15px;
height:15px;
}
It shows like as below
Try this one. Thank you!