How to use an attribute selector with vue.js? - javascript

I would like to apply a computed style to an input form. The documentation explains how to do that, but only for simple styles.
I need to apply the equivalent of
input[type="text"], textarea {
background-color : red;
}
but it is not clear for me how to convey the [type="text"] bit.
Using it verbatim does not work:
var vm = new Vue({
el: "#root",
data: {
password: '',
},
computed: {
passwordStyle: function() {
var style = {}
style['input[type="text"]'] = 'red';
style['textarea'] = 'blue';
return style;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
<div id="root>">
<input type="text" name="password" autofocus="true" v-bind:style='passwordStyle'>
</div>

You need to only pass the style, not the css selector, like:
var vm = new Vue({
el: "#root",
data: {
password: '',
},
computed: {
passwordStyle: function() {
return {
backgroundColor: 'red'
};
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.min.js"></script>
<div id="root">
<input type="text" name="password" autofocus="true" :style="passwordStyle">
</div>

Can you explain your use-case little bit elaborately, use of v-bind:style is when you want to dynamically change the style of some element, depending on some variable, as it is in docs, following code with change the CSS depending on isActive and hasError variable:
<div class="static"
v-bind:class="{ active: isActive, 'text-danger': hasError }">
</div>
data: {
isActive: true,
hasError: false
}
I don't see in your code you are changing style based on any variable.

Related

How to switch between v-html and insert as plain text in vue.js?

I'm looking to toggle between v-html and insert as plain text in vue.js v2. So far I have this
HTML
<div id="app">
<h2 v-html="html ? text : undefined">{{html ? '' : text}}</h2>
<button #click="toggle">
switch
</button>
</div>
JS
new Vue({
el: "#app",
data: {
text:"Hello<br/>World",
html:false
},
methods: {
toggle: function(){
this.html = !this.html;
}
}
})
but this doesn't work when html is false. How can I get this to work? I'm looking for a solution where I don't need to repeat <h2> twice using a v-else. Preferably, if I can do it with just the 1 <h2> tag.
Thanks
Use v-bind with the prop modifier. see docs.
new Vue({
el: "#app",
data: {
text:"Hello<br/>World",
html:false
},
computed: {
headingProps() {
return this.html ? { innerHTML: this.text } : { innerText: this.text } ;
},
},
methods: {
toggle: function(){
this.html = !this.html;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<h2 v-bind.prop="headingProps"></h2>
<button #click="toggle">
switch
</button>
</div>

How to swap input fields with Vue?

I am having difficulty to swap fields when a click event is triggered. Here is my code below, which is just changing the value and name once but it does not work if I click again. It also does not change the v-model value. Can anyone help me please?
HTML
<div id='app'>
<button #click="swapInputFields">Swap</button>
<input type="text" :name="[field1]" v-model="model1" :value="[fromCity]"><br>
<input type="text" :name="[field2]" v-model="model2" :value="[toCity]">
</div>
Vue code:
var app = new Vue({
el: '#app',
data: {
fromCity:'FROM',
toCity :'TO',
field1 :'name1',
field2 :'name2'
},
methods: {
swapInputFields()
{
this.fromCity = 'TO';
this.toCity ='FROM';
this.field1 = 'name2';
this.field2 ='name1';
}
}
});
Remove the [ ] brackets from the bindings and remove all of the attributes from the inputs other than type and v-model:
<button #click="swapInputFields">Swap</button>
<input type="text" v-model="fromCity"><br>
<input type="text" v-model="toCity">
You only need those model variables fromCity and toCity in your data:
data() {
return {
fromCity:'FROM',
toCity :'TO'
}
},
And swap them like this:
swapInputFields()
{
const temp = this.fromCity;
this.fromCity = this.toCity;
this.toCity = temp;
}
Here is a demo:
new Vue({
el: "#app",
data(){
return {
fromCity:'FROM',
toCity :'TO'
}
},
methods: {
swapInputFields()
{
const temp = this.fromCity;
this.fromCity = this.toCity;
this.toCity = temp;
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="swapInputFields">Swap</button>
<input type="text" v-model="fromCity"><br>
<input type="text" v-model="toCity">
</div>

Click-and-edit text input with Vue

I'm looking for a click-and-edit Vue component.
I've found a fiddle and made some edits. It works like this:
The fiddle is here.
The problem: I need an additional click to make the input focused. How can I make it focused automatically?
The code from the fiddle. HTML:
<div id="app">
Click the values to edit!
<ul class="todo-list">
<li v-for = "todo in todos">
<input v-if = "todo.edit" v-model = "todo.title"
#blur= "todo.edit = false; $emit('update')"
#keyup.enter = "todo.edit=false; $emit('update')">
<div v-else>
<label #click = "todo.edit = true;"> {{todo.title}} </label>
</div>
</li>
</ul>
</div>
JS:
new Vue({
el: '#app',
data: {
todos: [{'title':'one value','edit':false},
{'title':'one value','edit':false},
{'title':'otro titulo','edit':false}],
editedTodo: null,
message: 'Hello Vue.js!'
},
methods: {
editTodo: function(todo) {
this.editedTodo = todo;
},
}
})
You can use a directive, for example
JS
new Vue({
el: '#app',
data: {
todos: [
{ title: 'one value', edit: false },
{ title: 'one value', edit: false },
{ title: 'otro titulo', edit: false }
],
editedTodo: null,
message: 'Hello Vue.js!'
},
methods: {
editTodo: function (todo) {
this.editedTodo = todo
}
},
directives: {
focus: {
inserted (el) {
el.focus()
}
}
}
})
HTML
<div id="app">
Click the values to edit!
<ul class="todo-list">
<li v-for="todo in todos">
<input
v-if="todo.edit"
v-model="todo.title"
#blur="todo.edit = false; $emit('update')"
#keyup.enter="todo.edit=false; $emit('update')"
v-focus
>
<div v-else>
<label #click="todo.edit = true;"> {{todo.title}} </label>
</div>
</li>
</ul>
</div>
You can find more info here
https://v2.vuejs.org/v2/guide/custom-directive.html
With #AitorDB's help I have written a Vue component for this, I call it Click-to-Edit. It is ready to use, so I'm posting it.
What it does:
Supports v-model
Saves changes on clicking elsewhere and on pressing Enter
ClickToEdit.vue: (vue 2.x)
<template>
<div>
<input type="text"
v-if="edit"
:value="valueLocal"
#blur.native="valueLocal = $event.target.value; edit = false; $emit('input', valueLocal);"
#keyup.enter.native="valueLocal = $event.target.value; edit = false; $emit('input', valueLocal);"
v-focus=""
/>
<p v-else="" #click="edit = true;">
{{valueLocal}}
</p>
</div>
</template>
<script>
export default {
props: ['value'],
data () {
return {
edit: false,
valueLocal: this.value
}
},
watch: {
value: function() {
this.valueLocal = this.value;
}
},
directives: {
focus: {
inserted (el) {
el.focus()
}
}
}
}
</script>
Edit for 3.x: [Breaking changes between 2.x and 3.x]
remove .native from the event handlers
change the focus hook to mounted as described in Custom Directives 3.x.
Built on #Masen Furer's work. I added some protection to handle when a user deletes all of the data. There is probably a way to accomplish this using "update" but I couldn't get it working.
I also added the ability to hit escape and abandon any changes.
<template>
<span>
<input type="text"
v-if="edit"
:value="valueLocal"
#blur="save($event);"
#keyup.enter="save($event);"
#keyup.esc="esc($event);"
v-focus=""/>
<span v-else #click="edit = true;">
{{valueLocal}}
</span>
</span>
</template>
<script>
export default {
props: ['value'],
data () {
return {
edit: false,
valueLocal: this.value,
oldValue: (' ' + this.value).slice(1)
}
},
methods: {
save(event){
if(event.target.value){
this.valueLocal = event.target.value;
this.edit = false;
this.$emit('input', this.valueLocal);
}
},
esc(event){
this.valueLocal = this.oldValue;
event.target.value = this.oldValue;
this.edit = false;
this.$emit('input', this.valueLocal);
}
},
watch: {
value: function() {
this.valueLocal = this.value;
}
},
directives: {
focus: {
inserted (el) {
el.focus()
}
}
}
}
</script>

how to add or remove class in vuejs 2 based on id

I want to add or remove class to an element based on id using vuejs, but this code applies the behaviour to all elements. How can I add/remove a class to the element by id? Thanks all in advance.
new Vue({
el:"#test",
data: {
msg: 'msg goes here',
isActive: false
},
methods: {
log: function(e) {
this.isActive = ! this.isActive
//alert(e.currentTarget.id);
}
}
});
.active {
background: red
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.13/dist/vue.js"></script>
<div id="test">
<div id="1" v-on:click="log($event)" v-bind:class="{ active: isActive }">
{{ msg }}
</div>
<div id="2" v-on:click="log($event)" v-bind:class="{ active: isActive }">
{{ msg }}
</div>
</div>
Here is an example of using components to achieve the behavior you are looking for:
// register
const clickable = Vue.component('clickable', {
props: ['msg'],
data: function() {
return {
isActive: false
}
},
template: '<div :class="{ active: isActive }" #click="isActive = !isActive">{{ msg }}</div>'
})
new Vue({
el: "#test",
components: {
clickable
},
data: function() {
return {
msg: 'msg goes here',
isActive: false
}
}
});
.active {
background: red
}
<script src="https://cdn.jsdelivr.net/npm/vue#2.5.13/dist/vue.js"></script>
<div id="test">
<clickable :msg='msg'></clickable>
<clickable :msg='msg'></clickable>
</div>
You have not internalized basic vuejs concepts.
https://v2.vuejs.org/v2/guide/components.html
Both of your elements should be separate components.

How to point out this to a certain element in VueJS?

I am creating a form. When a input is focused, then the color of label should be blue. But it looks like something is wrong in my code. I am unable to point out this to the input.
Here's the code which doesn't work:
new Vue({
el: '#app',
data: {
inputs: document.querySelector('.input')
},
methods: {
changeColor(){
this.inputs.previousElementSibling.style.color = "blue";
}
}
});
<div id="app">
<label for="input">Input</label>
<input type="text" class = "input" v-on:focus = "changeColor"><br /><br />
</div>
<script type = "text/javascript" src = "https://vuejs.org/js/vue.js"></script>
Here's the code that works:
new Vue({
el: '#app',
data: {
inputs: document.querySelector('.input')
},
methods: {
changeColor(){
document.querySelector('.input').previousElementSibling.style.color = "blue";
}
}
});
<div id="app">
<label for="input">Input</label>
<input type="text" class = "input" v-on:focus = "changeColor"><br /><br />
</div>
<script type = "text/javascript" src = "https://vuejs.org/js/vue.js"></script>
So, my question why this.inputs doesn't work but document.querySelector('.input') works?
I have a simpler alternative that gives more flexibility
new Vue({
el: '#app',
props: ['styles'],
methods: {
changeStyles() {
this.styles = {
color: 'blue' // Add more CSS rules if you want
}
},
restoreStyles() {
this.styles = {
color: 'black'
}
}
}
})
<div id="app">
<label :style="styles">Input</label>
<input type="text" #focus="changeStyles" #focusout="restoreStyles">
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.0.3/vue.js"></script>
Hope it helps. And the for attribute in label tag only works with id of the bound input field.
Check the console output of this snippet:
new Vue({
el: '#app',
data: {
inputs: document.querySelector('.input')
},
methods: {
changeColor(){
console.log('Are the similar? answer: ',
this.inputs == document.querySelector('.input'));
this.inputs.previousElementSibling.style.color = "blue";
}
}
});
<div id="app">
<label for="input">Input</label>
<input type="text" class = "input" v-on:focus = "changeColor"><br /><br />
</div>
<script type = "text/javascript" src = "https://vuejs.org/js/vue.js"></script>
After Vue instance is created it replaces all elements inside the #app in its own flavor. Your inputs field is set at the moment of creating Vue instance and before mounting the #app component. So the thing that you store in the this.inputs is long dead!
You should probably read through the Reactivity in Depth very carefully. And as suggested by the #Shreevardhan's answer, you should always use Vue's way to manipulate Vue's stuffs.

Categories