Vuejs event on change of element value? - javascript

I have an element that I want to watch for a change like this:
<span id="slider-value-upper" class="lower">50</span>
Is it possible to do this cleanly with vuejs? I tried looking in the docs but I could not find anything like this.
I want to launch a custom event whenever '50' changes to something else with VueJs.

Have you tried with watch?
In your case it would be something like this.
template
<div id="app">
{{ message }}
<span id="slider-value-upper" class="lower">{{myValue}}</span><br />
<input v-model="myValue">
</div>
js code
new Vue({
el: '#app',
data: {
message: 'Watch example',
myValue: 50
},
watch: {
'myValue': function(val, oldVal){
if (val < 50) {
this.message= 'value too low!';
}else{
this.message= 'value is ok';
}
}
}
})
check out the example

Related

How to dynamically add part of an object with an arg in a vue method

Super simple question but i've never been able to solve it.
Say we have some data:
section: {
option1: true,
option2: true
}
and on a button we have:
<button #click="toggle(option1)">
How do I dynamically paste 'option1' arg into something like this:
toggle(opp){
console.log(this.section.opp)
}
Because currently it's literally looking for this.section.opp, and opp doesn't exist in the data.
Use this.section[opp] instead of this.section.opp as opp contains dynamic value and can not access directly with dot(.) notation as it is containing a different value.
Working Demo :
new Vue({
el: '#app',
data: {
section: {
option1: true,
option2: true
},
result: null
},
methods: {
toggle(opp) {
this.result = this.section[opp];
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<button #click="toggle('option1')">Click Me</button>
<p>Result: {{ result }}</p>
</div>

Vue/Javascript - Unable to clear input after paste event

I have a project where users need to paste something into an input field. Inside this event I need to use the pasted data and the clear the input field. But I cannot seem to get it empty.
I have tried clearing the v-model element binded to the input, clearing the input using ref and event.target.blur(). But nothing seems to clear the input when something is pasted inside.
new Vue({
el: "#app",
data: {
todo: ''
},
methods: {
onPaste: function(event) {
let clipped = event.clipboardData.getData('text');
console.log(clipped)
this.todo = ''
this.$refs['todo'].value = '';
event.target.blur();
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="text" v-model="todo" ref="todo" #paste="onPaste">
</div>
You can use the prevent modifier on paste to prevent the native event and you don't need to use the $ref in this case.
Check #paste.prevent:
new Vue({
el: "#app",
data: {
todo: ''
},
methods: {
onPaste: function(event) {
let clipped = event.clipboardData.getData('text');
console.log(clipped)
this.todo = '';
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="text" v-model="todo" #keyup.enter="addTodo" #paste.prevent="onPaste">
</div>

I'm trying to implement VeeValidate to check if at least one checkbox is checked

I found a jsfiddle example that I forked and then edited. I don't understand what's going on or how to fix it. In my example I'm using checkboxes with values but when I click a checkbox the value is changed to true or false depending on if the checkbox is clicked.
const Checkboxes = {
template: '#checkboxTmpl',
data() {
return {
text: '',
options: [
{
name: 'Web',
slug: 'web'
},
{
name: 'iOS',
slug: 'ios'
},
{
name: 'Android',
slug: 'android'
}
]
};
},
created() {
this.$validator.extend('oneChecked', {
getMessage: field => 'At least one ' + field + ' needs to be checked.',
validate: (value, [testProp]) => {
const options = this.options;
// console.log('questions', value, testProp, options.some((option) => option[testProp]));
return value || options.some((option) => option[testProp]);
}
});
},
methods: {
validateBeforeSubmit(e) {
this.$validator.validateAll(); // why is oneChecked not validated here? --> manually trigger validate below
this.options.forEach((option) => {
this.$validator.validate('platforms', option.slug, ['checked'])
});
console.log('validator', this.errors);
if (!this.errors.any()) {
alert('succesfully submitted!');
}
}
}
};
Vue.use(VeeValidate);
const app = new Vue({
el: '#app',
render: (h) => h(Checkboxes)
})
<script src="https://cdn.jsdelivr.net/vee-validate/2.0.0-beta.18/vee-validate.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.js"></script>
<div id="app">
</div>
<script id="checkboxTmpl" type="text/template">
<form #submit.prevent="validateBeforeSubmit">
<label v-for="(option, index) in options">
<input type="checkbox"
v-model="option.slug"
name="platform"
v-validate.initial="option.slug"
data-vv-rules="oneChecked:checked"
data-vv-as="platform"/> {{option.name}}
</label>
<p v-show="errors.has('platform')">{{ errors.first('platform') }}</p>
<pre>{{options}}</pre>
<button type="submit">Submit</button>
</form>
</script>
I don't understand why all of the checkboxes are checked and unchecking one of them returns a validation error even though two are still checked. I like that errors are shown before the form is submitted but unchecking all and then submitting doesn't trigger the validation error.
I'm using VeeValidate because that is what the example uses but any other solution would be fine. I don't want to use jQuery in my vue.js application.
I would really like to understand what is going on.
There was two main problems going on :
Using v-model on the wrong key. In fact, each time the checkbox was checked or unchecked, it will emit an input event that will modify the original slug of the option (in your data). Instead, you need to add a checked field in your option. Then in your template add the :checked attribute and modify your v-model to be :option.checked.
As the docs of VeeValidate say, you can just use the required rule to make sure a checkbox has to be checked to submit your form. Here is the link towards the docs. Therefore, you don't need your created block.
Additionally, the validateAll function returns a promise containing the result of the validation. So no need to use this.errors.any() too.
Also, I upgraded the VeeValidate library to the latest as you used a beta.
Here is the working code :
const Checkboxes = {
template: '#checkboxTmpl',
data() {
return {
text: '',
options: [{
name: 'Web',
slug: 'web',
checked: false
},
{
name: 'iOS',
slug: 'ios',
checked: true
},
{
name: 'Android',
slug: 'android',
checked: true
}
]
};
},
methods: {
validateBeforeSubmit(e) {
this.$validator.validateAll().then(value => {
if (value) {
alert('successfully submitted')
}
})
}
}
};
Vue.use(VeeValidate);
const app = new Vue({
el: '#app',
render: (h) => h(Checkboxes)
})
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.js"></script>
<script src="https://unpkg.com/vee-validate#latest"></script>
<script id="checkboxTmpl" type="text/template">
<form #submit.prevent="validateBeforeSubmit">
<label v-for="(option, index) in options">
<input type="checkbox"
:checked="option.checked"
v-model="option.checked"
name="platform"
v-validate="'required'"/> {{option.name}}
</label>
<p v-show="errors.has('platform')">{{ errors.first('platform') }}</p>
<pre>{{options}}</pre>
<button type="submit">Submit</button>
</form>
</script>
Hope that helps!

Pass click action using array and v-for (Vue.js)

I am trying to pass through a v-for the text and the #click action of each li. For the text I know how to do it...but for the click action?enter code here
Each item of the array menuOptions (which is in the 'data' part of my Vue component) is structured like this :
{name: "firstOption",action: "console.log('first option called')"}
The first parameter is the name of the option, the
<ul>
<li v-for="option in menuOptions" #click="option.action">{{option.name}}</li>
</ul>
Do you have some ideas? (I guess that's maybe a pure JS question, but maybe there are possibilities to do it Vue too?)
Pass a function expression to the action property, instead of a "stringified" function.
{
name: 'firstOption',
action: function() {console.log('first option called'}
}
var app = new Vue({
el: '#app',
data: {
menuOptions: [{
action: function() {
console.log('foo')
},
name: 'foo'
}, {
action: function() {
console.log('bar')
},
name: 'bar'
}],
}
})
<script src="https://unpkg.com/vue"></script>
<div id='app'>
<ul>
<li v-for="option in menuOptions" #click="option.action">{{option.name}}</li>
</ul>
</div>

Dynamic style binding in vue js to toggle a class

I am trying to bind an attribute to and id I have on a button to change its styling, basically I have a courses database table(using Laravel as backend) where each course has a Boolean named completed, All I want to do is if the course is completed(true) to render a specific id, and if it is not(false) to render another one, that's it, here's my code,
This is the blade template, this is inside a table:
<td>
<form method="POST" action="{{ route('course.completed', $course->name) }}" id="form-submit">
{{ csrf_field() }}
#if ($course->completed)
<button #click.prevent="onSubmit({{ $course }})" type="button" class="btn btn-sm" :id="cssClass">#{{ text }}</button>
#endif
</form>
And here is the vue instance, All i want to do here is to add an if condition that will set the cssClass properly to the name of the id that I want:
<script>
new Vue({
el: '#app',
data: {
cssClass: '',
text: ''
},
methods: {
onSubmit: function(course) {
axios.post('/MyCourses/' + course.name)
// .then(function (response){
// });
}
},
//Basically here's what I would like to be able to do
if (course.completed == true) {
this.cssClass = 'coursetogglingtrue',
this.text = 'Done!'
} else {
this.cssClass = 'coursetogglingfalse',
this.text = 'Not Yet!'
}
});
</script>
Right now the above code in the view instance errors out with "Uncaught SyntaxError: Unexpected token ." directed at the if statement course.completed, and it doesn't go away unless I delete the whole if statement, I know I'm not fetching the course from anywhere, I just don't know how yet, if there is a better idea/approach please let me know, and thanks for your time.
UPDATE:
Here's a change, this is what I have done so far,
As for the view:
#if ($course->pivot->completed == true)
<button #click.prevent="onSubmit({{ $course }})" type="button" class="btn btn-sm" :id="[isActive ? greenClass.aClass : redClass.aClass]">#{{ greenClass.text }}</button>
{{-- #else
<button #click.prevent="onSubmit({{ $course }})" type="button" class="btn btn-sm" :id="[isActive ? greenClass.aClass : redClass.aClass]"></button> --}}
#endif
Now as for the vue instance:
<script>
new Vue({
el: '#app',
data: {
isActive: true,
greenClass: {aClass: 'coursetogglingtrue', text: 'Done!'},
redClass: {aClass: 'coursetogglingfalse', text: 'Not Yet!'}
},
methods: {
onSubmit: function(course) {
axios.post('/MyCourses/' + course.name)
// .then(function (response){
// });
this.isActive = !this.isActive;
}
}
});
</script>
Since that I know the blade #if condition is passing as true, I can hardcode the is active is true, and when I press on the button I get what I wanted the class actually toggles, if that is not true I default to the other class, now the problem is I need that action to be performed on exactly one button, the one I pressed on, right now what happens is every single button toggles its class, I know that once again it's due to my code not being explicit about this, the thing is I don't know how yet, so please help if you have any idea, have been stuck on this for weeks and weeks, it's really frustrating that I can't get this one simple thing to work.
It doesn’t make sense to put an expression as a property key.
Try this:
new Vue({
el: '#app',
data: {
cssClass: '',
text: ''
},
methods: {
onSubmit: function(course) {
axios.post('/MyCourses/' + course.name)
// .then(function (response){
// });
if (course.completed == true) {
this.cssClass = 'coursetogglingtrue',
this.text = 'Done!'
} else {
this.cssClass = 'coursetogglingfalse',
this.text = 'Not Yet!'
}
}
}
});

Categories

Resources