How to set checked attribute to radio in litelement - javascript

I would like to know how to set checked to radio button using litelement.
I have a object and for each object options, radio button is created.
For example, for id=SG two radio buttons are created,
if no checked, set bank as default checked
else set corresponding selected radio value as checked.
I got stuck in litelement.
const obj= [{
id: "SG",
options: ["bank", "credit"]
},
{
id: "TH",
options: ["bank"]
}
];
render(){
${obj.map((e)=>{
return html`
<form>
${obj.options.map((option_value)=>{
return html`
<input class="form-check-input" name="sending-${option_value}" type="radio" id="provider-send-${option_value}" value=${option_value} ?checked=${option_value=="bank"} > // not working
<label class="form-check-label">
${option_value}
</label><br>
`})}
</form>
})`;
}
Expected Output:
Set checked to corresponding radio selected
If no checked, set bank as default checked

This sets the checked attribute to true if the option is bank:
import { LitElement, html } from 'lit-element';
class TestElement extends LitElement {
static get properties() {
return {
countries: {
type: Array,
},
};
}
constructor() {
super();
this.countries = [
{
id: 'SG',
options: ['bank', 'credit'],
},
{
id: 'TH',
options: ['bank'],
},
{
id: 'MY',
options: ['credit'],
}
];
}
render() {
return html`
${this.countries.map(country => html`
<fieldset>
<legend>${country.id}</legend>
<form>
${country.options.map(option => html`
<input
id="provider-send-${option}"
name="sending-${country.id}"
type="radio"
class="form-check-input"
value="${option}"
?checked=${option === 'bank'}
>
<label class="form-check-label">${option}</label>
<br>
`)}
</form>
</fieldset>
`)}
`;
}
}
customElements.define('test-element', TestElement);
Looks like you just missed mapping the actual obj (country in my snippet).
Also, in order to change the selected radio, the name should be the same for all radios in a group. Your code is setting a different name to each radio.

Related

How to get the values of default checked checkbox

I was working on a project of multiple checkbox. There, I want the checkboxes to be checked from the start and the value to be in the form(I am using reactive form). The user can unselect the boxes according to their wish and the data will be stored accordingly. This is the stackblitz of the project. There I was able to make the checkbox checked from the beginning, but when I hit the submit button there is no data when I console-logged. I think this is some binding issue,but I couldn't figure out what is exactly the problem.
Can someone help?
Thanks in advance.
This is code:
<form [formGroup]="form" (ngSubmit)="submit()">
<div class="form-group">
<label for="website">Website:</label>
<div *ngFor="let web of websiteList">
<label>
<input
type="checkbox"
[value]="web.id"
(change)="onCheckboxChange($event)"
[checked]="web.isSelected"
/>
{{ web.name }}
</label>
</div>
</div>
<button class="btn btn-primary" type="submit">Submit</button>
</form>
form: FormGroup;
websiteList: any = [
{ id: 1, name: 'HDTuto.com', isSelected: true },
{ id: 2, name: 'HDTuto.com', isSelected: true },
{ id: 3, name: 'NiceSnippets.com', isSelected: true },
];
constructor(private fb: FormBuilder) {
this.form = this.fb.group({
website: this.fb.array([], [Validators.required]),
});
}
ngOnInit() {}
onCheckboxChange(e: any) {
const website: FormArray = this.form.get('website') as FormArray;
console.log('checking ->', e);
if (e.target.checked) {
website.push(new FormControl(e.target.value));
console.log('website ->', website);
} else {
//console.log(e);
const index = website.controls.findIndex((x) => {
console.log('x.value ->', x.value);
console.log('target.value ->', e.target.value);
x.value === e.target.value;
});
website.removeAt(index);
}
}
submit() {
console.log(this.form.value);
}
https://stackblitz.com/edit/angular-ivy-qar4ph?file=src/app/app.component.ts
Pay attention to changes in template:
Added formArrayName attribute to checkboxes wrapper and formControlName attribute to input element.
Removed change and checked attributes
In the component ts file:
Added initial form array values
Added mapping to submit method
Removed onCheckboxChange method

Appropriate two way binding for checkboxes in Vue JS

I have the data from MySQL database in the form of "1" and "0" representing the boolean true and false.These values are set in the vue component in the following manner :
data(){
return {
form : {
attribute_1 : "1", //attribute 1 is true
attribute_2 : "0", //attribute 2 is false
attribute_3 : "1", //attribute 3 is true
}
}
}
To maintain the two-way binding I am currently using the computed properties as follows :
attribute1: {
get(){
return this.form.attribute_1 == "1" ? true : false ;
},
set(newValue){
this.form.attribute_1 = newValue ? "1" : "0";
}
},
attribute2: {
get(){
return this.form.attribute_2 == "1" ? true : false ;
},
set(newValue){
this.form.attribute_2 = newValue ? "1" : "0";
}
}, ...
These computed properties are wired on HTML code in following manner.
<input type="checkbox" checked v-model="attribute1">
<input type="checkbox" checked v-model="attribute2">
This works quite good for the two way binding in VUE. But there is a severe repetition in the code.
There is another way I have in mind using the #change event to track the changes in the checkbox :checked property and change the data attributes according but It seems to be one way binding and in the Vue console values are only updated when the I refresh the VUE panel.
Is there is a better way to achieve two way binding in this particular scenario?
You can achieve this by simply updating your template like:
<input type="checkbox" v-model="form.attribute1" :true-value="1" :false-value="0">
<input type="checkbox" v-model="form.attribute2" :true-value="1" :false-value="0">
and that's it. You will not need any computed properties anymore. You will get this.form.attribute1 value as "1" when checkbox will be checked or "0" when unchecked. Also, if you set form.attribute1 value as "1" then the checkbox will be checked by default as shown in the demo below.
DEMO:
new Vue({
el: '#app',
data(){
return {
form: {
attribute1: "1", //attribute 1 is true
attribute2: "0" //attribute 2 is false
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<input type="checkbox" v-model="form.attribute1" :true-value="1" :false-value="0">
<label for="checkbox">{{ form.attribute1 }}</label><br/><br/>
<input type="checkbox" v-model="form.attribute2" :true-value="1" :false-value="0">
<label for="checkbox">{{ form.attribute2 }}</label><br/><br/>
</div>
My favorite solution is to create component to achieve that:
My Checkbox.vue component:
<template>
<input type="checkbox" :checked="isChecked" #change="change" />
</template>
<script>
export default {
props: {
value: {}
},
computed: {
isChecked() {
return this.value === "1" || this.value === true;
}
},
methods: {
change(e) {
this.$emit("input", e.target.checked ? "1" : "0");
}
}
};
</script>
and use it in other components:
<template>
<div>
<Checkbox v-model="isChecked" />
</div>
</template>
<script>
import Checkbox from "./Checkbox";
export default {
components: {
Checkbox
},
data: () => ({
isChecked: "1"
})
};
</script>

React - how to pass multiple input values to child in on change event when values have different types (is not always e.target.value)?

I have multiple input fields and 1 react-select dropdown field. I created a method in my parent component that sets the state with the values from the input, passes it down to the child which should call the method. My problem is that react-select doesn't take the value but an object like this:
{value: 'xy', name:'x', label: 'y'}
so normally my function in my onChange event handler would look like this (when passing multiple values):
in parent:
testing(e) {
this.setState({
[e.target.name]: e.target.value
})
}
in child:
<input type="text" name="maxfare" onChange={this.onChange}/>
...
onChange(e){
var value = [e.target.name] = e.target.value;
this.props.onChange(value);
}
...
However, while my input fields take:
e.target.value
my select dropdown takes entire 'e' - not e.target.value. I tried to pass my onChange function in child component 2 arguments, calling my method in parent with 2, but that doesn't to work. Any help would be great! My code is below (the relevant parts- if I forgot something that you think is important, please let me know). Ps. I thought about having 2 onChange functions, passing once my value for select dropdown and a second one doing the rest, but then I would need to pass 2 onChange methods to the child and I believe thats not possible in react?! Thanks!!:
Parent:
...
onChangeT(selectValue, value) {
this.setState({
origin: selectValue,
maxfare: value
...
})
}
render(){
....
<Parent cities={this.state.citiesToSelect} origin={this.state.origin} maxfare={this.state.maxfare} onChange={this.onChangeT}/>
...
}
Child:
....
onChangeC(e){
var value = [e.target.name] = e.target.value;
this.props.onChange(e, value);
console.log("name", name)
}
....
<Select
onChange={this.onChangeC}
labelKey='name'
value={this.props.origin}
options={this.props.cities}
/>
<input type="text" name="maxfare" onChange={this.onChangeC}/>
We want to be able to do this in the parent
onChange = (name, value) => {
this.setState({[name]: value});
}
We fix the "wiring" of the children onChange to do exactly that, raise an onChange with a name and a value. Wrap react-select and provide a consistent interface to the parent.
Form example
import * as React from 'react';
import Input from './Input';
import Select from './Select';
export default class Form extends React.Component {
state = {
input: '',
select: '',
options: ['A', 'B', 'C']
};
onChange = (name: string, value: string) => {
this.setState({[name]: value});
}
render() {
return (
<form>
<Input
label="Surname"
name={'input'}
value={this.state.input}
onChange={this.onChange}
/>
<Select
label="Grade"
name={'select'}
value={this.state.select}
options={this.state.options}
onChange={this.onChange}
/>
</form>
);
}
}
Input example
import * as React from 'react';
export default class Input extends React.Component {
onChange = (e) => {
const {onChange, name} = this.props;
if (onChange) {
onChange(name, e.currentTarget.value);
}
}
render() {
return (
<div>
<label>{this.props.label}</label>
<input
type="text"
name={this.props.name}
value={this.props.value}
onChange={this.onChange}
/>
</div>
);
}
}
And a DOM native <Select /> example
import * as React from 'react';
export default class Select extends React.Component {
onChange = (e) => {
const {onChange, name} = this.props;
if (onChange) {
onChange(name, e.currentTarget.value);
}
}
render() {
return (
<div>
<label>{this.props.label}</label>
<select
name={this.props.name}
value={this.props.value}
onChange={this.onChange}
>
{this.props.options.map(o => <option key={o}>{o}</option>)}
</select>
</div>
);
}
}
The fact that react-select doesn't return a native event nor a similar object shape of a native event, is forcing you to normalize the shape of the object that returned from it. You can do that by wrapping the Select component of react-select with your own component and returning a custom object for your use-case.
In this example we are trying to normalize the behavior of our onChange event both for inputs and Select. We will first check if the object that returned is having a target key, if it does we know that this is a native event that we are handling and we will set the state according to the name of the input and its value (exactly how you did it in your example).
If we don't have a target key, then we may handle a different kind of event.
We will check if we get a selectedValue key (just a convention between yourself, you can change the key as you like), then we will set the state by its name and selectedValue that we received.
This will only work if you will pass the name upwards of course.
So the object that you need to return from the custom Select component should look something like this:
{name: this.props.name, selectedValue }
// where selectedValue is the object received from the real Select component
Here is a running example:
const options = [
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two' },
]
const moreOptions = [
{ value: 'mike', label: 'johnson' },
{ value: 'lynda', label: 'bog' },
]
class MySelect extends React.Component {
handleChange = selectedValue => {
const { name, onChange } = this.props;
onChange({ name, selectedValue });
}
render() {
const { options, value, ...rest } = this.props;
return (
<Select
{...rest}
value={value}
onChange={this.handleChange}
options={options}
/>
);
}
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
option1: '',
option2: '',
value1: 1,
value2: '',
value3: 3,
}
}
handleChange = e => {
let nextState;
if (e.target) {
const { name, value } = e.target;
nextState = { [name]: value };
} else if (e.selectedValue) {
const { name, selectedValue } = e;
nextState = { [name]: selectedValue };
}
this.setState(nextState);
}
render() {
const { value1, value2, value3, option1, option2 } = this.state;
return (
<div>
<MySelect
value={option1.value}
onChange={this.handleChange}
options={options}
name="option1"
/>
<div>
<span>input1 </span>
<input value={value1} name="value1" onChange={this.handleChange} />
</div>
<div>
<span>input2 </span>
<input value={value2} name="value2" onChange={this.handleChange} />
</div>
<div>
<span>input3 </span>
<input value={value3} name="value3" onChange={this.handleChange} />
</div>
<MySelect
value={option2.value}
onChange={this.handleChange}
options={moreOptions}
name="option2"
/>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://unpkg.com/prop-types#15.5.10/prop-types.js"></script>
<script src="https://unpkg.com/classnames#2.2.5/index.js"></script>
<script src="https://unpkg.com/react-input-autosize#2.0.0/dist/react-input-autosize.js"></script>
<script src="https://unpkg.com/react-select/dist/react-select.js"></script>
<link rel="stylesheet" href="https://unpkg.com/react-select/dist/react-select.css">
<div id="root"></div>

React Jest: How to get the state of checkbox

I'm trying to find the checked status of a checkbox in a React component. This is my component:
class Checkboxes extends React.Component {
constructor() {
super();
console.log('Hello world!');
this.state = {
filterEnabled: {
'desserts': true,
'juices': true,
'meats': true,
'veggies': true,
},
isApplyingFilter: false
};
}
getInitialState () {
return {
filterEnabled: {
'desserts': true,
'juices': true,
'meats': true,
'veggies': true
},
isApplyingFilter: false
};
}
render () {
const { isApplyingFilter } = this.props;
return (
<div>
<div className="row">
<div className="col-md-12">
<div className="mt-checkbox-inline">
<label className="mt-checkbox">
<input type="checkbox" name="desserts" value="desserts"
checked={this.state.filterEnabled.desserts}
/>
<span>desserts</span>
</label>
<label className="mt-checkbox">
<input type="checkbox" name="juices" value="juices"
checked={this.state.filterEnabled.juices}
/>
<span>juices</span>
</label>
<label className="mt-checkbox">
<input type="checkbox" name="meats" value="meats"
checked={this.state.filterEnabled.meats}
/>
<span>meats</span>
</label>
<label className="mt-checkbox">
<input type="checkbox" name="veggies" value="veggies"
checked={this.state.filterEnabled.veggies}
/>
<span>veggies</span>
</label>
</div>
</div>
</div>
</div>
);
}
}
I wrote the following test scenario:
it('Applying "foods" filter will display only selected food items.', () => {
// Locate the checkboxes div
var checkboxes = TestUtils.scryRenderedDOMComponentsWithTag(DOM, 'input');
// Pick the first checkbox
var cb = checkboxes[0].attributes;
// prints out "desserts"
console.log('name: ', cb['name'].value);
// prints out an empty string
console.log('checked: ', cb['checked'].value);
});
When I attempt to get the value for cb['checked'], it simply prints out an empty string ''. I'm expecting to get true instead.
What is the correct way to get the state of the checkbox?
Since you set checked to be equal to this.state.filterEnabled, it would be enough to just check the state.
expect(this.state.filterEnabled.desserts).toBe(true);

Working with Radio Buttons on Flux

Just started my first app in React and I want to know if there is a React way to work with Radio Buttons, I have a form with 4 radio buttons, I need to take 2 of the options selected and send that info to a backend.
class RadioBtns extends Component {
constructor (props) {
super(props);
this.state = {
greet : '',
hello : '',
};
}
render () {
return (
<div>
<div>
<form>
<input type="radio" value="first" name="greet" onChange={this._onChangeGreet}/> Option 1
<input type="radio" value="second" name="greet" onChange={this._onChangeGreet}/> Option 2
<input type="radio" value="three" name="hello" onChange={this._onChangeHello}/> Option 3
<input type="radio" value="four" name="hello" onChange={this._onChangeHello}/> Option 4
</form>
<hr />
<button type="submit" onClick={this._submitSettings}>YES!</button>
</div>
</div>
);
}
_onChangeGreet = ({ target }) => {
this.setState({
greet : target.value,
});
}
_onChangeHello = ({ target }) => {
this.setState({
hello : target.value,
});
}
_submitSettings = () => {
console.log('submit');
}
}
export default RadioBtns;
how do I send this states with the values to the stores ?
and here I have the action
#createActions(flux)
class RadioBtnsActions {
constructor () {
this.generateActions('optionSelected');
}
}
export default RadioBtnsActions;
and in the Store
import flux from 'flux';
import RadioBtnsActions from 'actions/RadioBtnsActions';
#createStore(flux)
class RadioBtnsStore {
constructor () {
this.state = {
radioSelected : false,
};
}
#bind(RadioBtnsActions.optionSelected)
optionSelected (option) {
this.setState({
radioSelected : option,
});
}
}
export default RadioBtnsStore;
Here's what we did in our project (simplified, use your imagination):
First you create a RadioButton component that renders the actual input:
render(){
<div>
<input id={this.props.id} type="radio"
name={this.props.name} value={this.props.value}
checked={this.props.checked} onChange={this.onChange}/>
<label htmlFor={this.props.id}>{this.props.label}</label>
</div>
},
onChange: function(ev){
this.props.onChange(ev.target.checked, this.props.value);
}
Then you use that to implement a RadioButtonGroup component:
render: function(){
var name = this.name, value = this.props.value, onChange = this.onSingleRadioChange;
var options = _.map(this.props.options, function(option){
var id = name + '-' + option.value;
return <RadioButton key={option.value} id={id} name={name} value={option.value} label={option.label} checked={option.value == value} onChange={onChange} />
});
return <div>{options}</div>
},
onSingleRadioChange: function(checked, value){
if(checked)
this.props.onChange(value);
}
You can use it like this:
<RadioButtonGroup name='greet' options={[{value: 'first', label: 'First'}, {value: 'second', label: 'Second'}]} onChange={val => { Actions.radioGroupChanged('greet', val);}} />
Where Actions.radioGroupChanged is the action that your store is listening on.
Don't forget to use labels for better UX.
Edit: here's a rough draft of the store, although we use Reflux, so it's a different API that what you have:
var store = Reflux.createStore({
radioGroups: {greet: 'first', hello: 'three'}, //state of the radio button groups lives here
init(){
this.listenTo(Actions.radioGroupChanged, this.onRadioGroupChanged);
},
onRadioGroupChanged(group, value){
this.radioGroups[group] = value;
this.trigger(); //this notifies the component that the store changed;
}
});
The component then listens to the store and updates its own state:
componentDidMount(){
this.listenTo(store, () => { this.setState({radios: store.groups}) });
}
render(){
return <RadioButtonGroup name='greet' value={this.state.radios.greet} .../>
}

Categories

Resources