How to use the WIZARD component in vue3 correctly - javascript

I am using the wizard component, which is a step by step, I am placing a select in each tab, but I have the problem that only the select of the first tab is shown, how could I solve this problem?
component:https://bahadirsofuoglu.github.io/form-wizard-vue3/guide/installation.html
I attach my code:
<template>
<div id="app">
<div>
<h1>Customize with Props</h1>
<Wizard
squared-tabs
card-background
navigable-tabs
scrollable-tabs
:nextButton="{
text: 'test',
icon: 'check',
hideIcon: true, // default false but selected for sample
hideText: false, // default false but selected for sample
}"
:custom-tabs="[
{
title: 'Step 1',
},
{
title: 'Step 2',
},
]"
:beforeChange="onTabBeforeChange"
#change="onChangeCurrentTab"
#complete:wizard="wizardCompleted"
>
<template v-if="currentTabIndex === 0">
<h5>Tab 0</h5>
<v-select
:items="options"
label="Select an option"
v-model="selectedOption"
></v-select>
</template>
<template v-if="currentTabIndex === 1">
<h5>Tab 1</h5>
<v-select
:items="options"
label="Select an option"
v-model="selectedOption"
></v-select>
</template>
</Wizard>
</div>
</div>
</template>
<script>
import "form-wizard-vue3/dist/form-wizard-vue3.css";
import Wizard from "form-wizard-vue3";
export default {
name: "App",
components: {
Wizard,
},
data() {
return {
currentTabIndex: 0,
options: ["Option 1", "Option 2", "Option 3"],
selectedOption: "",
};
},
methods: {
onChangeCurrentTab(index, oldIndex) {
console.log(index, oldIndex);
this.currentTabIndex = index;
},
onTabBeforeChange() {
if (this.currentTabIndex === 0) {
console.log("First Tab");
}
console.log("All Tabs");
},
wizardCompleted() {
console.log("Wizard Completed");
},
},
};
</script>
attached image:
tab 1:
tab2:

From quick look at the documentation it seems that you need all of the steps content to be wrapped with <template #activeStep>. And then inside your v-if logic probably.

Related

How to autofocus Quill Editor in Vue.js?

I'm using quill with vue 3 and can't find a way to autofocus the editor input field in their docs.
I've tried targeting parent elements with:
document.getElementById(...).focus()
which did nothing. This is how I've implemented quill, text-editor.vue:
<template>
<div id="text-editor" class="text-editor">
<quill-editor :modules="modules" :toolbar="toolbar"/>
</div>
</template>
<script setup>
import BlotFormatter from 'quill-blot-formatter'
const modules = {
module: BlotFormatter,
}
const toolbar = [
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
[{ 'size': ['small', false, 'large', 'huge'] }],
['bold', 'italic', 'underline', 'strike'],
['blockquote', 'code-block'],
[{ 'align': [] }],
[{ 'list': 'ordered'}, { 'list': 'bullet' }],
[{ 'color': [] }, { 'background': [] }],
[{ 'font': [] }],
['link', 'image', 'video'],
['clean']
];
</script>
and import it in component.vue:
<template>
<div id="component">
<text-editor/>
</div>
</template>
<script setup>
import textEditor from './text-editor'
</script>
Any idea how to autofocus quill?
I found the solution. Just use the #onReady event. As simple as this:
<QuillEditor
theme="snow"
#ready="onReady"
/>
Then add the method:
methods: {
onReady(editor) {
editor.focus();
},
},
You can access the quill instance with getQuill() API and then use quill.focus() to focus the quill editor, here is an example:
<template>
<QuillEditor
ref="quillEditor"
theme="snow"
:options="options"
#ready="onQuillReady"
/>
</template>
<script setup>
import { ref } from "vue";
import { QuillEditor } from "#vueup/vue-quill";
import "#vueup/vue-quill/dist/vue-quill.snow.css";
const quillEditor = ref(); // editor ref
const options = {
// ... options for quill editor ...
}
function onQuillReady() {
// focus editor when it is ready
quillEditor.value.getQuill().focus();
}
</script>
Ref: https://vueup.github.io/vue-quill/api/methods.html#getquill

Set checkbox selected in Vue

I am beginner in vue and web developing. I make my app with Laravel and Vue.
I have this code:
created: function () {
let self = this;
self.setActive('tab1');
axios.get(this.$apiAdress + '/api/tasks/create?token=' + localStorage.getItem("api_token"))
.then(function (response) {
self.documentDircionary = response.data.documentDircionary;
self.selectedDocumentDircionary = response.data.selectedDocumentDircionary;
}).catch(function (error) {
console.log(error);
self.$router.push({path: '/login'});
});
<template v-for="(option) in documentDircionary">
<div class="form-group form-row" :key="option.name">
<CCol sm="12">
<input type="checkbox" name="selectedDocuments[]" :id="option.value" /> {{ option.label }}
</CCol>
</div>
</template>
This code show me inputs - and it's work fine.
I have problem with set selected attribute for selected checkbox.
In array selectedDocumentDircionary results from api:
"selectedProducts": [1,2,43]
How can I set checked for only this checkbox, witch selectedProducts?
Please help me
You can use :checked attribute to marked the checkbox checked as per the selectedProducts you have.
Working Demo :
const app = new Vue({
el: '#app',
data() {
return {
selectedProducts: [1, 2, 43],
documentDircionary: [{
name: 'checkbox1',
value: 1,
label: 'Checkbox 1'
}, {
name: 'checkbox2',
value: 2,
label: 'Checkbox 2'
}, {
name: 'checkbox3',
value: 3,
label: 'Checkbox 3'
}, {
name: 'checkbox4',
value: 4,
label: 'Checkbox 4'
}, {
name: 'checkbox43',
value: 43,
label: 'Checkbox 43'
}]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.0/vue.js"></script>
<div id="app">
<template v-for="option in documentDircionary">
<div :key="option.name">
<input type="checkbox" name="selectedDocuments[]" :id="option.value" :checked="selectedProducts.includes(option.value)" /> {{ option.label }}
</div>
</template>
</div>
You can set :checked based on if the id of the current element is in the array:
<template v-for="(option) in documentDircionary">
<div class="form-group form-row" :key="option.name">
<CCol sm="12">
<input type="checkbox" name="selectedDocuments[]" :id="option.value" :checked="selectedProducts.includes(option.value)" /> {{ option.label }}
</CCol>
</div>
</template>

Adjust the select box when option value is bigger using element ui

Adjust the select box when option value is bigger using element ui
How this is possible please guide
It should not cut the string after selection
<template>
<el-select v-model="value" placeholder="Select">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
</div>
var Main = {
data() {
return {
options: [{
value: 'OptionFirstWithBigCharacter',
label: 'OptionFirstWithBigCharacter'
}, {
value: 'Option2',
label: 'Option2'
}, {
value: 'Option3',
label: 'Option3'
}, {
value: 'Option4',
label: 'Option4'
}, {
value: 'Option5',
label: 'Option5'
}],
value: ''
}
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
#import url("//unpkg.com/element-ui#2.7.2/lib/theme-chalk/index.css");
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui#2.7.2/lib/index.js"></script>
<div id="app">
<template>
<el-select v-model="value" placeholder="Select">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
</div>
"OptionFirstWithBigCharacter" should display properly
Add some padding to the select input as follows :
.el-select>.el-input {
display: block;
padding-right: 2px;
}
var Main = {
data() {
return {
options: [{
value: 'OptionFirstWithBigCharacter',
label: 'OptionFirstWithBigCharacter'
}, {
value: 'Option2',
label: 'Option2'
}, {
value: 'Option3',
label: 'Option3'
}, {
value: 'Option4',
label: 'Option4'
}, {
value: 'Option5',
label: 'Option5'
}],
value: ''
}
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
#import url("//unpkg.com/element-ui#2.7.2/lib/theme-chalk/index.css");
.el-select>.el-input {
display: block;
padding-right: 8px;
}
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui#2.7.2/lib/index.js"></script>
<div id="app">
<template>
<el-select v-model="value" placeholder="Select">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
</div>
That's an interesting question.
Obviously, the solution would be to calculate the text width of selected value and adjust select to this width, but that's a tricky task.
Under the hood el-select uses <input> element to show selected item, and <input> can't adjust its width based on its value, so we'd need to use another element that can do that. For example, <span> is good choice.
Here is what I've got:
Vue.config.productionTip = false;
var Main = {
data() {
return {
options: [{
value: 'OptionFirstWithBigCharacter',
label: 'OptionFirstWithBigCharacter'
}, {
value: 'Option2',
label: 'Option2'
}, {
value: 'Option3',
label: 'Option3'
}, {
value: 'Option4',
label: 'Option4'
}, {
value: 'Option5',
label: 'Option5'
}],
value: ''
}
},
mounted() {
// pass true to make input use its initial width as min-width
this._addShadow();
},
methods: {
_getElements() {
// helper method to fetch input and its shadow span
const input = this.$refs.resizeable.$el.querySelector('.el-input__inner');
const span = input.previousSibling;;
return { input, span };
},
_addShadow(useMinWidth = false) {
// this method adds shadow span to input
// we'll use this span to calculate text width
const { input } = this._getElements();
const span = document.createElement('span');
span.classList.add('resizeable-shadow');
input.parentNode.insertBefore(span, input);
// copy font, padding and border styles from input
const css = input.computedStyleMap();
span.style.font = css.get('font');
span.style.padding = css.get('padding');
span.style.border = css.get('border');
if (useMinWidth) {
span.style.minWidth = `${input.getBoundingClientRect().width}px`;
}
},
_adjustSize() {
this.$nextTick(() => {
const { input, span } = this._getElements();
span.textContent = input.value;
input.style.width = `${span.getBoundingClientRect().width}px`;
});
},
},
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
#import url("//unpkg.com/element-ui#2.7.2/lib/theme-chalk/index.css");
span.resizeable-shadow {
display: inline-block;
box-sizing: border-box;
position: absolute;
left: -99999px;
top: -99999px;
}
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui#2.7.2/lib/index.js"></script>
<div id="app">
<template>
<el-select v-model="value" placeholder="Select"
ref="resizeable" #change="_adjustSize">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</template>
</div>
Code is pretty simple and I've added some comments, so it shouldn't be hard to adjust it to your needs: move it to mixin, add support for multiple selects etc.
Popper works weird in SO snippet, so here is working jsfiddle.

Vuejs add and remove classes with v-for

i'm making a list of items with vuejs v-for loop. I have some API data from server.
items: [
{
foo: 'something',
number: 60
},
{
foo: 'anything',
number: 15
},
{
foo: 'text',
number: 20,
}
]
Template
<div v-for="(item,index) in items" :key="index">
<div :class="{ active: ????}" #click="toggleActive">
{{ item.foo }}
{{ item.number }}
</div>
</div>
JS
methods: {
toggleActive() {
//
}
}
I need following: When i'm clicking on div add class active, if i have already active class - remove active class.( toggle ). Also i can select multiple items.
How can i do this? I don't have boolean variable in items array, and i shouldn't move item in a separate component
Here you go.
new Vue({
el: "#app",
data: {
items: [{
foo: 'something',
number: 60
},
{
foo: 'anything',
number: 15
},
{
foo: 'text',
number: 20,
}
]
},
methods: {
toggleActive(index) {
let item = this.items[index];
item.active = !item.active;
this.$set(this.items, index, item);
}
}
})
.active {
color: red;
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.17/dist/vue.js"></script>
<div id="app">
<div v-for="(item,index) in items" :key="index">
<div :class="{ active: item.active}" #click="toggleActive(index)">
{{ item.foo }} {{ item.number }}
</div>
</div>
</div>
Here's a JS Fiddle:
https://jsfiddle.net/eywraw8t/250008/
App.vue
<template>
<div>
<div
v-for="(item, i ) in items"
:key="i"
:class="{ active: i === activeItem}"
>
// some looped items from data here
// button for active toggle
<button #click="selectItem(i)"> make item active </button>
</div>
</div>
</template>
Data and Methods
<script>
export default {
data() {
return {
activeItem: null,
};
},
methods: {
selectItem(i) {
this.activeItem = i;
},
},
};
</script>

Vue.js survey using browser back/forward buttons

I'm using Vue.js to create a survey with multiple pages. Everything works, except I need to make browser back/forward buttons to do the same as Previous/Next buttons on the page.
I have googled multiple times, but I couldn't come up with any solution for the moment...
I know that I could use vue-router, but I don't know how to adapt it.
How can I achieve this?
HTML
<!DOCTYPE html>
***head***
<body>
<div id="app">
<h1>{{ survey.title }}</h1>
<div id="survey" v-for="(question, index) in survey.questions">
<div v-show="index === questionIndex">
<h3>{{ question.text }}</h3>
<div v-if="questionIndex === 2">
<input type="text" v-model="userResponses[2]" placeholder="Please enter your location:">
</div>
<div v-else-if="questionIndex === 4">
<select v-model="question4" multiple>
<option v-for="response in question.responses"> {{ response.text }} </option></select>
</div>
<div v-else-if="questionIndex === 5">
<select v-model="question5" multiple>
<option v-for="response in question.responses"> {{ response.text }} </option></select>
</div>
<div v-else>
<ol>
<li v-for="response in question.responses">
<label>
<input type="radio" v-bind:value="response"
v-bind:name="index"
v-model="userResponses[index]"> {{ response.text }}
</label>
</li>
</ol>
</div>
<div id="container">
<button id="left" v-if="questionIndex > 0" v-on:click="prev">Previous</button>
<button id="right" v-on:click="next">Next</button>
</div>
</div>
</div>
<div v-show="questionIndex === survey.questions.length">
<h2>Thank you for taking our survey!</h2>
<p>{{ userResponses }}</p>
<p>{{ question4 }}</p>
<p>{{ question5 }}</p>
</div>
</div>
<footer>© 2018 George Salukvadze for ***</footer>
</body>
</html>
Vue.js
window.onload = survey;
function survey(){
var survey = {
title: 'Welcome to online survey for Liquid!',
questions: [
{
text: "What is your age group?",
responses: [
{text: '15-24'},
{text: '25-34'},
{text: '35-44'},
]
}, {
text: "What is your gender?",
responses: [
{text: 'Male'},
{text: 'Female'},
{text: 'Do not identify'},
]
}, {
text: "Where do you live?",
responses: [
{text: 'Please enter your location'},
]
}, {
text: "Do you like to shop?",
responses: [
{text: 'Yes'},
{text: 'No'},
]
}, {
text: "Select your favorite things to buy:",
responses: [
{text: 'Clothing'},
{text: 'Lingerie'},
{text: 'Shoes'},
{text: 'Devices'},
{text: 'Cars'},
]
}, {
text: "Please select your favorite brands:",
responses: [
{text: 'Sandro'},
{text: 'Maje'},
{text: 'Sony'},
{text: 'Ferrari'},
{text: 'BMW'},
{text: 'Asus'},
]
}
]
};
new Vue({
el: '#app',
data: {
survey: survey,
questionIndex: 0,
userResponses: Array(survey.questions.length),
question4: Array(5),
question5: Array(9),
},
methods: {
next: function() {
this.questionIndex++;
},
prev: function() {
this.questionIndex--;
}
}
});
}
You could use the vue-router as you implied. The simplest solution for your example, though, is to just use the browser's history API. Steps:
When moving to previous/next questions, use history.pushState to add a state to the browser's history:
methods: {
next: function() {
this.questionIndex++;
this.updateHistory(); // added this line
},
prev: function() {
this.questionIndex--;
this.updateHistory(); // added this line
},
updateHistory: function() { // added this method
history.pushState({questionIndex: this.questionIndex}, "Question " + this.questionIndex);
}
}
And now all you have to do is listen to those history state changes. A good spot to hook a listener to this event is the mounted:
mounted: function() {
var vm = this;
window.addEventListener('popstate', function(event) {
vm.questionIndex = (event.state || {questionIndex: 0}).questionIndex;
});
},
And that's it.
Click here for the a demo page at JSBin (check the history button).
You'll find the source for that demo here.

Categories

Resources