How will I do select with vue-select in vue 3?
<v2-select :options="options" label="title">
<template slot="option" slot-scope="option">
<img :src="option.url">
{{ option.url }}
</template>
</v2-select>
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'
}
],
}
example:
https://stackblitz.com/edit/vue-5ni27c?file=src%2FApp.vue,package.json,src%2Fcomponents%2FHelloWorld.vue
In vue 2 it work, bot in vue 3 dont
Your slot binding is wrong.
Check the Docs: Vue - Named Slots and Vue-Select - Slots - option
This
<template slot="option" slot-scope="option">
should be written so
<template v-slot:option="option">
or so (using the shorthand #)
<template #option="option">
Then it works:
UPDATE:
slot-scope was deprecated in Vue2
Using the following version
"vue-select": "^4.0.0-beta.5"
And installing like that in main.js
import { createApp } from "vue"
import vSelect from "vue-select"
import App from "./App.vue"
const app = createApp(App)
app.component("v-select", vSelect)
app.mount("#app")
You can then use the following
<template>
<v-select :options="options" label="title">
<template #option="option">
<span><img :src="option.image" />{{ option.title }}</span>
</template>
</v-select>
</template>
<script>
export default {
data() {
return {
options: [
{
title: "Read the Docs",
image: "https://source.unsplash.com/random/20x20?sig=1",
url: "https://codeclimate.com/github/sagalbot/vue-select",
},
{
title: "View on GitHub",
image: "https://source.unsplash.com/random/20x20?sig=2",
url: "https://codeclimate.com/github/sagalbot/vue-select",
},
{
title: "View on NPM",
image: "https://source.unsplash.com/random/20x20?sig=3",
url: "https://codeclimate.com/github/sagalbot/vue-select",
},
{
title: "View Codepen Examples",
image: "https://source.unsplash.com/random/20x20?sig=4",
url: "https://codeclimate.com/github/sagalbot/vue-select",
},
],
};
},
};
</script>
For this kind of result
PS: be careful, some examples in the documentation are indeed not up to date regarding Vue's API, especially slot-scope as explained here (not available anymore in Vue3).
Related
Is there a way to pass information down though components in storybook that do not inheartly pass props though.
A proacticle example of this being that i have a language select button (usually pulls its information from a store so no information is passed to it), for storybook i have some props avaiable for this so i can run tests etc without having dirrect access to the store. this component on its own works fine.
On top of this i have a header nav bar that utlises this component, but does not pass informaton to it (as its self managed), however when trying to now set this component up in storybook the language select does not display as not having data.
I was reading though the multi-component documentation but struggling to get this to work for this use case and begining to wonder if this is going to be possiable and if so whats the best way to approach this.
in terms of code this is what i currently have
//header.vue
<template>
<div class="HeaderComponent">
//other component code here
<language-selector/>
</div>
</div>
</nav>
</div>
</template>
<script setup lang="ts">
import LanguageSelector from "#/components/HeaderAndFooter/LanguageSelector.vue";
import _ from "underscore";
import ImageModel from "#/helpers/classes/core/ImageModel";
import { defineProps } from "vue";
import HeaderNavigation from "#/helpers/classes/Navigation/HeaderNavigation";
// eslint-disable-next-line no-unused-vars
const props = defineProps({
menu: {
type: Object as () => {[key: string]: HeaderNavigation} | undefined,
default: undefined
},
icon: {
type: Object as () => ImageModel | undefined,
default: undefined
}
})
</script>
///languageSelector.vue
<template>
<div class="languageSelector" v-if="props.languages.length > 1">
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle" type="button" id="languageDropdownButton" data-bs-toggle="dropdown" aria-expanded="false">
{{currentLang.name}}
</button>
<ul class="dropdown-menu" aria-labelledby="languageDropdownButton">
<li v-for="language in props.languages" :key="language.i18n">
<a class="dropdown-item" href="#" #click="ChangeLanguage(language.i18n)">{{language.name}}</a>
</li>
</ul>
</div>
</div>
</template>
<script setup lang="ts">
import {useLanguageStore} from "#/store/languageStore";
import {computed, defineProps} from "vue";
import Language from "#/helpers/classes/Language";
const props = defineProps({
languages: {
languages: Object as () => Language[],
default: useLanguageStore().availableLanguages
},
})
const currentLang = computed(() => useLanguageStore().currentLanguage);
function ChangeLanguage(i18nCode : string)
{
useLanguageStore().updateCurrentLanguage(i18nCode);
}
</script>
///header.story.js
import LanguageSelector from "#/components/HeaderAndFooter/LanguageSelector.vue";
import { DefaultLangSelector } from './LanguageSelector.stories.js';
// More on default export: https://storybook.js.org/docs/vue/writing-stories/introduction#default-export
export default {
title: 'Framework/Header',
component: HeaderComponent,
// More on argTypes: https://storybook.js.org/docs/vue/api/argtypes
argTypes: {},
};
// More on component templates: https://storybook.js.org/docs/vue/writing-stories/introduction#using-args
const Template = (args) => ({
components: { HeaderComponent, LanguageSelector },
setup() {
return { args };
},
template: '<header-component v-bind="args" />',
});
export const Primary = Template.bind({});
Primary.args = {
menu: {
"Item 1": {
"children": {},
"id": "1",
"title": "Item 1"
},
"Item 2": {
"children": {},
"id": "2",
"title": "Item 2"
}
},
icon:
{
"url": "https://th.bing.com/th/id/R.25df89f6bbce9ce2324fb746d01940ea?rik=WpLZgCWrgPXbLA&pid=ImgRaw&r=0"
},
...DefaultLangSelector.args = {
languages: [
{"name" : "English", "i18n" : "en"},
{"name" : "Spanish", "i18n" : "es"},
],
}
};
I'm creating a blog with free sewing patterns as content. I'm using route parameters to receive each blog individually. However, I'm getting a blank page when trying to retrieve its data from firebase firestore. Please help.
The blog's id appears on my address bar:
http://localhost:8080/#/admin/single-pattern/4LIS362IEWa7RKEv79g8
But it renders a blank page. I cant see my blog content.
This is my route path code. I've added a parameter of :id in my singlepattern. The SinglePattern component is where I will get the individual blog's data:
{
path: "/admin",
name: "admin",
component: Admin,
meta: {
auth: true,
},
children: [
{
path: "dashboard",
name: "dashboard",
component: Dashboard,
},
{
path: "manage-patterns",
name: "manage-patterns",
component: ManagePatterns,
},
{
path: "single-pattern/:id",
name: "single-pattern",
component: SinglePattern,
},
],
},
Here is my "ListPattern" component's code. ListPattern is where all my sewing blogs are displayed.
<template>
<div class="list-blogs">
<h1>LIST BLOG TITLES</h1>
<br />
<input type="text" v-model="search" placeholder="search blogs" />
<div
class="blog-cover"
v-for="pattern in filteredPatterns"
:key="pattern.id"
>
<div>
<router-link v-bind:to="'/admin/single-pattern/' + pattern.id">
<h3 style="cursor: pointer" v-rainbow>
{{ pattern.title | uppercase }}
</h3></router-link
>
</div>
<p
:style="'background-color: var(--lightgrey)'"
:inner-html.prop="pattern.description | snippet"
></p>
</div>
</div>
</template>
<script>
import firebase from "firebase";
import searchMixin from "../mixins/searchMixin";
// Basic Use - Covers most scenarios
import { VueEditor } from "vue2-editor";
import Quill from "quill";
const AlignStyle = Quill.import("attributors/style/align");
Quill.register(AlignStyle, true);
// import $ from "jquery";
import Swal from "sweetalert2";
window.Swal = Swal;
const Toast = Swal.mixin({
toast: true,
position: "top-end",
showConfirmButton: false,
timer: 3000,
});
window.Toast = Toast;
export default {
name: "ManagePatterns",
components: { VueEditor },
data() {
return {
patterns: [],
pattern: {
title: null,
description: null,
image: null,
},
search: "",
};
},
firestore() {
return {
patterns: firebase.firestore().collection("free-patterns"),
};
},
computed: {},
},
};
</script>
And this is my 'SinglePattern' component where the clicked blog/pattern is displayed.
<template>
<div class="single-pattern">
<div class="blog-cover">
<div>
</div>
<div v-if="pattern">
<h3 style="cursor: pointer">
{{ pattern.title }}
</h3>
<div v-if="pattern.description">
<p
:style="'background-color: var(--lightgrey)'"
:inner-html.prop="pattern.description"
></p>
</div>
</div>
</div>
</div>
</template>
<script>
import firebase from "firebase";
import searchMixin from "../../mixins/searchMixin";
export default {
data() {
return {
id: this.$route.params.id,
patterns: [],
pattern: {
title: null,
description: null,
image: null,
},
};
},
firestore() {
return {
patterns: firebase.firestore().collection("free-patterns"),
};
},
mixins: [searchMixin],
created() {
console.log(this.$route.params.id);
var pat = this;
firebase
.firestore()
.collection("free-patterns")
.doc(this.$route.params.id)
.get()
.then(function(doc) {
if (doc.exists) {
pat.pattern = doc.data().pattern;
} else {
console.log("no such doc");
}
});
},
methods: {},
};
</script>
It works. I just had to change the code in my created() hook in 'SingePattern' component.
created() {
console.log(this.$route.params.id);
var docRef = firebase
.firestore()
.collection("free-patterns")
.doc(this.$route.params.id);
docRef
.get()
.then((doc) => {
if (doc.exists) {
this.pattern = doc.data();
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
})
.catch((error) => {
console.log("Error getting document:", error);
});
I am trying to add Full Calendar to my Nuxt project. Here is my code.
<template>
<div>
<!-- {{calendarOptions}} -->
<FullCalendar :options="calendarOptions" />
</div>
</template>
<script>
import FullCalendar from '#fullcalendar/vue'
import dayGridPlugin from '#fullcalendar/daygrid'
import interactionPlugin from '#fullcalendar/interaction'
import timeGridPlugin from '#fullcalendar/timegrid'
export default {
components: {
FullCalendar, // make the <FullCalendar> tag available
},
data() {
return {
allevents: [{ title: 'Event 2', start: '2021-01-04', end: '2021-01-07' },
{ title: 'Event 3', start: '2021-01-05', end: '2021-01-09' }],
calendarOptions: {
plugins: [dayGridPlugin, interactionPlugin, timeGridPlugin],
initialView: 'dayGridMonth',
nowIndicator: true,
events: [
{ title: 'Event 1', start: '2021-01-01', end: '2021-01-03' },
],
},
}
},
}
</script>
I want to add data in allevents array to events array inside calenderOptions object.
Can anyone please tell me how I can do this?
Create a method to push data from your allevents array to the calendarOptions.events array.
methods: {
doTheThing() {
this.allevents.forEach(event => {
this.calendarOptions.events.push(event)
}
}
}
I'm trying to create a custom WordPress gutenberg block that allows me to select any image and text.
I can create the block using this code and I can see content on the frontend of the site however the block crashes if I view the block to edit it.
The console gives the following error: -
Block validation: Block validation failed for cgb/block-imagecta (
Object { name: "cgb/block-imagecta", icon: {…}, attributes: {…}, keywords: (3) […], save: save(), title: "imagecta - CGB Block", category: "common", edit: edit()
}
).
Content generated by save function:
<div class="wp-block-cgb-block-imagecta"><div class="imageCtaBg"><img class="bg" alt="sergserge"/><p></p></div></div>
Content retrieved from post body:
<div class="wp-block-cgb-block-imagecta"><div class="imageCtaBg"><img class="bg" alt="sergserge"/><p>dxfbxdfbxdfbfb</p></div></div>
Is this related to the attributes at all?
/**
* BLOCK: imagecta
*
* Registering a basic block with Gutenberg.
* Simple block, renders and saves the same content without any interactivity.
*/
// Import CSS.
import './editor.scss';
import './style.scss';
const {__} = wp.i18n; // Import __() from wp.i18n
const {registerBlockType} = wp.blocks; // Import registerBlockType() from wp.blocks
const {FormFileUpload} = wp.components;
const {RichText, MediaUpload} = wp.blockEditor;
registerBlockType('cgb/block-imagecta', {
title: __('imagecta - CGB Block'),
icon: 'shield',
category: 'common',
keywords: [
__('imagecta — CGB Block'),
__('CGB Example'),
__('create-guten-block'),
],
attributes: {
content: {
type: 'html',
selector: '.captionText',
},
logo: {
type: 'string',
default: null,
},
},
edit: (props) => {
const {attributes: {content}, setAttributes} = props;
function onImageSelect(imageObject) {
setAttributes({
logo: imageObject.sizes.full.url
});
}
const onChangeContent = (newContent) => {
setAttributes({content: newContent});
};
// Creates a <p class='wp-block-cgb-block-imagecta'></p>.
return (
<div className={props.className}>
<MediaUpload
onSelect={onImageSelect}
type="image"
value={logo} // make sure you destructured backgroundImage from props.attributes!
render={({open}) => (
<button onClick={open}>
Upload Image!
</button>
)}
/>
<div className='imageCtaBg'>
<img src={logo} class="bg" alt={'sergserge'}/>
<RichText
tagName={'p'}
className='captionText'
onChange={onChangeContent}
value={content}
placeholder='Enter text...'
/>
</div>
</div>
);
},
save: (props) => {
const {attributes: {content}, setAttributes} = props;
return (
<div className={props.className}>
<div className={'imageCtaBg'}>
<img src={props.attributes.logo} className="bg" alt={'sergserge'}/>
<RichText.Content tagName={"p"} value={props.attributes.content}/>
</div>
</div>
);
},
});
The issue was to do with the content attribute.
Instead of giving the richtext the class of 'captionText' I moved it do a wrapping div and changed the content attribute to the following: -
content: {
type: 'string',
source:'html',
selector: '.captionText',
},
This finds the text inside of that div and allows me to update the block with no validation issues.
The data is not showing, I do not know how to push the value from the firebase to the v-data-table values. Here is my code.
<template>
<div class="dashboard">
<h2 class="subheading mx-5">Subject</h2>
<v-btn block color="primary mt-5" #click="enrollSubjects()">Enroll Subjects</v-btn>
<v-container class="my-5">
<template>
<v-card>
<v-card-title>
Courses
<v-spacer></v-spacer>
<v-text-field v-model="search" append-icon="search" label="Search" single-line hide-details></v-text-field>
</v-card-title>
<v-data-table v-model="selected" :headers="headers" :items="courses" show-select :single-select="singleSelect" item-key="descrip_title" :search="search">
</v-data-table>
</v-card>
</template>
</v-container>
</div>
</template>
<script>
// # is an alias to /src
import db from '#/firebase/init'
export default {
name: 'dashboard',
data(){
return{
search: '',
singleSelect: false,
subjects: [],
selected: [],
headers: [
{text: 'Control No.', value: 'controlno'},
{text: 'Course No.', value: 'courseno'},
{text: 'Descriptive Title', value: 'descrip_title'},
{text: 'Schedule(In)', value: 'schedin'},
{text: 'Schedule(Out)', value: 'schedout'},
{text: 'Room No.', value: 'roomno'},
{text: 'Days', value: 'days'},
{text: 'Units', value: 'units'}
],
courses: []
}
},
methods:{
enrollSubjects(){
if(this.selected === this.selected){
this.$swal({
title: 'No Course Selected',
text: 'Please select course/s',
type: 'error'
})
}
},
created(){
db.collection('masterlist_courses').get()
.then(snapshot => {
snapshot.forEach(doc => {
let course = doc.data()
course.id = doc.id
this.courses.push(course)
})
})
}
}
}
</script>
I am practicing in firebase and vuetify, I do not know how to push this to the value of the v-data-table. I am having hard time and its not showing anything to the datatable and also there is no error. It's not saying anything after I code the data in the firebase not displaying
You need to use one of the vue.js life cycle hook to trigger the fetch before the component is mounted.
For example the created hook can be used to "run code after an instance is created", as follows:
<script>
// # is an alias to /src
import db from '#/firebase/init'
export default {
name: 'dashboard',
data(){
return{
search: '',
singleSelect: false,
subjects: [],
selected: [],
headers: [
{text: 'Control No.', value: 'controlno'},
{text: 'Course No.', value: 'courseno'},
{text: 'Descriptive Title', value: 'descrip_title'},
{text: 'Schedule(In)', value: 'schedin'},
{text: 'Schedule(Out)', value: 'schedout'},
{text: 'Room No.', value: 'roomno'},
{text: 'Days', value: 'days'},
{text: 'Units', value: 'units'}
],
courses: []
}
},
methods:{
enrollSubjects(){
if(this.selected === this.selected){
this.$swal({
title: 'No Course Selected',
text: 'Please select course/s',
type: 'error'
})
}
}
},
created: function() {
db.collection('masterlist_courses').get()
.then(snapshot => {
snapshot.forEach(doc => {
let course = doc.data()
course.id = doc.id
this.courses.push(course)
})
})
}
}
</script>
Note that if the query to Firestore is going to take some time, you could display a spinner and hide it when the query is done, i.e. in the callback passed to then(), after snapshot.forEach().
You need to define what items should be shown. You have only defined your headers so far. Try it like this for every header you have.
<template v-slot:item.controlno="{ item }">
{{ item.controlno }}
</template>
Hope this helps =)