Vue.js adding a toggle and method to a button - vue.js

I have a button that should toggle and also call a method. How do I achieve this? Seems like it can be only one or the other.
new Vue({
el: "#app",
data: {
iExist:false,
iDoNotExist: true,
},
methods: {
iSignedUpforThis: function(){
console.log("step X");
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<p v-show="iExist"> i EXISTS </p>
<p v-show="iDoNotExist">
<strong> You are not found: </strong>
<form >
First name:<br>
<input type="text" name="firstname" value="Mickey">
<br>
Last name:<br>
<input type="text" name="lastname" value="Mouse">
<br><br>
</form>
<BUTTON v-on:click="iExists = iDoNotExist">
TOGGLE MY EXISTENCE
</BUTTON>
</div>

Move
iExists = iDoNotExist to a method:
methods: {
iSignedUpforThis: function(){
this.iExist = this.iDoNotExist
console.log("step X");
}
}
<button v-on:click="iSignedUpForThis">
TOGGLE MY EXISTENCE
</button>

First off to accomplish your desired result you need only one Boolean variable. Then in your method just switch between true and false. Also you have an invalid markup - there is closing tap p but no closing. That's why your example does not work.
Notice: it's bad idea to nest form tag inside p tag, so use div instead. It's considered a good practice to associate your input with it's label using label tag. Also there is shortcut for v-on:click - #click. data should be an function that returns an object, this will prevent . multiple instance to share the same object.
If you follow above recommendations you will make your code much clear and bug-less.
new Vue({
el: '#app',
data: {
isExist: false,
},
methods: {
method() {
this.isExist = !this.isExist
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<div v-show="isExist">I exist</div>
<div v-show="!isExist">
<strong>You are not found:</strong>
<form>
<label>First name:<br>
<input type="text" name="firstname" value="Mickey">
</label>
<br>
<label>Last name:<br>
<input type="text" name="lastname" value="Mouse">
</label>
</form>
</div>
<button #click="method">Toggle</button>
</div>

It might be late but I am sure it will help others. Create a component ToggleButton.js and paste the below codes.
<template>
<label for="toggle_button">
<span v-if="isActive" class="toggle__label">On</span>
<span v-if="! isActive" class="toggle__label">Off</span>
<input type="checkbox" id="toggle_button" v-model="checkedValue">
<span class="toggle__switch"></span>
</label>
</template>
<script>
export default {
data() {
return {
currentState: false
}
},
computed: {
isActive() {
return this.currentState;
},
checkedValue: {
get() {
return this.defaultState
},
set(newValue) {
this.currentState = newValue;
}
}
}
}
</script>
Take a look at the article to learn more https://webomnizz.com/create-toggle-switch-button-with-vue-js/

Related

Vue-JS v-show Percitence in radio

v-show appears not be percitent when whit radio (v-model)
Please find example: https://jsfiddle.net/Lngocxrj/1/
<div id="helloWorldApp">
<input type="radio" v-model="visible" value="true" name="optradio">hide
<input type="radio" v-model="visible" value="false" name="optradio">show
<div v-show="visible">
Hello World
</div>
<p>
{{visible}}
</p>
</div>
new Vue({
el: "#helloWorldApp",
data: {
visible: true
},
methods: {
show: function() {
this.visible = !this.visible;
}
}
});
It works, if you use a method to toggle the data.
HTML:
<div id="helloWorldApp">
<label>hide<input type="radio" value="false" #click="inputClick(false)" name="optradio" /></label>
<label>show<input type="radio" value="true" #click="inputClick(true)" name="optradio" /></label>
<div v-show="visible">
Hello World
</div>
<p>
{{visible}}
</p>
</div>
JavaScript:
new Vue({
el: "#helloWorldApp",
data: {
visible: false
},
methods: {
inputClick(val) {
this.visible = val;
}
}
});
Added a new property to differentiate input changes and show/hide div
<div id="helloWorldApp">
<input type="radio" v-model="visible" value="true" name="optradio">hide
<input type="radio" v-model="visible" value="false" name="optradio">show
<div v-if="showDiv">
Hello Worlds
</div>
<p>
{{visible}}
</p>
</div>
new Vue({
el: "#helloWorldApp",
data: {
visible: false,
showDiv: true
},
watch: {
visible(val) {
this.showDiv = val;
}
}
});
As per my comment: the reason why your element is showing regardless of the v-show directive is because the values from the checkboxes are being stored as strings and not booleans. And since "false" is actually truthy because it is a string of non-zero length, your div will always be visible.
Quick solution: Perform string comparison
If you want to keep your code as-is, and understanding that you are looking at string values instead of boolean stored in visible, updating your template to use v-show="visible === 'true'" will work.
Note: I do not encourage this method though, because this is a code smell (see further below for a better solution).
new Vue({
el: "#helloWorldApp",
data: {
visible: 'true'
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="helloWorldApp">
<input type="radio" v-model="visible" value="true" name="optradio">hide
<input type="radio" v-model="visible" value="false" name="optradio">show
<div v-show="visible === 'true'">
Hello World
</div>
<p>
{{visible}}
</p>
</div>
A better solution: use checkbox for binary state toggling
This brings us to another issue: since you are toggling a property, a radio button is not the best UI to do that. A checkbox is more appropriate: in this case, you don't need to do dirty strict comparisons:
new Vue({
el: "#helloWorldApp",
data: {
visible: true
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="helloWorldApp">
<input type="checkbox" v-model="visible" checked>visible
<div v-show="visible">
Hello World
</div>
<p>
{{visible}}
</p>
</div>

How to combine v-for and v-model to edit a list of objects?

I would like to edit a list of users using Vue.js. Each user has a name and an age. It seems that v-for is the right directive to work with lists and v-model is the right directive to bind the contents of an input to a particular element in the list.
So I tried to implement it like this:
new Vue({
el: '#exercise',
data: {
users: [{
name: "martin",
age: 32
}]
},
methods: {
add_user: function() {
this.users.push({
name: "",
age: ""
});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="exercise">
<form id="list">
<div></div>
<div v-for="user in users">
<input v-model="user.name">
<input v-model="user.age">
<button #click="add_user">+</button>
</div>
</form>
</div>
However, once I click the button to add a new user, a new line with input fields is displayed only for a fraction of a second and then disappears, leaving the list of users containing only one element.
Please, could you tell me what am I doing wrong?
The reason is <button> with <form> when you're click button it does the request automatically so its refresh or disappear because it fails to try to use <a> or using <button #click.prevent="add_user" />
<div id="exercise">
<form id="list">
<div></div>
<div v-for="user in users">
<input v-model="user.name">
<input v-model="user.age">
<a #click="add_user">+</a> //solution
<button #click.prevent="add_user">+</button> //another solution
</div>
</form>
</div>
The button is submitting the form, add .prevent to stop the action:
new Vue({
el: '#exercise',
data: {
users: [{
name: "martin",
age: 32
}]
},
methods: {
add_user () {
this.users = [ ...this.users, {
name: "",
age: ""
}]
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="exercise">
<form id="list">
<div v-for="(user, index) in users" :key="index">
<input v-model="user.name" :key="`name-${index}`">
<input v-model="user.age" :key="`age-${index}`">
</div>
<button #click.prevent="add_user">+</button>
</form>
</div>
You need to set tye type of the button, since it's inside a form it fallbacks to submit button.
Also, it's good to define a :key to help vue to tell the difference between one line to another on v-for.
new Vue({
el: '#exercise',
data: {
users: [{
id:new Date().getTime(),
name: "martin",
age: 32
}]
},
methods: {
add_user: function() {
this.users.push({
id:new Date().getTime(),
name: "",
age: ""
});
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="exercise">
<form id="list">
<div v-for="user in users" :key="user.id">
<input v-model="user.name">
<input v-model="user.age">
<button type="button" #click="add_user">+</button>
</div>
</form>
</div>

Validation Error messages on form load

About the issue
I am using Laravel 5.6.7 with vue.js. vee-validate is being used for validation
When the form loads, it shows validation error messages. User did not even click the submit button. Below is the screenshot.
Code
<template>
<div>
<form role="form">
<input v-validate data-vv-rules="required" type="text"
v-model="UpdateForm.First_Name">
<p v-if="errors.has('First Name')">{{ errors.first('First Name') }}</p>
<button type="button">
Update Profile
</button>
</form>
</div>
</template>
<script>
export default {
data() {
return {
UpdateForm: {
First_Name: ''
}
}
},
created() {
this.GetProfile();
},
methods: {
GetProfile() {
axios.post("some api url", {}).then(response => {
this.UpdateForm.First_Name = response.data.Data.First_Name;
});
}
}
}
</script>
Could I get rid of validation error messages on form load?
This is not the expected behavior. For initial validating you need to inform it with v-validate.initial.
Maybe you are defining this to happen when declaring v-validate or in other place.
Vue.use(VeeValidate);
new Vue({
el: '#demo'
})
.is-danger{
color: red;
}
<script src="https://unpkg.com/vue"></script>
<script src="https://cdn.jsdelivr.net/npm/vee-validate#latest/dist/vee-validate.js"></script>
<div id="demo">
<label>This one needs touching</label>
<input type="text" name="name" v-validate="'required'">
<div v-show="errors.has('name')" class="is-danger">Errors: {{ errors.first('name') }}</div>
<br/>
<label>This one does not need touching</label>
<input name="name2" v-validate.initial="'required'" type="text">
<div v-show="errors.has('name2')" class="is-danger">{{ errors.first('name2') }}</div>
</div>
Changed
this.editForm.First_Name = Data.User.First_Name;
to
if(Data.User.First_Name != null && Data.User.First_Name != "") {
this.editForm.First_Name = Data.User.First_Name;
}
and validation is working fine now. Basically the variable is not initialized.

Vue 2 - use same form for adding new and editing

I have following template:
<template>
<div>
<form #submit="save">
<div class="field">
<label class="label">Name</label>
<div class="control">
<input class="input" type="text" placeholder="Name" :value="book.title">
</div>
</div>
<div class="field">
<label class="label">Name</label>
<div class="control">
<input class="input" type="text" placeholder="Name" :value="book.author">
</div>
</div>
</form>
</div>
</template>
<script>
export default {
data() {
return {
book : {}
}
},
methods: {
save() {
}
},
created() {
if(this.$store.state.book != 'undefined'){
this.book = this.$store.state.book;
}
},
computed: {}
}
</script>
<style></style>
So far everything works fine if the book is pass with the this.$store.state.book, but if this is not passed the form is failing, with the error message:
** Error in render function: "TypeError: Cannot read property 'title' of undefined"**
I thought that passing the empty object would dynamically bind the book object and auto create the params.
Is it possible to use the same form for both adding new and editing?
I tried your code, and all you have to do is remove the 'quotes' from 'undefined'. Obviously, it's a string as is, and not a js thing.

vue js get multiple values from inputs

So I have 2 blocks of HTML, each containing 2 input fields and when submitting the form, I want to get all values from the inputs, and then create an object from the values...
As of know I've done it with plain vanilla JS and it works as it should, however if feels like to touching the DOM a bit to much, and also are very much depending on a specific DOM struckture, and therefore I was thinking there must be a better way, the VUE way so to speak, however im a bit stuck on how to do this the VUE way, which is why posting the question here in hope of getting some useful tips :)
HTML:
<form novalidate autocomplete="off">
<div class="input-block-container">
<div class="input-block">
<input type="text" placeholder="Insert name" name="name[]" />
<input-effects></input-effects>
</div>
<div class="input-block">
<input type="email" placeholder="Insert email address" name="email[]" />
<input-effects></input-effects>
</div>
</div>
<div class="input-block-container">
<div class="input-block">
<input type="text" placeholder="Insert name" name="name[]" />
<input-effects></input-effects>
</div>
<div class="input-block">
<input type="email" placeholder="Insert email address" name="email[]" />
<input-effects></input-effects>
</div>
</div>
<button class="button button--primary" #click.prevent="sendInvites"><span>Send</span></button>
</form>
JS:
methods: {
createDataObject() {
let emailValues = document.querySelectorAll('input[type="email"]');
emailValues.forEach((email) => {
let name = email.parentNode.parentNode.querySelector('input[type="text"]').value;
if(email.value !== "" && name !== "") {
this.dataObj.push({
email: email.value,
name
});
}
});
return JSON.stringify(this.dataObj);
},
sendInvites() {
const objectToSend = this.createDataObject();
console.log(objectToSend);
//TODO: Methods to send data to server
}
}
You can provide data properties for each of your inputs if you have static content.
data: function() {
return {
name1: '',
email1: '',
name2: '',
email2: ''
}
}
Then use them in your template:
<input type="text" placeholder="Insert name" v-model="name1" />
Access in method by this.name1
Try this
<div id="app">
<h1> Finds </h1>
<div v-for="find in finds">
<input name="name[]" v-model="find.name">
<input name="email[]" v-model="find.email">
</div>
<button #click="addFind">
New Find
</button>
<pre>{{ $data | json }}</pre>
</div>
Vue Component
new Vue({
el: '#app',
data: {
finds: []
},
methods: {
addFind: function () {
this.finds.push({ name: '', email: '' });
}
enter code here
}
});