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
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
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
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.
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>
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.