Is it possible to bind the inline style with vue.js? - javascript

I am curious, is it possible to bind the inline style in Vue.js? I'm familiar with class binding but what if sometimes for some reason you want to bind a style statement inline, is it possible to bind it like you do with class?
For example:
<template>
<div>
<h1 :style="{('background:red') : condition}"> Text </h1>
<button #click='condition = true'>Click me</button>
</div>
</template>
<script>
export default {
data() {
return {
condition: false,
};
},
};
</script>
In the example above I'd like to change the background of the element when the condition becomes true.

Of course it is possible as described here: https://v2.vuejs.org/v2/guide/class-and-style.html
<template>
<div>
<h1 v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"> Text </h1>
<button #click='condition = true'>Click me</button>
</div>
</template>
<script>
export default {
data() {
return {
condition: false,
activeColor: 'white',
fontSize: 12,
};
},
};
</script>

Yes, it's possible please go through the docs
Note: please use computed, methods instead of inline for better debugging
<template>
<div>
<h1 :style="styleObject"> Text </h1>
<button #click='toggleCondition'>Click me</button>
</div>
</template>
<script>
export default {
data() {
return {
condition: false,
};
},
computed: {
styleObject() {
return this.condition ? { background: 'red' } : {};
},
},
methods: {
toggleCondition() {
this.condition = !this.condition;
},
},
};
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

Related

Am having issue implementing the javascript code with vue

Am very new to vuejs.am trying to replicate the javascript with vue. where a user can toggle button. I have a list of buttons and I would like to toggle the active class but remove the active class from all other buttons.. Is there a better way of writtting the function without the querySelector? Am really stuck..
<template>
<div #click="selectItem" class="menu-tabs">
<button type="btn" class="menu-tab-item active" data-target="#remis-transfer"> Transfer
</button>
<button type="btn" class="menu-tab-item text-muted" data-target="#bank-transfer">
Transfer Money
</button>
<button type="btn" class="menu-tab-item text-muted" data-target="#fueling">
Fueling
</button>
</div>
</template>
<script>
export default {
methods: {
selectItem(e) {
if (e.target.classList.contains("menu-tab-item") && !e.target.classList.contains("active")) {
const target = e.target.getAttribute("data-target")
menuTabs.querySelector(".active").classList.remove("active");
e.target.classList.add("active");
const menuSection = document.querySelector(".menu-section");
menuSection.querySelector(".menu-tab-content.active").classList.remove("active");
menuSection.querySelector(target).classList.add('active');
}
}
}
}
</script>
Look at the code
var Main = {
data() {
return {
active: 0,
buttonList: [
{
text: "Transfer",
target: "#remis-transfer",
},
{
text: "Transfer Money",
target: "#bank-transfer",
},
{
text: "Fueling",
target: "#fueling",
},
],
};
},
methods: {
selectItem(i) {
this.active = i;
},
},
};
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.9/vue.js"></script>
<div id="app">
<div class="menu-tabs">
<button
type="btn"
class="menu-tab-item"
v-for="(item, index) in buttonList"
:class="[{ active: active == index }, { 'text-muted': active != index }]"
:data-target="item.target"
:key="index"
#click="selectItem(index)"
>
{{ item.text }}
</button>
</div>
</div>
You can simply define some states like:
data() {
return {
myActiveClass: 'active',
myMutedClass: 'text-muted'
}
},
and pass this myActiveClass and myMutedClass states to your elements like this:
class=menu-tab-item ${myMutedClass} ${myActiveClass}
with this approach, you can quickly achieve what you want. So when you want an element to not be active, in your function you can make myActiveClass = '', or if you want the text to lose muted class you can say myMutedClass = '' .
Just make sure to play with states in the way you want.

Clear v-model input from method in Vue2

I have a form with two datepickers and a button to clear each one of them as follows:
<template>
<form>
<div>
<datetime id="someDate" v-model="fields.some_date"></datetime>
<button #click.prevent="clearSomeDate()">X</button>
</div>
<div>
<datetime id="anotherDate" v-model="fields.another_date"></datetime>
<button #click.prevent="clearAnotherDate()">X</button>
</div>
</form>
</template>
<script>
export default {
data() {
return {
fields: {
some_date: null,
another_date: null
},
};
},
methods: {
clearSomeDate() {
this.fields.some_date = null;
},
clearAnotherDate() {
this.fields.another_date = null;
},
},
}
</script>
And works pretty well, but it's not so much reusable.
Is there a way to achieve this with a single clearField() function and pass the model as a parameter or something? Should I do my own custom component to make it work?
You could completely get rid of the methods by just doing the assignment directly in the template:
<div>
<datetime id="someDate" v-model="fields.some_date"></datetime>
<button #click.prevent="fields.some_date = null">X</button>
</div>
That way you have the clearing logic directly next to the model.
If you want to make it reusable you could also extract it into a separate component:
<template>
<div>
<datetime v-bind="$attrs" :value="value" v-on="eventHandlers"></datetime>
<button #click.prevent="$emit('input', null)">X</button>
</div>
</template>
<script>
export default {
name: "datetime-with-x",
model: { prop: "value", event: "input" },
props: ["value"],
inheritAttrs: false,
computed: {
eventHandlers() {
return {
...this.$listeners,
input: ev => this.$emit('input', ev)
};
}
}
};
</script>
and then use it in your component like this:
<template>
<form>
<datetime-with-x id="someDate" v-model="fields.some_date" />
<datetime-with-x id="anotherDate" v-model="fields.another_date" />
</form>
</template>
<script>
import DatetimeWithX from "./datetime-with-x";
export default {
name: "your-form",
components: { DatetimeWithX },
data() {
return {
fields: {
some_date: null,
another_date: null
}
};
}
};
</script>
You could pass the field property name as parameter
clearField(name) {
this.fields[name] = null;
}
and call it with argument
<button #click.prevent="clearField('some_date')">X</button>
Though a cleaner approach would be to build another reusable component and bind it with v-model
<div>
<datetime :value="value" #change="$emit('input', $event)"></datetime>
<button #click.prevent="$emit('input', null)">X</button>
</div>

how to bind value of v-for to v-if

I'm working with BootstrapVue. To my problem: I have a v-for in my template in which I have two buttons.
Looping over my v-for my v-if doesn't generate unique IDs and than after clicking one button each button will be triggered (from Open me! to Close me! and other way around).
How can I manage to get each button only triggers itself and doesn't affect the other?
I think I have to use my n of my v-for but I actually don't know how to bind this to a v-if..
Thanks in advance!
<template>
<div>
<div v-for="n in inputs" :key="n.id">
<b-button v-if="hide" #click="open()">Open me!</b-button>
<b-button v-if="!hide" #click="close()">Close me! </b-button>
</div>
<div>
<b-button #click="addInput">Add Input</b-button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
id: null,
inputs: [{
id: 0
}],
hide: true,
};
},
methods: {
open() {
this.hide = false
},
close() {
this.hide = true
},
addInput() {
this.inputs.push({
id: this.id += 1;
})
}
}
};
</script>
Everything seems to look fine. In order to handle each button triggers,
you can maintain an object like so:
<script>
export default {
data() {
return {
inputs: [{id: 0, visible: false}],
};
},
methods: {
open(index) {
this.inputs[index].visible = false
},
close(index) {
this.inputs[index].visible = true
},
addInput() {
this.inputs.push({id: this.inputs.length, visible: false});
}
}
};
</script>
and your template should be like
<template>
<div>
<div v-for="(val, index) in inputs" :key="val.id">
<b-button v-if="val.visible" #click="open(index)">Open me!</b-button>
<b-button v-if="!val.visible" #click="close(index)">Close me! </b-button>
</div>
</div>
</template>
Edit:
You don't need to insert an id every time you create a row, instead can use the key as id. Note that the inputs is an object and not array so that even if you want to delete a row, you can just pass the index and get it removed.
I would create an array of objects. Use a boolean as property to show or hide the clicked item.
var app = new Vue({
el: '#app',
data: {
buttons: []
},
created () {
this.createButtons()
this.addPropertyToButtons()
},
methods: {
createButtons() {
// Let's just create buttons with an id
for (var i = 0; i < 10; i++) {
this.buttons.push({id: i})
}
},
addPropertyToButtons() {
// This method add a new property to buttons AFTER its generated
this.buttons.forEach(button => button.show = true)
},
toggleButton(button) {
if (button.show) {
button.show = false
} else {
button.show = true
}
// We are changing the object after it's been loaded, so we need to update ourselves
app.$forceUpdate();
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<template>
<div>
<div v-for="button in buttons" :key="button.id">
<button v-if="button.show" #click="toggleButton(button)">Open me!</button>
<button v-if="!button.show" #click="toggleButton(button)">Close me! </button>
</div>
</div>
</template>
</div>

Vue.js - Computed property not updating - child component

I've created a simple component named DefaultButton.
It bases on properties, that are being set up whenever this component is being created.
The point is that after mounting it, It does not react on changes connected with "defaultbutton", that is an object located in properties
<template>
<button :class="buttonClass" v-if="isActive" #click="$emit('buttonAction', defaultbutton.id)" >
{{ this.defaultbutton.text }}
</button>
<button :class="buttonClass" v-else disabled="disabled">
{{ this.defaultbutton.text }}
</button>
</template>
<script>
export default {
name: "defaultbutton",
props: {
defaultbutton: Object
},
computed: {
buttonClass() {
return `b41ngt ${this.defaultbutton.state}`;
},
isActive() {
return (this.defaultbutton.state === "BUTTON_ACTIVE" || this.defaultbutton.state === "BUTTON_ACTIVE_NOT_CHOSEN");
}
}
};
</script>
Having following component as a parent one:
<template>
<div v-if="state_items.length == 2" class="ui placeholder segment">
{{ this.state_items[0].state }}
{{ this.state_items[1].state }}
{{ this.current_active_state }}
<div class="ui two column very relaxed stackable grid">
<div class="column">
<default-button :defaultbutton="state_items[0]" #buttonAction="changecurrentstate(0)"/>
</div>
<div class="middle aligned column">
<default-button :defaultbutton="state_items[1]" #buttonAction="changecurrentstate(1)"/>
</div>
</div>
<div class="ui vertical divider">
Or
</div>
</div>
</template>
<script type="text/javascript">
import DefaultButton from '../Button/DefaultButton'
export default {
name: 'changestatebox',
data() {
return {
current_active_state: 1
}
},
props: {
state_items: []
},
components: {
DefaultButton
},
methods: {
changecurrentstate: function(index) {
if(this.current_active_state != index) {
this.state_items[this.current_active_state].state = 'BUTTON_ACTIVE_NOT_CHOSEN';
this.state_items[index].state = 'BUTTON_ACTIVE';
this.current_active_state = index;
}
},
},
mounted: function () {
this.state_items[0].state = 'BUTTON_ACTIVE';
this.state_items[1].state = 'BUTTON_ACTIVE_NOT_CHOSEN';
}
}
</script>
It clearly shows, using:
{{ this.state_items[0].state }}
{{ this.state_items[1].state }}
{{ this.current_active_state }}
that the state of these items are being changed, but I am unable to see any results on the generated "DefaultButtons". Classes of objects included in these components are not being changed.
#edit
I've completely changed the way of delivering the data.
Due to this change, I've abandoned the usage of an array; instead I've used two completely not related object.
The result is the same - class of the child component's object is not being
DefaulButton.vue:
<template>
<button :class="buttonClass" v-if="isActive" #click="$emit('buttonAction', defaultbutton.id)" >
{{ this.defaultbutton.text }}
</button>
<button :class="buttonClass" v-else disabled="disabled">
{{ this.defaultbutton.text }}
</button>
</template>
<style lang="scss">
import './DefaultButton.css';
</style>
<script>
export default {
name: "defaultbutton",
props: {
defaultbutton: {
type: Object,
default: () => ({
id: '',
text: '',
state: '',
})
}
},
computed: {
buttonClass() {
return `b41ngt ${this.defaultbutton.state}`;
},
isActive() {
return (this.defaultbutton.state === "BUTTON_ACTIVE" ||
this.defaultbutton.state === "BUTTON_ACTIVE_NOT_CHOSEN");
}
}
};
</script>
ChangeStateBox.vue:
<template>
<div class="ui placeholder segment">
{{ this.state_first.state }}
{{ this.state_second.state }}
{{ this.current_active_state }}
<div class="ui two column very relaxed stackable grid">
<div class="column">
<default-button :defaultbutton="state_first" #buttonAction="changecurrentstate(0)"/>
</div>
<div class="middle aligned column">
<default-button :defaultbutton="state_second" #buttonAction="changecurrentstate(1)"/>
</div>
</div>
<div class="ui vertical divider">
Or
</div>
</div>
</template>
<script type="text/javascript">
import DefaultButton from '../Button/DefaultButton'
export default {
name: 'changestatebox',
data() {
return {
current_active_state: 1
}
},
props: {
state_first: {
type: Object,
default: () => ({
id: '',
text: ''
})
},
state_second: {
type: Object,
default: () => ({
id: '',
text: ''
})
},
},
components: {
DefaultButton
},
methods: {
changecurrentstate: function(index) {
if(this.current_active_state != index) {
if(this.current_active_state == 1){
this.$set(this.state_first, 'state', "BUTTON_ACTIVE_NOT_CHOSEN");
this.$set(this.state_second, 'state', "BUTTON_ACTIVE");
} else {
this.$set(this.state_first, 'state', "BUTTON_ACTIVE");
this.$set(this.state_second, 'state', "BUTTON_ACTIVE_NOT_CHOSEN");
}
this.current_active_state = index;
}
},
},
created: function () {
this.state_first.state = 'BUTTON_ACTIVE';
this.state_second.state = 'BUTTON_ACTIVE_NOT_CHOSEN';
}
}
</script>
You're declaring props wrong. It is either an array of prop names or it is an object with one entry for each prop declaring its type, or it is an object with one entry for each prop declaring multiple properties.
You have
props: {
state_items: []
},
but to supply a default it should be
props: {
state_items: {
type: Array,
default: []
}
},
But your problem is most likely that you're mutating state_items in such a way that Vue can't react to the change
Your main problem is the way you are changing the button state, according with Array change detection vue can't detect mutations by indexing.
Due to limitations in JavaScript, Vue cannot detect the following
changes to an array:
When you directly set an item with the index, e.g.
vm.items[indexOfItem] = newValue When you modify the length of the
array, e.g. vm.items.length = newLength
In case someone will be having the same issue:
#Roy J as well as #DobleL were right.
The reason behind this issue was related with the wrong initialization of state objects.
According to the documentation:
Vue cannot detect property addition or deletion.
Since Vue performs the getter/setter conversion process during instance
initialization, a property must be present in the
data object in order for Vue to convert it and make it reactive.
Before reading this sentence, I used to start with following objects as an initial data:
var local_state_first = {
id: '1',
text: 'Realized',
};
var local_state_second = {
id: '2',
text: 'Active'
};
and the correct version of it looks like this:
var local_state_first = {
id: '1',
text: 'Realized',
state: 'BUTTON_ACTIVE'
};
var local_state_second = {
id: '2',
text: 'Active',
state: 'BUTTON_ACTIVE'
};
whereas declaring the main component as:
<change-state-box :state_first="local_state_first" :state_second="local_state_second" #buttonAction="onbuttonAction"/>
Rest of the code remains the same ( take a look at #edit mark in my main post )

Check if props in vue.js component template exists

After tried many variations, I don't know how to properly style a component's slot or partial code within <template></template> section.
Is there a way to check if props <counter :recent="true"></counter> from parent level exists, so in a Counter.vue in section <template></template> i would show a special html markup for it ?
=== UPDATED ===
Vue.component('counter', {
template: `
<span class="counter" :number="21" v-text="number">
<span v-if="recent">
since VARTIME
</span>
</span>
`,
data: function(){
return{
count: this.number + 1
}
},
props: {
number: Number,
recent: {
type: Boolean,
default: false
}
},
computed: {
},
created(){
if( this.recent === true ){
console.log('mounted recent true');
}
}
});
new Vue({
el: "#app",
data: {
count: ''
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<div id="app">
<counter :number="20" :recent="true"></counter>
</div>
Here the default value for the recent will be false and if the recent is passed from the parent it will get set in the child.
Just use the detailed props definition as mentioned here.
Remove the v-text="number" as it overrides the internal content of the span and therefore the v-if will never executes.
This is a working example
Vue.component('counter', {
template: `
<span class="counter" :number="21">
<span v-if="recent"> since VARTIME </span>
</span>
`,
data: function() {
return {
count: this.number + 1
}
},
props: {
number: Number,
recent: {
type: Boolean,
default: false
}
},
computed: {},
created() {
if ( this.recent === true ) {
console.log('mounted recent true');
}
}
});
new Vue({
el: "#app",
data: {
count: ''
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.4/vue.min.js"></script>
<div id="app">
<counter :number="20" :recent="true"></counter>
</div>
You should add a condition class binding, that you eventually style from css/sass/stylus/less.
This can be done as follows:
<template>
<span class="counter" v-text="count" :class="{ cssClassName: recent}">
<slot></slot>
<span v-if="recent">
since VAR_DATETIME <i class="fa fa-refresh" #click="updateList"></i>
</span>
</span>
</template>
Notice that vuejs will automatically combine multiple class declarations on the same element without problems, as described in the manual.

Categories