I am using checkboxes to behave like radio buttons but the one behavior that I want to fix is the ability to keep the checkbox checked until the second one is checked (which will then uncheck the first one). I don't want the ability to deselect the checkbox by clicking on it again, just to hit the "none" checkbox to deselect the one below.
Referring to the image above, the label selects the checkbox as well. Once the checkbox is selected and is tapped on again, it goes back to the none checkbox on the left. Maybe radio buttons would be better, but I like checkboxes more. Here's the code:
<label :for="'none-'+product.id"
class="none addon_label"
:class="{'addon_selected': !selected}"
>
<input class=""
type="checkbox"
:id="'none-'+product.id"
:true-value="false"
:false-value="true"
:value="false"
v-model="selected"
checked
/>
<span class="checkmark addon_checkbox"></span>
<div class="v-center">None</div>
</label>
<label :for="'product-'+product.id"
class="is_flex addon_label"
:class="{'addon_selected': selected}"
:data-product-id="product.id"
>
<div class="checkbox-container">
<input class=""
type="checkbox"
:true-value="true"
:false-value="false"
:id="'product-'+product.id"
v-model="selected"/>
<span class="checkmark addon_checkbox"></span>
To do this, you just need to have two v-models, one for each button, and to create a function that when one of the two buttons changes, each of the values takes its opposite value.
Then, in order to avoid deselection by clicking on its own button, you use :disabled= with the reference of your button
Vue.js 3 with Composition
<script setup lang="ts">
import { ref } from "vue";
let selectedNone = ref(true);
let selectedChoice = ref(false);
function selectOption() {
selectedNone.value = !selectedNone;
selectedChoice.value = !selectedChoice;
}
</script>
<template>
<label>
<input
type="checkbox"
:value="false"
v-model="selectedNone"
:disabled="selectedNone"
#click="selectOption"
/>
<span>None</span>
</label>
<label >
<input
type="checkbox"
v-model="selectedChoice"
:disabled="selectedChoice"
#click="selectOption"
/>
<span>Choice</span>
</label>
</template>
You can use watch to check if the value of the checkbox has changed, and then either select all or deselect all, based on that.
Here's a quick demo
Vue.config.devtools = false;
Vue.config.productionTip = false;
new Vue({
el: '#app',
data: () => {
return {
options: {
check1: null,
check2: null,
check3: null,
},
check1: null,
check2: null,
check3: null,
deselect: null,
};
},
watch: {
deselect(isDeselected) {
if (isDeselected) {
this.options.check1 = false;
this.options.check2 = false;
this.options.check3 = false;
}
},
options() {
console.log("Change");
},
...["options.check1", "options.check2", "options.check3"].reduce(function (
acc,
currentKey
) {
acc[currentKey] = function (newValue) {
if (newValue) this.deselect = false;
};
return acc;
},
{}),
},
})
<script src="https://unpkg.com/vue#2.x/dist/vue.js"></script>
<div id="app">
<label for="check1">Check 1</label>
<input type="checkbox" v-model="options.check1" id="check1" />
<br />
<label for="check2">Check 2</label>
<input type="checkbox" v-model="options.check2" id="check2" />
<br />
<label for="check3">Check 3</label>
<input type="checkbox" v-model="options.check3" id="check3" />
<br />
<label for="deselect-check">Deselect All</label>
<input type="checkbox" v-model="deselect" id="deselect-check" />
</div>
Related
Example Form So Far
This is my current code that works, without any checkbox handling started.
import React, { useState } from "react";
import "../admin/SysHealthForm.scss";
export default function SysHealthForm() {
const [input, setInput] = useState({
header: "",
content: "",
eta: "",
});
//When any change is registered, update the Name + Value with target.
//Return previous text and display as name: entered value
function handleChange(e) {
const { name, value } = e.target;
setInput((prevInput) => {
return {
...prevInput,
[name]: value,
};
});
}
//Stop Page Refreshing and Console.log the JSON
function handleClick(e) {
e.preventDefault();
console.log(input);
}
return (
<div className="widgit-syshealth">
<h2>System Health</h2>
<form>
<input
name="header"
placeholder="Header"
autoComplete="off"
onChange={handleChange}
value={input.header}
required
></input>
<textarea
name="content"
placeholder="Message"
autoComplete="off"
onChange={handleChange}
value={input.content}
required
></textarea>
<div className="form-school-check">
<div>
<input type="checkbox" id="syshpcb1" value="Fosseway"></input>
<label htmlFor="syshpcb1">Fosse Way</label>
</div>
<div>
<input type="checkbox" id="syshpcb2" value="Mendip"></input>
<label htmlFor="syshpcb2">Mendip</label>
</div>
<div>
<input type="checkbox" id="syshpcb3" value="Nunney"></input>
<label htmlFor="syshpcb3">Nunney</label>
</div>
<div>
<input type="checkbox" id="syshpcb4" value="Hayesdown"></input>
<label htmlFor="syshpcb4">Hayesdown</label>
</div>
<div>
<input type="checkbox" id="syshpcb5" value="Moorlands"></input>
<label htmlFor="syshpcb5">Moorlands</label>
</div>
<div>
<input type="checkbox" id="syshpcb6" value="Cameley"></input>
<label htmlFor="syshpcb6">Cameley</label>
</div>
<div>
<input type="checkbox" id="syshpcb7" value="St Mary's"></input>
<label htmlFor="syshpcb7">St Mary's</label>
</div>
<div>
<input type="checkbox" id="syshpcb8" value="Other"></input>
<label htmlFor="syshpcb8">Other</label>
</div>
</div>
<input
placeholder="ETA For Fix"
onChange={handleChange}
value={input.eta}
name="eta"
></input>
<button type="Submit" onClick={handleClick}>
Submit
</button>
</form>
</div>
);
}
At The Moment, when you submit the data. It logs the header, content and eta etc correctly
but i want it to essentially create an Array of all the checkboxes that are ticked.
I just don't know where i would even begin..
Will be pushing the data back up to a MongoDB Atlas database once recieved.
Thanks
Reference link https://jsfiddle.net/8xom729c/
<div class="checkbox-alignment-form-filter">
<input type="checkbox" id="HR 3502 : 2004" class="vh-product" value="HR 3502 : 2004" v-model="checkboxestwo[0]" v-on:click="checkAlltwo()" />
<label class="productlist-specific" for="HR 3502 : 2004">HR 3502 : 2004</label
>
</div>
<div class="checkbox-alignment-form-filter7">
<input
type="checkbox"
id="E250A2"
class="vh-product"
v-model="checkboxestwo[1]"
value="E250A"
/>
<label class="productlist-specific" for="E250A2">E250A</label>
</div>
How to print selected checkbox value, I mean like when i click on any checkbox value, I need to display the selected value.
Is there any alternative way of doing it in vuejs.
Can anyone please give some inputs. Thanks
In spite of being usingv-model you can use click event as the code below #click="checkedInput. But the elegant solution is using v-model.If you need additional filtering before selecting a checkbox. You can use this type of click event
let vue = new Vue({
el: '#app',
data: {
checkedNames: [],
checkedName: true,
close: false
},
methods: {
uncheck: function(checkedName) {
this.checkedNames = this.checkedNames.filter(name => name !== checkedName);
this.$refs[checkedName.toLowerCase()].checked = false
},
uncheckall: function(event) {
this.checkedNames.forEach(e => this.$refs[e.toLowerCase()].checked = false)
this.checkedNames = [];
},
mouseOver: function() {
this.close = true;
},
mouseOut: function() {
this.close = false;
},
checkedInput(event) {
if (this.checkedNames.includes(event.target.value)) {
this.uncheck(event.target.value)
} else {
this.checkedNames.push(event.target.value)
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" />
<div id='app'>
<ul class="checkboxes">
<li><input type="checkbox" ref="jack" value="Jack" #click="checkedInput">
<label for="jack">Jack</label></li>
<li><input type="checkbox" ref="john" value="John" #click="checkedInput">
<label for="john">John</label></li>
<li><input type="checkbox" ref="mike" value="Mike" #click="checkedInput">
<label for="mike">Mike</label></li>
</ul>
<br/>
<ul class="tags">
<li #mouseover="mouseOver" #mouseleave="mouseOut" #click="uncheck(checkedName)" class="badge badge-pill badge-primary" v-for="checkedName in checkedNames">
{{ checkedName }}<span v-show="close" aria-hidden="true">×</span>
</li>
<li class="badge badge-pill badge-danger" #mouseover="mouseOver" #mouseleave="mouseOut" #click="uncheckall" v-show="checkedNames != ''">Clear</li>
</ul>
</div>
I am trying to create a card element where users can vote "yes", "no", or "maybe" on an image. Right now it is reading like the radio buttons 90 options for one image, rather than 30 individual ones with 3 options. How do I map over each card so the form is specific to the image? The array will read as
{ userChoices: {
characterName[0]:choice.value,
characterName[1]:choice.value,
....
}}
const choiceCard = characterData.map((character, key) =>
<div className="col-sm-12 col-md-3" id="choiceCard" key={character.id}>
<div id="choiceContent">
<img src={character.statusImage}/>
<div id="choice-inner" className="form">
<span>{character.name}</span>
<div class="form-check">
<input
class="form-check-input"
type="radio"
name="yes"
id="yes"
value="yes"/>
<label class="form-check-label" for="yes">
Yes
</label>
</div>
<div class="form-check">
<input
class="form-check-input"
type="radio"
name="no"
id="no"
value="no"/>
<label class="form-check-label" for="no">
No
</label>
</div>
<div class="form-check disabled">
<input class="form-check-input" type="radio" name="maybe" id="maybe" value="maybe"/>
<label class="form-check-label" for="maybe">
Maybe
</label>
</div>
</div>
</div>
</div>
);
You're close to where you want to be, there's just two things that need to be dealt with here:
Associating each set of buttons with a character.
Keeping track of the state for each character.
This is a natural use case for controlled components. A controlled radio button will look something like this:
<input
key={someID}
type="radio"
value={choice}
checked={this.state.choice === choice}
onChange={() => this.handleChange(choice)}
/>
with a change handler:
handleChange = newChoice => {
this.setState({
choice: choice
});
}
(see https://reactjs.org/docs/forms.html)
Applying this to your problem, you'd end up with something like this:
const choices = [
"Yes",
"No",
"Maybe"
]
const choiceCard = characterData.map((character, key) => {
return (
<label key={character.id}>
{character.name}
{choices.map(choice => {
return (
<input
key={choice}
type="radio"
value={choice}
checked={this.state.userChoices[key] === choice}
onChange={() => this.handleChange(choice, key)}
/>
);
})}
</label>
);
});
And the following change handler:
handleChange = (choice, key) => {
this.setState(prevState => ({
userChoices: { ...prevState.userChoices, [key]: choice }
}));
};
Here's a quick and dirty codepen you can play with to help your understanding: https://codepen.io/anon/pen/axzMxm?editors=0010
Check-all feature stops working when I try to get value of each checkbox in an array using v-model. I read lot of questions on different portals including stackoverflow, people are saying that v-model doesn't work with :checked attribute which I understand but could not find a solution / alternate code to make it work.
The 1st code that I tried was to select all checkboxes using the 1st checkbox. This works well. Code below:
new Vue({
el: "#app",
data: {
selectAll:false
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<label>
<input type="checkbox" v-model="selectAll">
Select all
</label>
<br>
<label>
<input type="checkbox" :checked="selectAll" value="Item 1">
Item 1
</label>
<br>
<label>
<input type="checkbox" :checked="selectAll" value="Item 2">
Item 2
</label>
<br>
<label>
<input type="checkbox" :checked="selectAll" value="Item 3">
Item 3
</label>
</div>
The 2nd code that I tried was to get value of each checkbox in an array but in this case 'select all' automatically stops working. Code below:
new Vue({
el: "#app",
data: {
selectAll:false,
eachCheckbox: [],
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<label>
<input type="checkbox" v-model="selectAll">
Select all
</label>
<br>
<label>
<input type="checkbox" :checked="selectAll" value="Item 1" v-model="eachCheckbox">
Item 1
</label>
<br>
<label>
<input type="checkbox" :checked="selectAll" value="Item 2" v-model="eachCheckbox">
Item 2
</label>
<br>
<label>
<input type="checkbox" :checked="selectAll" value="Item 3" v-model="eachCheckbox">
Item 3
</label>
<br>
Selected checkbox values: {{eachCheckbox}}
</div>
I don't know how to make this work. Can someone help please?
Use Vue.set to create objects in the checkbox array once an API call completes.
This shows a simulated async api call which takes 2.5 seconds to complete.
new Vue({
el: '#app',
data () {
return {
loading: false,
checkall: false,
checkboxes: []
}
},
methods: {
toggleAll () {
this.checkall = !this.checkall
this.checkboxes.forEach(c => {
c.checked = this.checkall
})
}
},
watch: {
checkboxes: {
deep: true,
handler: function () {
this.checkall = this.checkboxes.every(c => c.checked)
}
}
},
mounted () {
// simulate an async api call which takes 2.5 seconds to complete
this.loading = true
setTimeout(() => {
Array.from(Array(3), (c, i) => ({ checked: false, text: `Option ${i + 1}` })).forEach((c, i) => {
Vue.set(this.checkboxes, i, c)
})
this.loading = false
}, 2500)
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<input type="checkbox" #click="toggleAll" v-model="checkall"/> Check All<br/>
<div v-for="(c, i) in checkboxes" :key="i">
<input type="checkbox" v-model="c.checked"/>{{ c.text }}<br/>
</div>
<p v-if="!loading">Checked: {{ checkboxes.filter(c => c.checked).map(c => c.text).join(',') }}</p>
<p v-else>Fetching data...</p>
</div>
i had faced the same problem before and i didn't find a good solution, but i had tried something like the following :
new Vue({
el: "#app",
data: {
selectAll: false,
eachCheckbox: [],
},
methods: {
selectAllItems() {
this.selectAll ? this.eachCheckbox = ["Item 1", "Item 2", "Item 3"] : this.eachCheckbox = [];
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<label>
<input type="checkbox" v-model="selectAll" #change="selectAllItems">
Select all
</label>
<br>
<label>
<input type="checkbox" :checked="selectAll" value="Item 1" v-model="eachCheckbox">
Item 1
</label>
<br>
<label>
<input type="checkbox" :checked="selectAll" value="Item 2" v-model="eachCheckbox">
Item 2
</label>
<br>
<label>
<input type="checkbox" :checked="selectAll" value="Item 3" v-model="eachCheckbox">
Item 3
</label>
<br> Selected checkbox values: {{eachCheckbox}}
</div>
I am not able to click or select on any of my radio buttons. Can someone help me out how to work with radio buttons in react?
I tried removing e.preventDefault() but that didn't help either.
Here's what my code looks like:
File 1:
this.state = {
fields: {
gender: ''
}
}
fieldChange(field, value) {
this.setState(update(this.state, { fields: { [field]: { $set: value } } }));
}
<Form
fields={this.state.fields}
onChange={this.fieldChange.bind(this)}
onValid={() => handleSubmit(this.state.fields)}
onInvalid={() => console.log('Error!')}
/>
File 2:
render() {
const { fields, onChange, onValid, onInvalid, $field, $validation } = this.props;
return (
{/* Gender */}
<div id={styles.genderField} className={`form-group ${styles.formGroup} ${styles.projName}`}>
<label className="col-sm-2 control-label">Gender:</label>
<div className="col-sm-10">
<label className="radio-inline">
<input type="radio" name="gender" id="male"
checked={fields.gender === "Male"}
value={fields.gender} {...$field( "gender", e => onChange("gender", e.target.value)) } />
Male
</label>
<label className="radio-inline">
<input type="radio" name="gender" id="female"
checked={fields.gender === "Female"}
value={fields.gender} {...$field( "gender", e => onChange("gender", e.target.value)) } />
Female
</label>
</div>
</div>
<div className={`modal-footer ${styles.modalFooter}`}>
<button
className={`btn btn-primary text-white ${styles.saveBtn}`}
onClick={e => {
e.preventDefault();
this.props.$submit(onValid, onInvalid);
}}
>
Save
</button>
</div>
)
}
That's not how the docs handle onChange events. https://reactjs.org/docs/handling-events.html
You need to provide the full code to be able to help with that particular component.
Check out this working example: https://stackblitz.com/edit/react-radiobtns
class App extends Component {
constructor(props) {
super(props);
this.state = {selectedOption: 'option1'};
// This binding is necessary to make `this` work in the callback
this.handleOptionChange = this.handleOptionChange.bind(this);
}
handleOptionChange(changeEvent) {
this.setState({
selectedOption: changeEvent.target.value
});
}
render() {
return (
<form>
<label>
<input
onChange={this.handleOptionChange}
type="radio" value="option1"
checked={this.state.selectedOption === 'option1'}
name="radio1"/>
Option 1
</label>
<label>
<input
onChange={this.handleOptionChange}
checked={this.state.selectedOption === 'option2'}
type="radio"
value="option2"
name="radio1"/>
Option 2
</label>
<label>
<input
onChange={this.handleOptionChange}
checked={this.state.selectedOption === 'option3'}
type="radio"
value="option3"
name="radio1"/>
Option 3
</label>
</form>
);
}
}