Vue 2 select2 custom template for label - vue.js

I know I can change the template for the option slot, but can we do the same for the label slot? Like for option:
<v-select inputId="originsId" :options="origins" label="city" placeholder="Search...">
<template slot="option" slot-scope="origin">
<div class="flex">
<div class="col">
<span>{{ origin.city }}</span>
</div>
<div class="col">
<span>{{ origin.country }}</span>
</div>
</div>
</template>
</v-select>
Is there some way I can style the label when the option is selected? Now it only shows the label="city" value. I need something like:
<v-select inputId="originsId" :options="origins" label="city" placeholder="Search...">
<template slot="label" slot-scope="origin">
<div class="flex">
<div class="col">
<span>Selected city: {{ origin.city }}</span>
</div>
<div class="col">
<span>Selected country: {{ origin.country }}</span>
</div>
</div>
</template>
<template slot="option" slot-scope="origin">
<div class="flex">
<div class="col">
<span>{{ origin.city }}</span>
</div>
<div class="col">
<span>{{ origin.country }}</span>
</div>
</div>
</template>
</v-select>
Basically I need some custom styling and additional info other then label="city" when the option is selected.

As Vue-select Github: L324 and Vue-select Github: L539, uses <slot name="selected-option"> will be one solution.
Updated: from Vue-select Github you will see there is one parent slot = selected-option-container, but I found it hasn't been deployed to the dist. In future, you should be able to use this slot to custom the whole container and the selected options.
Like below demo:
Vue.component('v-select', VueSelect.VueSelect)
new Vue({
el: '#app',
data: {
options: [
{
title: 'Read the Docs',
icon: 'fa-book',
url: 'https://codeclimate.com/github/sagalbot/vue-select'
},
{
title: 'View on GitHub',
icon: 'fa-github',
url: 'https://codeclimate.com/github/sagalbot/vue-select'
},
{
title: 'View on NPM',
icon: 'fa-database',
url: 'https://codeclimate.com/github/sagalbot/vue-select'
},
{
title: 'View Codepen Examples',
icon: 'fa-pencil',
url: 'https://codeclimate.com/github/sagalbot/vue-select'
}
]
}
})
body {
font-family: "Source Sans Pro", "Helvetica Neue", Arial, sans-serif;
}
h1,.muted {
color: #2c3e5099;
}
h1 {
font-size: 26px;
font-weight: 600;
text-rendering: optimizelegibility;
-moz-osx-font-smoothing: grayscale;
-moz-text-size-adjust: none;
}
#app {
max-width: 30em;
margin: 1em auto;
}
#app .dropdown li {
border-bottom: 1px solid rgba(112, 128, 144, 0.1)
}
#app .dropdown li:last-child {
border-bottom: none;
}
#app .dropdown li a {
padding: 10px 20px;
display: flex;
width: 100%;
align-items: center;
font-size: 1.25em;
}
#app .dropdown li a .fa {
padding-right: 0.5em;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<script src="https://unpkg.com/vue-select#latest"></script>
<div id="app">
<h1>Vue Select - Custom Option Templating</h1>
<v-select :options="options" label="title">
<template slot="selected-option" slot-scope="option">
<div class="flex">
<div class="col">
<span class="fa" :class="option.icon"></span>
<span>Selected item: {{ option.title }}</span>
</div>
</div>
</template>
<template slot="option" slot-scope="option">
<span class="fa" :class="option.icon"></span>
{{ option.title }}
</template>
</v-select>
</div>

Related

Dynamic columns how to seperate styles

I am trying to create dynamic columns, whenever I have 2,3,4 columns then it's not a problem because these are cards with same styles. I want to be able to have 1 item per row with completely different css than the cards. What's the best way to achieve that?
This is what I've tried so far
<script setup>
import { ref } from 'vue'
const list = ref([
{ title: 'hello', content: 'world'},
{ title: 'hello', content: 'world'},
{ title: 'hello', content: 'world'},
{ title: 'hello', content: 'world'},
{ title: 'hello', content: 'world'},
])
const itemsPerRow = ref('25%')
function toggle(e) {
itemsPerRow.value = `${e.target.value}%`
}
</script>
<template>
<select #change="toggle($event)">
<option value="25">4</option>
<option value="33">3</option>
<option value="50">2</option>
<option value="100">1</option>
</select>
<div class="container">
<div class="items">
<div v-for="item in list" class="item">
{{ item.title }}
</div>
</div>
</div>
</template>
<style>
.items {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
}
.item {
flex-basis: v-bind(itemsPerRow);
border: 1px solid black;
box-sizing: border-box;
}
</style>
Working Example
This is just one of many ways you could conditionally render the data based on the number of columns.
Per Vue documentation, you could place the v-for on a template element. And inside use v-if and v-else to render different markup. In this example we check if itemsPerRow == '100%', which indicates that one column is being displayed, and apply different Bootstrap classes.
<template v-for="item in list">
<div v-if="itemsPerRow == '100%'" class="item card mb-2">
<img class="card-image-top" src="https://loremflickr.com/320/50/dog">
<div class="card-body">
<h5 class="card-title">{{item.title}}</h5>
{{item.content}}
</div>
</div>
<div v-else class="item alert alert-primary">
{{ item.title }}
</div>
</template>
Snippet
The snippet differs from the original code since it's an app rather than a component. Selecting 1 column from the dropdown will display a different layout from multiple columns.
const {
createApp
} = Vue
createApp({
methods: {},
watch: {
itemsPerRow: function(value) {
document.querySelector(":root").style
.setProperty("--itemsPerRow", value);
}
},
data() {
return {
itemsPerRow: "25%",
list: []
}
},
mounted() {
for (let i = 1; i <= 100; i++) {
this.list.push({
title: "Title " + i,
content: "The quick brown fox jumped over the lazy dog"
});
}
}
}).mount('#app')
:root {
--itemPerRow: 25%;
}
.container {
margin: 2rem;
}
.items {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 100%;
}
.item {
flex-basis: var(--itemsPerRow);
border: 1px solid black;
box-sizing: border-box;
padding: 0.25rem;
}
<div id="app">
<div class="container">
<select v-model="itemsPerRow" class="form-control mb-2">
<option value="25%">4 columns</option>
<option value="33%">3 columns</option>
<option value="50%">2 columns</option>
<option value="100%">1 column</option>
</select>
<div class="items">
<template v-for="item in list">
<div v-if="itemsPerRow == '100%'" class="item card mb-2">
<img class="card-image-top" src="https://loremflickr.com/320/50/dog">
<div class="card-body">
<h5 class="card-title">{{item.title}}</h5>
{{item.content}}
</div>
</div>
<div v-else class="item alert alert-primary">
{{ item.title }}
</div>
</template>
</div>
</div>
</div>
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.2.2/dist/css/bootstrap.min.css" rel="stylesheet">

I'm trying to convert from pure html code to Vuejs but it's not working

This is the logic algorithm I'm converting and it's not working.
Popup.vue
<script>
import '../../assets/style.css'
export default {
data(){
return{
ceos: [{name_ceo:"Mr. A",
position_ceo:"CEO-GOSTREAM",
content:"Lorem."},
{name_ceo:"Mr. B",
position_ceo:"CTO-GOSTREAM",
content:"Lorem2."},
{name_ceo:"Mr. C",
position_ceo:"CGO-GOSTREAM",
content:"Lorem3."},
]
}
},
methods:{
modalCeo(i){
var modal = this.$refs.modal;
modal[0].style.display="flex";
ceos.forEach(element => {
name_ceo1.innerHTML=ceos[i].name_ceo;
position.innerHTML=ceos[i].position_ceo;
content.innerHTML=ceos[i].content;
});
},
closemodal(){
var modal = this.$refs.modal;
modal[0].style.display="none";
}
}
}
</script>
<style>
</style>
My theme:
<template>
<div class="ceo">
<div ref="modal" class="ceo-popup">
<div class="modal-content-ceo">
<div class="btn-close-popup">
<img src="../../assets/close.svg" id="btn-close-modal" type="button" #click="closemodal()">
</div>
<div class="content-main" v-for="(detail, index) in ceos" :key="index">
<h3 id="name"></h3>
<h5 id="position"></h5>
<h6 id="intro-ceo"></h6>
</div>
<img class="buiding-popup" src="../../assets/Group 226.png" alt="">
</div>
</div>
<div class="title">
<h5>Đội ngũ GoStream</h5>
<h2>Co-Founders</h2>
</div>
<div class="avatar-buiding">
<img class="buiding" src="../../assets/building-0122.png" alt="">
<div class="avatar ">
<img src="../../assets/Profile1.png" #click="modalCeo(0)">
<img src="../../assets//Profile2.png" alt="" #click="modalCeo(1)">
<img src="../../assets/Profile3.png" alt="" #click="modalCeo(2)">
</div>
</div>
</div>
</template>
I want when I click it, a pop up will appear showing the values ​​I have given.
Can you guys give me a solution to this problem?
<div class="avatar" v-for="(item, index) in images" :key="index" >
<img :src="item.url" #click="modalCeo(index)">
</div>
Script:
images:[
{url: '../../assets/Profile1.png'},
{url: '../../assets/Profile2.png'},
{url: '../../assets/Profile3.png'},
]
Update on the code I worked on but it still can't render the image.
You can simply achieve it by using Vue Modal component.
Demo :
new Vue({
el: '#app',
data: {
showModal: false,
selectedCeo: [],
ceos: [
{name_ceo:"Mr. A",
position_ceo:"CEO-GOSTREAM",
content:"Lorem."},
{name_ceo:"Mr. B",
position_ceo:"CTO-GOSTREAM",
content:"Lorem2."},
{name_ceo:"Mr. C",
position_ceo:"CGO-GOSTREAM",
content:"Lorem3."}
]
},
methods: {
modalCeo(index) {
this.showModal = true;
this.selectedCeo = this.ceos[index];
}
}
});
.modal-vue .overlay {
position: fixed;
z-index: 9998;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .5);
}
.modal-vue .modal {
position: relative;
width: 300px;
z-index: 9999;
margin: 0 auto;
padding: 20px 30px;
background-color: #fff;
}
.modal-vue .close{
position: absolute;
top: 10px;
right: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<!-- app -->
<div id="app" class="modal-vue">
<!-- button show -->
<button v-for="(item, index) in ceos" :key="index" #click="modalCeo(index)">{{ item.name_ceo }}</button>
<!-- overlay -->
<div class="overlay" v-if="showModal" #click="showModal = false"></div>
<!-- modal -->
<div class="modal" v-if="showModal">
<button class="close" #click="showModal = false">x</button>
<p>Name : {{ selectedCeo.name_ceo }}</p>
<p>Position : {{ selectedCeo.position_ceo }}</p>
<p>Content : {{ selectedCeo.content }}</p>
</div>
</div>
Note : I updated code snippet as per your comment. Instead of the profile pictures I used buttons just for the demo.

Vuejs binding Progress Circle with text active class

I have this app.
I'm tryna make when progress %20 bottom section text number 1 (Your answers are being analyzed)
opacity = 0.4; --> opacity = 1; I mean I guess active class but how to bind with progress bar ı dont know.
Progress percent %40 text number 2
Progress percent %60 text number 3
Progress percent stops %75 (and there will be popup, this section my part)
When pop-up closed Progress bar keep going from 75 to 100
I'm using this plugin for progress circle: https://github.com/setaman/vue-ellipse-progress
<template>
<div>
<section class="AboutSection d-flex flex-column justify-content-center align-items-start text-center pt-5">
<div>
<router-link to="/eighthPage" class="BackBtn"> <img src="https://img.icons8.com/ios-glyphs/30/000000/back.png"/></router-link>
<router-view></router-view>
</div>
<div class="container-fluid logoHeader">
<h1>Vue-VPN</h1>
</div>
<div class="AboutText container-fluid ">
<div class="row justify-content-center align-items-center text-center ">
<div class="col-md-10">
<h2 class="fw-bolder my-5">Thanks! Your plan is being prepared</h2>
<p class="py-3" style="color: #1488CC;">Please wait a moment...</p>
</div>
<div class="col-md-5 d-flex flex-column justify-content-center align-items-center text-center">
<!-- PROGRESS CIRCLE -->
<ve-progress class="progressCircle position-relative" :progress="75" />
<!-- END PROGRESS CIRCLE -->
<!-- TEXT SECTION-->
<ul class="p-0 m-0 mt-3">
<li class="my-3 d-flex justify-content-start progressText">
<i class="fas fa-check me-2 pt-1" style="color: limegreen;"></i>
<p>Your answers are being analyzed. </p>
</li>
<li class="my-3 d-flex justify-content-start progressText">
<i class="fas fa-check me-2 pt-1" style="color: limegreen;"></i>
<p>Account setup in progress. </p>
</li>
<li class="my-3 d-flex justify-content-start progressText">
<i class="fas fa-check me-2 pt-1" style="color: limegreen;"></i>
<p>Server location setup is in progress. </p>
</li>
<li class="my-3 d-flex justify-content-start progressText">
<i class="fas fa-check me-2 pt-1" style="color: limegreen;"></i>
<p>Your account is being created. </p>
</li>
</ul>
<!-- END TEXT SECTION-->
</div>
<h1>IN PROGRESS</h1>
</div>
</div>
</section>
</div>
</template>
<script>
// import percentCounter from '../components/percentCounter.vue'
// import Progress from '../components/progress2.vue'
export default {
el: '#app',
components: {
// percentCounter ,
// Progress
},
methods:{
}
}
</script>
<style scoped>
.progressCircle{
font-size: 1.5rem;
}
.progressCircle::before{
content: '%';
position: absolute;
font-size: 1.5rem;
display: flex;
justify-content: center;
align-items: center;
top: 50%;
left: 35%;
transform: translate(-50%, -50%);
}
.progressText{
opacity: .4;
color: #111;
}
</style>
if you have an idea it could be anything please comment.
Track your percent in a variable. Then compare if the percent passes text line's percent.
Checkout code snippet below.
<template>
<div id="app">
<ol>
<li v-for="(todo, index) in todos" :key="index">
<label :class="{ passed: percent >= todo.percent }">
{{ todo.text }}
</label>
</li>
</ol>
</div>
</template>
<script>
export default {
data() {
return {
todos: [
{ text: "Learn JavaScript", percent: 20 },
{ text: "Learn Vue", percent: 40 },
{ text: "Play around in JSFiddle", percent: 60 },
],
percent: 10,
interval: null,
}
},
methods: {
increasePercent: function() {
this.percent += 10
},
},
created() {
this.interval = setInterval(this.increasePercent, 500)
},
}
</script>
<style lang="scss">
li {
margin: 8px 0;
font-weight: bolder;
label {
opacity: 0.4;
&.passed {
opacity: 1;
text-decoration: line-through;
}
}
}
</style>
JSFiddle

Styling selected value in Vue Select

I'm using vue select. In the dropdown, there are the labels (not only text). Is it possible to have also the label for the selected value?
<div class="form-group row">
<label for="project_status_id" class="col-sm-3 col-form-label">Projekt Status</label>
<div class="col-sm-9">
<v-select :options="resources.activeProjectStatus" :reduce="project_status_id => project_status_id.id" v-model="form.project_status_id" label="name" id="project_status_id" placeholder="Projekt Status" :class="$vSelectStyle($v.form.project_status_id)">
<template v-slot:option="option" >
<div v-html="option.status_label" class="mb-1">
</div>
</template>
</v-select>
<template v-if="$v.form.project_status_id.$error">
<p class="text-danger" v-if="!$v.form.project_status_id.required">
Projekt - Status ist erforderlich!
</p>
</template>
</div>
</div>
Assuming you want the HTML of the status_label, also assuming that status_label is a template string or similar, then use the selected-option slot with the slot's content being the same as your option slot without the class attached.
The key part in the example below is, as mentioned, the selected-option slot:
<!-- Using OP's `option` key -->
<template v-slot:selected-option="option">
<div v-html="option.status_label"></div>
</template>
The example below is a fork of Vue-Select's Codepen example with modifications for the answer.
Vue.config.productionTip = false;
Vue.component('v-select', VueSelect.VueSelect);
new Vue({
el: '#app',
data: {
options: [
{
name: `<span style="padding: 4px; background: green; border-radius: 0.25rem; color: white;">Foo</span>`
},
{
name: `<span style="padding: 4px; background: orange; border-radius: 0.25rem; color: white;">Bar</span>`
},
{
name: `<span style="padding: 4px; background: red; border-radius: 0.25rem; color: white;">Baz</span>`
}
]
}
});
body {
font-family: 'Source Sans Pro', 'Helvetica Neue', Arial, sans-serif;
}
h1 {
font-size: 26px;
font-weight: 600;
color: #2c3e5099;
text-rendering: optimizelegibility;
-moz-osx-font-smoothing: grayscale;
-moz-text-size-adjust: none;
}
#app {
max-width: 30em;
margin: 1em auto;
}
<script src="https://unpkg.com/vue#latest"></script>
<script src="https://unpkg.com/vue-select#latest"></script>
<link rel="stylesheet" href="https://unpkg.com/vue-select#latest/dist/vue-select.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:600">
<div id="app">
<h1>Vue Select</h1>
<v-select :options="options" label="label">
<template v-slot:option="option" >
<div v-html="option.name" style="padding: 2px 0;"></div>
</template>
<template v-slot:selected-option="option">
<div v-html="option.name"></div>
</template>
</v-select>
</div>

Open one div at a time and close all others which are opened in VueJS

Trying to implement a show/hide description box.
If the user clicks on the first showDesc link it opens it's description box. Then if the user clicks the second showDesc link it opens it's description box and should close all the others which are opened in VueJs.
I tried something as show below.
Below is my code:
new Vue({
el: "#app",
data: {
Show: false
},
methods: {
showDesc: function() {
this.Show = !this.Show;
}
}
})
.descContainer {
position: relative;
padding: 24px 40px 24px 24px;
border-top: 1px solid rgba(0, 0, 0, .08);
display: none;
line-height: 24px;
background-color: #fdfdfd;
}
.descContainer.show {
position: relative;
padding: 24px 40px 24px 24px;
border-top: 1px solid rgba(0, 0, 0, .08);
display: block;
line-height: 24px;
background-color: #fdfdfd;
}
a.mainSmooth.showDesc {
color: dodgerblue;
text-decoration: underline;
cursor: pointer;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet"/>
<main id="app">
<section>
<article class="feedBox mainSmooth">
<div class="feedContainer">
<div class="feedContent">
<h3>Title</h3>
<div class="feedButtonContainer"></div>
<ul class="list-inline feedExtras">
<li class="">
<a #click="showDesc" class="mainSmooth showDesc">show description</a>
</li>
</ul>
</div>
</div>
<div :class="{ show: Show }" class="descContainer">
<div>Description Text</div>
</div>
</article>
<br/>
<article class="feedBox mainSmooth">
<div class="feedContainer">
<div class="feedContent">
<h3>Title</h3>
<div class="feedButtonContainer"></div>
<ul class="list-inline feedExtras">
<li class="">
<a #click="showDesc" class="mainSmooth showDesc">show description</a>
</li>
</ul>
</div>
</div>
<div :class="{ show: Show }" class="descContainer">
<div>Description Text</div>
</div>
</article>
<br/>
<article class="feedBox mainSmooth">
<div class="feedContainer">
<div class="feedContent">
<h3>Title</h3>
<div class="feedButtonContainer"></div>
<ul class="list-inline feedExtras">
<li class="">
<a #click="showDesc" class="mainSmooth showDesc">show description</a>
</li>
</ul>
</div>
</div>
<div :class="{ show: Show }" class="descContainer">
<div>Description Text</div>
</div>
</article>
</section>
</main>
How about in this way:
new Vue({
el: "#app",
data: {
},
methods: {
showDesc: function(e) {
let allA = document.querySelectorAll("a");
for(let a of allA) {
let descContainer = a.closest("article").querySelector("div.descContainer");
descContainer.classList.remove('show');
if(a === e.target) {
descContainer.classList.add('show');
}
}
}
}
})
.descContainer {
position: relative;
padding: 24px 40px 24px 24px;
border-top: 1px solid rgba(0, 0, 0, .08);
display: none;
line-height: 24px;
background-color: #fdfdfd;
}
.descContainer.show {
position: relative;
padding: 24px 40px 24px 24px;
border-top: 1px solid rgba(0, 0, 0, .08);
display: block;
line-height: 24px;
background-color: #fdfdfd;
}
a.mainSmooth.showDesc {
color: dodgerblue;
text-decoration: underline;
cursor: pointer;
}
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js"></script>
<main id="app">
<section>
<article class="feedBox mainSmooth">
<div class="feedContainer">
<div class="feedContent">
<h3>Title</h3>
<div class="feedButtonContainer"></div>
<ul class="list-inline feedExtras">
<li class="">
<a #click="showDesc" class="mainSmooth showDesc">show description</a>
</li>
</ul>
</div>
</div>
<div class="descContainer">
<div>Description Text 1</div>
</div>
</article>
<br/>
<article class="feedBox mainSmooth">
<div class="feedContainer">
<div class="feedContent">
<h3>Title</h3>
<div class="feedButtonContainer"></div>
<ul class="list-inline feedExtras">
<li class="">
<a #click="showDesc" class="mainSmooth showDesc">show description</a>
</li>
</ul>
</div>
</div>
<div class="descContainer">
<div>Description Text 2</div>
</div>
</article>
<br/>
<article class="feedBox mainSmooth">
<div class="feedContainer">
<div class="feedContent">
<h3>Title</h3>
<div class="feedButtonContainer"></div>
<ul class="list-inline feedExtras">
<li class="">
<a #click="showDesc" class="mainSmooth showDesc">show description</a>
</li>
</ul>
</div>
</div>
<div class="descContainer">
<div>Description Text 3</div>
</div>
</article>
</section>
</main>
Here's the fiddle.
It's just a raw idea of how it can be done. I hope it helps.