How initialize tabs when state changes in vue? - vue.js

Here is sample of my code in vue.
<template>
<tabs>
<tab
v-for="c in myCount"
:key="c"
:name="c"
:selected="c === 1"
>
{{ c }}
</tab>
</tabs>
<button type="button" #click="showOneTab">Show just one tab</button>
</template>
<script>
export default {
name: 'myComponent',
data: {
return {
myCount: 5
}
},
methods: {
showOneTab() {
this.myCount = 1
}
}
}
</script>
myCount has default value of 5. after clicking a button it changes to 1. I need to tabs be removed and just the first appears.

Your code looks correct. But it doesn't work, you can try a computed property:
v-for="c in count"
computed: {
count() {
return myCount
}
}

Your data option should be a function that returns an object data(){ return { myCount: 5 } } not a field with object as value :
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: '#app',
data(){
return {
myCount: 5
}
},
methods: {
showOneTab() {
this.myCount = 1
}
}
})
<link type="text/css" rel="stylesheet" href="//unpkg.com/bootstrap/dist/css/bootstrap.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<div id="app" class="container">
<div v-for="c in myCount" :key="c">
{{ c }}
</div>
<button type="button" #click="showOneTab">Show just one tab</button>
</div>

Related

How can I show div onlick in Vue.js?

I want to display divreg template when someone click this button. My problem is that I dont know how to write in in this method.
const divreg = {
name: "divreg",
template: `
<div>
Hello
</div> `
};
var app = new Vue({
el: "#app",
components: {
divreg
},
data: {
message: "Załóż konto!"
},
methods: {
handleClick() {
//here I need to code to show this template onlick
}
},
template: `
<div>
<h1> {{message}} </h1>
<divreg />
<button #click="handleClick"> Zarejestruj się</button>
</div>
`
});
you can use v-if to show or hide the element, in your case it will something like this:
<divreg v-if="showElement" />
<button #click="handleClick"> Zarejestruj się</button>
data: () => ({
showElement: false
})
methods: {
handleClick() {
this.showElement = true
}
}
<template>
<divreg v-if="showElement" />
<button #click="showElement !== showElement">Zarejestruj się</button>
</template>
<script>
export default {
data: () => ({
showElement: false
}),
}
</script>

Update properties of component in Vue.js

I've been searching for the answer 2nd day. But still couldn't find solution.
I have the modal window template. And the main page template from where I need to update modal window size by clicking on the button (span). Shortly it's like this for HTML:
<template id="modal">
<div>
<div :class="'modal-' + size">
...
</div>
</div>
</template>
<template id="list">
<div>
<span #click="onDetails">
Show Details
</span>
</div>
<modal size="md" #showdetails="showdetails();" ref="modal">
...
</modal>
</template>
And for JS:
Vue.component("modal", {
template: "#modal",
props: {
size: {
type: String,
default: ""
}
},
methods: {
onDetails() {
this.$emit("showdetails")
}
}
})
var List = Vue.extend({
template: "#list",
methods: {
showDetails() {
if(this.$refs.modal.size == "md") {
this.$refs.modal.size = "lg"
}
<additional code here>
}
}
})
When I'm accessing this.$refs.modal.size for read - it's OK. When I'm just changing it from showDetails - OK if only this action in the function. When I'm put something else instead of - size is not updating.
For example:
this.$refs.modal.size = "lg" - will work
this.$refs.modal.theme = "danger"; this.$refs.modal.size = "lg" - neither of them are updating
What am I doing wrong?
You need to assign the attribute value of Size by the javascript method setAttribute . Example : this.$refs.modal.setAttribute('size', 'lg')
There is a working demo below:
new Vue({
el: '#app',
methods: {
showdetails() {
console.log(this.$refs.modal.getAttribute('size'));
this.$refs.modal.setAttribute('size', 'lg')
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.15/vue.js"></script>
<div id='app'>
<button size="md" #click="showdetails" ref="modal">Click</button>
</div>

Computed property setter creates Maximus stack exceeded

I have such code:
<div id="app">
<b-form-group label="Sorting">
<b-form-checkbox-group
v-model="sorting"
:options="filterData.sorting"
/>
</b-form-group>
</div>
new Vue({
el: '#app',
computed: {
sorting: {
get: function () {
return this.filterInput.sorting
},
set: function (value) {
// this array needs to always have only one value
this.filterInput.sorting = [value[0]]
}
}
},
data () {
return {
filterData: {
sorting: ['PRICE_ASC', 'PRICE_DESC']
},
filterInput: {
sorting: []
}
}
}
})
https://jsfiddle.net/pum86bsx/1/
Error seems to be in computed getter. When I comment it out it's all good. I have no idea why it's like that.
You setting the value of the v-model (the value returned in the getter), which will cause the setter to fire again.. and again.. and again.. Causing your stack to overflow.
Using checkboxes
You could instead use the #change event, which should only fire when the value actually changes.
new Vue({
el: '#app',
data () {
return {
filterData: {
sorting: ['PRICE_ASC', 'PRICE_DESC']
},
filterInput: {
sorting: []
}
}
},
methods: {
onChange(value) {
if(value.length === 0) {
this.filterInput.sorting = value
} else {
this.filterInput.sorting = [value[value.length - 1]]
}
}
}
})
<link href="https://unpkg.com/bootstrap#4.5.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue#2.15.0/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.15.0/dist/bootstrap-vue.js"></script>
<div id="app">
<b-form-group label="Sorting">
<b-form-checkbox-group
v-model="filterInput.sorting"
:options="filterData.sorting"
#change="onChange"
></b-form-checkbox-group>
</b-form-group>
</div>
Using radio buttons
Alternatively you could use radio buttons, which only allows one to be selected at a time, so you don't have to handle that yourself.
new Vue({
el: '#app',
data () {
return {
filterData: {
sorting: ['PRICE_ASC', 'PRICE_DESC']
},
filterInput: {
sorting: []
}
}
}
})
<link href="https://unpkg.com/bootstrap#4.5.0/dist/css/bootstrap.min.css" rel="stylesheet" />
<link href="https://unpkg.com/bootstrap-vue#2.15.0/dist/bootstrap-vue.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.js"></script>
<script src="https://unpkg.com/bootstrap-vue#2.15.0/dist/bootstrap-vue.js"></script>
<div id="app">
<b-form-group label="Sorting">
<b-form-radio-group
v-model="filterInput.sorting"
:options="filterData.sorting"
></b-form-radio-group>
</b-form-group>
</div>

Vue v-for conditional styling

I use v-for to create buttons. I add the .active class if isActiveButton() returns true:
<button
v-for="(text, index) in this.buttonOptions"
class="btn"
:class="{active: isActiveButton(text)}"
:value='text'
#mousedown.prevent #click="some_method">
{{text}}
</button>
What is the best way to add the .active class to the first button if isActive() returns false for all buttonOptions? Note that the buttonOptions is a prop.
A Computed Property would be the way to go!
var app = new Vue({
el: '#app',
data: {
buttonOptions: ['button1', 'button2', 'button3', 'button4']
},
methods: {
isActiveButton: function (text) {
return (text === text.toUpperCase());
},
some_method: function() {
console.log('Button clicked')
}
},
computed: {
shouldFirstBeActive: function () {
return (this.buttonOptions.filter(el => this.isActiveButton(el))).length === 0
}
}
});
.active {
background: #f00;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<section>
<button
v-for="(text, index) in buttonOptions"
class="btn"
:class="{active: isActiveButton(text) || (shouldFirstBeActive && index === 0)}"
:value='text'
#mousedown.prevent #click="some_method">
{{text}}
</button>
</section>
</div>
I don't know what the methods isActiveButton do, so I had to improvise: It checks if the string is uppercase.
What does the trick is the computed property shouldFirstBeActive which returns true if all the items in the buttonOptions array fails the isActiveButton method:
return (this.buttonOptions.filter(el => this.isActiveButton(el))).length === 0
If you change the button2 to BUTTON2 for example, then the isActiveButton returns true for that item, which renders the shouldFirstBeActive computed property to false
var app = new Vue({
el: '#app',
data: {
buttonOptions: ['button1', 'BUTTON2', 'button3', 'button4']
},
methods: {
isActiveButton: function (text) {
return (text === text.toUpperCase());
},
some_method: function() {
console.log('Button clicked')
}
},
computed: {
shouldFirstBeActive: function () {
return (this.buttonOptions.filter(el => this.isActiveButton(el))).length === 0
}
}
});
.active {
background: #f00;
}
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<section>
<button
v-for="(text, index) in buttonOptions"
class="btn"
:class="{active: isActiveButton(text) || (shouldFirstBeActive && index === 0)}"
:value='text'
#mousedown.prevent #click="some_method">
{{text}}
</button>
</section>
</div>
Use a computed that filters this.buttonOptions where isActiveButton is true and that takes index as a parameter

Vue2 v-bind not working properly on child instance?

I have a child instance of Vue and v-bind only works on the parent instance but not in the child one. I did a sample file to explain my issue.
Am I missing something?
This is my code:
var app2 = new Vue({
el: '#app2',
data: {
isSpinning2: true
},
methods: {
stop2: function() {
app2.isSpinning2 = false;
}
}
});
var app1 = new Vue({
el: '#app1',
data: {
isSpinning: true
},
methods: {
stop1: function() {
app1.isSpinning = false;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<div id="app1">
<i v-bind:class="{'fa-spin': isSpinning}" class="fa fa-address-book"></i>
<button v-on:click="stop1">Stop 1</button>
<div id="app2">
<i v-bind:class="{'fa-spin': isSpinning2}" class="fa fa-address-book"></i>
<button v-bind:onclick="stop2">Stop 2</button>
</div>
</div>
This is exactly what components are for. Here is a component encapsulating your spinner buttons.
console.clear()
Vue.component("spinner",{
template: `
<div>
<i v-bind:class="{'fa-spin': isSpinning}" class="fa fa-address-book"></i>
<button v-on:click="stop"><slot /></button>
</div>
`,
data(){
return {
isSpinning: true
}
},
methods: {
stop: function() {
this.isSpinning = false;
}
}
})
var app1 = new Vue({
el: '#app1',
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.2/vue.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" />
<div id="app1">
<spinner>Stop 1</spinner>
<spinner>Stop 2</spinner>
</div>