Abnormal behaviour of radio button when click - html

I have created a radio button in parent and child relationship. Like main is parent and sub is its child.
When I checked the parent div radio button, and after that trying to checked the its child div radio button, then parent div radio button automatically unchecked. I don't know how ?
Here is the code .
import React from 'react';
class Body extends React.Component {
constructor(props) {
super(props);
this.state = {
length :1,
arr:[{
subLen:2
},{
subLen:0
},{
subLen:1
}]
}
this.addMain = this.addMain.bind(this);
this.addSub = this.addSub.bind(this);
}
addMain(event) {
let temp = this.state.arr;
temp.push({subLen:0});
this.setState({arr:temp});
}
addSub(event,i){
console.log("add sub click ",i);
let temp = this.state.arr;
temp[i].subLen=temp[i].subLen+1;
this.setState({arr:temp},()=>{
console.log(this.state.arr);
});
}
render() {
return (
<div>
{
this.state.arr.map((e1,i1)=>{
return <div>
<h1>Main part</h1>
<input type="text" name={`${i1}name`}
placeholder="Enter name"/><br/>
Male:<input type="radio" name=
{`${i1}gender`} value="Male"/>
Female:<input type="radio" name=
{`${i1}gender`} value="Female"/>
{e1.subLen> 0 && <h2>Sub Part</h2>}
{e1.subLen > 0 &&
Array(e1.subLen).fill().map((e2,i2)=>{
return <div>
<input type="text" name=
{`${i2}name`} placeholder="Enter name"/><br/>
Male:<input type="radio" name=
{`${i2}gender`} value="Male"/>
Female:<input type="radio" name=
{`${i2}gender`} value="Female"/>
</div>
})
}
<button onClick=
{(event)=>this.addSub(event,i1)}>Add Sub</button>
</div>
})
}
<button onClick={this.addMain}>Add More</button>
<button onClick=
{()=>console.log(this.state.arr)}>Show</button>
</div>
)
}
}
export default Body;
As you see in the image that while clicking the sub part radio buttons main part radio button unchecked automatically
I don't know why this is happening ?

Issue
Because you are using an array index as part of the radio input name and with the same suffix (i.e. "gender") they become part of the same radio button group.
Solution
Use more specific names to disambiguate the main inputs from the sub inputs.
I suggest "main-${index}-name" and "main-${index}-gender" for the main inputs, and "sub-${index}-name" and "sub-${index}-gender" for the sub inputs.
{this.state.arr.map((e1, i1) => {
return (
<div>
<h1>Main part</h1>
<input type="text" name={`main-${i1}-name`} placeholder="Enter name" />
<br />
Male:
<input type="radio" name={`main-${i1}-gender`} value="Male" />
Female:
<input type="radio" name={`main-${i1}-gender`} value="Female" />
{e1.subLen > 0 && <h2>Sub Part</h2>}
{e1.subLen > 0 &&
Array(e1.subLen)
.fill()
.map((e2, i2) => {
return (
<div>
<input
type="text"
name={`sub-${i2}-name`}
placeholder="Enter name"
/>
<br />
Male:
<input type="radio" name={`sub-${i2}-gender`} value="Male" />
Female:
<input type="radio" name={`sub-${i2}-gender`} value="Female" />
</div>
);
})}
<button onClick={(event) => this.addSub(event, i1)}>Add Sub</button>
</div>
);
})}

Related

How to change input filed border color into red. When fields are empty

Here I have written a code for validating form input fields in Vue. And it is working fine when input fields are empty the form is not navigating to the next step. My issue is that while the field is empty, and the user tries to navigate to the next step, the input field border color should change in red. If one field is empty and the user is trying to navigate another step, the navigation should prevent, and the empty fields' border should be displayed in red.
<div id="vk_app">
<form>
<div v-if="step === 1">
<h1>Step One</h1>
<p>
<legend for="name">Your Name:</legend>
<input id="name" name="name" v-model="name">
<input id="name" name="name" v-model="age">
</p>
<button #click.prevent="next()">Next</button>
</div>
<div v-if="step === 2">
<template>
<input id="name" name="name" v-model="address">
<input id="name" name="name" v-model="h_no">
<input id="name" name="name" v-model="mobile">
<button #click.prevent="prev()">Previous</button>
<button #click.prevent="next()">Next</button>
</template>
</div>
<div v-if="step === 3">
<template>
<input id="name" name="name" v-model="subject">
<input id="name" name="name" v-model="occupation">
<button #click.prevent="prev()">Previous</button>
<button #click.prevent="next()">Next</button>
</template>
<button #click.prevent="prev()">Previous</button>
<button #click.prevent="submit()">Save</button>
</div>
</form>
</div>
vue.js
const app = new Vue({
el:'#vk_app',
data() {
return {
step:1,
name:null,
age:null,
city:null,
state:null,
}
},
methods:{
prev() {
if(this.checkForm()) {
this.step--;
}
},
next() {
if(this.checkForm()) {
this.step++;
}
},
checkForm: function (e) {
if (this.name && this.age) {
return true;
}
this.errors = [];
if (!this.name) {
this.errors.push('Name required.');
}
if (!this.age) {
this.errors.push('Age required.');
}
e.preventDefault();
}
}
});
Here is my answer for your code example, it will work when you click on next button.
Updated HTML and Inputs:
<div id="vk_app">
<form>
<div v-if="step === 1">
<h1>Step One</h1>
<legend for="name">Your Name:</legend>
<input id="name" :class="errorField.name ? 'error-input' : ''" name="name" v-model="name" />
<input id="name" :class="errorField.age ? 'error-input' : ''" name="name" v-model="age" />
<button #click.prevent="next()">Next</button>
</div>
<div v-if="step === 2">
<template>
<input id="name" name="name" :class="errorField.address ? 'error-input' : ''" v-model="address" />
<input id="name" name="name" :class="errorField.h_no ? 'error-input' : ''" v-model="h_no" />
<input id="name" name="name" :class="errorField.mobile ? 'error-input' : ''" v-model="mobile" />
<button #click.prevent="prev()">Previous</button>
<button #click.prevent="next()">Next</button>
</template>
</div>
<div v-if="step === 3">
<template>
<input id="name" name="name" v-model="subject">
<input id="name" name="name" v-model="occupation">
<button #click.prevent="prev()">Previous</button>
<button #click.prevent="next()">Next</button>
</template>
<button #click.prevent="prev()">Previous</button>
<button #click.prevent="submit()">Save</button>
</div>
</form>
</div>
Vue Functions and Data Update:
data() {
return {
errorField: { name: false, age: false, city: false, state: false },
step:1,
name:null,
age:null,
city:null,
state:null,
}
},
methods:{
prev() {
if(this.checkForm()) {
this.step--;
}
},
next() {
if(this.checkForm()) {
this.step++;
}
},
checkForm: function (e) {
if (this.name && this.age) {
return true;
}
this.errors = [];
if (!this.name) {
this.errorField.name = true
this.errors.push('Name required.');
}
if (!this.age) {
this.errorField.age = true
this.errors.push('Age required.');
}
}
}
Since this feature(red border on invalid input) is required more often, we can use dynamic classes :
in style section define a class
.input--error{
border-color:red;
}
and in template section add
:class="{'input--error':!name}"
to input tag making it look like :
<input id="name" name="name" v-model="name" :class="{'input--error':!name}"/>
The whole code would look something like this:
<template>
<div>
<!-- Using dynamic classes -->
<input id="name" name="name" v-model="name" :class="{'input--error':!name}"/>
<input id="name" name="name" v-model="age" :class="{'input--error':!age}"/>
</div>
</template>
<script>
export default {
data(){
return{
name:null,
age:null
}
}
}
</script>
<style scoped>
.input--error{
border-color:red;
}
</style>
We could also add this directly in style attribute in input tag:
<input id="name" name="name" v-model="mobile" :style="!mobile ? 'border-color:red':''">
This would overcrowd the code unnecessarily.
We have a blur event.
When blur event fired, if the input box was empty (or whatever you want), add a class such as "red" to the input box.
<input id="name" name="name" v-model="name" #blur="validation($event.target)">
const validation = el => {
if (!el.value) {
// this is a very simple examples. I don't recommend using jQuery.
$(el).addClass('red');
}
};
Add.
You can use the method on Next() method.
<input id="name" name="name" v-model="name" ref="name">
const next = () => {
const inputName = this.$refs.name; // this if for just Vue2.
if (!inputName.value) {
$(inputName).addClass('red');
}
};

HTML forms are a mystery

I am taking a Vue.js course and I just learned about forms and managing them(the code is down below). I don't understand how does the tag work. It's value is determined by the option value and the selected text is the text of that specific option? Also, I am confused when it comes to checkboxes and Vue. Why do the checkboxes need different "value"s when you use v-model on that checkbox? Why would I want to create a checkbox group (inputs with the same value for the name attribute)? I don't really understand how v-model works with forms and I would love to. Thanks in advance for the person that's taking time to help me.
The Code
<template>
<form #submit.prevent="submitForm">
<div class="form-control">
<label for="user-name">Your Name</label>
<input id="user-name" name="user-name" type="text" v-model="userName" />
</div>
<div class="form-control">
<label for="age">Your Age (Years)</label>
<input id="age" name="age" type="number" v-model.number="userAge" />
</div>
<div class="form-control">
<label for="referrer">How did you hear about us?</label>
<select id="referrer" name="referrer" v-model="referrer">
<option value="google">Google</option>
<option value="wom">Word of mouth</option>
<option value="newspaper">Newspaper</option>
</select>
{{ referrer }}
</div>
<div class="form-control">
<h2>What are you interested in?</h2>
<div>
<input id="interest-news" name="interest" value="news" type="checkbox" v-model="interests"/>
<label for="interest-news">News</label>
</div>
<div>
<input id="interest-tutorials" name="interest" value="tutorials" type="checkbox" v-model="interests"/>
<label for="interest-tutorials">Tutorials</label>
</div>
<div>
<input id="interest-nothing" name="interest" value="nothing" type="checkbox" v-model="interests"/>
<label for="interest-nothing">Nothing</label>
</div>
</div>
<div class="form-control">
<h2>How do you learn?</h2>
<div>
<input id="how-video" name="how" value="video" type="radio" v-model="how"/>
<label for="how-video">Video Courses</label>
</div>
<div>
<input id="how-blogs" name="how" value="blogs" type="radio" v-model="how"/>
<label for="how-blogs">Blogs</label>
</div>
<div>
<input id="how-other" name="how" value="other" type="radio" v-model="how"/>
<label for="how-other">Other</label>
</div>
</div>
<div class="form-control">
<input type="checkbox" id="confirm-terms" name="confirm-terms" v-model="confirm">
<label for="confirm-terms">Agree to terms of use?</label>
</div>
<div>
<button>Save Data</button>
</div>
<div class="form-control">
<select></select>
</div>
</form>
</template>
<script>
export default {
data() {
return {
userName: "",
userAge: null,
referrer: "newspaper",
interests: [],
how: null,
confirm: false
};
},
methods: {
submitForm() {
// console.log("Username: " + this.userName);
// this.userName = "";
// console.log("User age: ");
// console.log(this.userAge);
// console.log(31);
// this.userAge = null;
// console.log("Referrer: " + this.referrer);
// this.referrer = "wom";
// console.log("Checkboxes: ");
// console.log(this.interests);
console.log("Radio Buttons");
console.log(this.how);
this.interests = [];
this.how = null;
// console.log('Confirm? ');
// console.log(this.confirm);
// this.confirm = false;
},
},
};
</script>
v-model is syntactical sugar for :value and #change
Instead of <input v-model="name">, you could use
<input :value="name" #update:model-value="v => name=v"> which would have the same result.
Here is an example that perhaps belabors it a bit.
const app = Vue.createApp({
data() {
return {
name: ""
}
}
})
app.component('custom-input', {
props: ['modelValue'],
emits: ['update:modelValue'],
template: `
<input
:value="modelValue"
#input="$emit('update:modelValue', $event.target.value)"
>
`
})
app.mount("#app")
<script src="https://unpkg.com/vue#next/dist/vue.global.prod.js"></script>
<div id="app">
<custom-input :value="name" #update:model-value="v => name=v"></custom-input><br />
<custom-input v-model="name"></custom-input><br />
<input :value="name" #update:model-value="v => name=v"><br />
<input v-model="name"><br />
Name: {{name}}
</div>
More info in v3 docs here

Show and hide html elements depending on radio selection

Yes, there are many posts that are kind of similar but not like mine I guess. After struggling for a while I'm not able to come up with a solution. I need help!
I have 4 different criteria:
Resident/Single, Resident/Family, Non-Resident/Single, Non-Resident/Family
For example: if Resident and Single are checked then show that div. The rest goes the same way.
<fieldset>
<ol id="membership">
<li>
<input type="radio" name="resident" value="Resident" checked="checked" /> Resident
<input type="radio" name="resident" value="Non-Resident" /> Non-Resident
</li>
<li>
<input type="radio" name="single" value="Single" checked="checked" /> Single
<input type="radio" name="single" value="Family" /> Family
</li>
</ol>
<div style="display: none;">
<div>Resident/Single</div>
<div>Resident/Family</div>
<div>Non-Resident/Single</div>
<div>Non-Resident/Family</div>
</div>
</fieldset>
This is as far as I was able to go.
$(document).ready(function() {
$('input').change(function() {
if ($('input[value="Resident"]').is(':checked') && $('input[value="Single"]').is(':checked')) {
$('div').show();
} else if ($('input[value="Resident"]').is(':checked') && $('input[value="Family"]').is(':checked')) {
$('div').show();
} else if ($('input[value="Non-Resident"]').is(':checked') && $('input[value="Single"]').is(':checked')) {
$('div').show();
} else if ($('input[value="Non-Resident"]').is(':checked') && $('input[value="Family"]').is(':checked')) {
$('div').show();
} else {
$('div').hide();
}
});
});
This is my repl: https://repl.it/#labanino/Show-based-on-selection#script.js
Instead of using ifs statement to show/hide divs you can simply get the checked values of radio button then just loop through your divs and compare if the .text() is equal to radio values show that divs only .
Demo Code :
$(document).ready(function() {
$(".category div:eq(0)").show() //show 1st div
$('input').change(function() {
//get radio values
var value = $("input[name='resident']:checked").val();
var value1 = $("input[name='single']:checked").val();
console.log(value + "/" + value1)
$(".category div").hide(); //hide all divs
var divss = value + "/" + value1;
//loop through divs
$(".category div").each(function() {
if ($(this).text() === divss) {
$(this).show() //show that div
}
})
});
})
.category > div {
display: none
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<fieldset>
<ol id="membership">
<li>
<input type="radio" name="resident" value="Resident" checked="checked" /> Resident
<input type="radio" name="resident" value="Non-Resident" /> Non-Resident
</li>
<li>
<input type="radio" name="single" value="Single" checked="checked" /> Single
<input type="radio" name="single" value="Family" /> Family
</li>
</ol>
<div class="category">
<div>Resident/Single</div>
<div>Resident/Family</div>
<div>Non-Resident/Single</div>
<div>Non-Resident/Family</div>
</div>
</fieldset>
Try selecting the divs by name or value and show them while hiding the others.
Check this repl -
https://repl.it/#DavidThomas12/Show-based-on-selection
I believe it fits your use case.

Get all values for elements in a div

I have a for loop in and it generation id for div
i need to get all values for elements in a div when click any element at div
<div id="{{ item3.id }}" (click)="getChildren($event)">
<input type="checkbox" name="status" [checked]="item3.templatesFields.status"/>
<input type="checkbox" name="inMain" [checked]="item3.templatesFields.inMain" />
</div>
and this ts code
public getChildren(e) {
}
Try This
getChildren(e)
{
if (e.target.children.length!=0) {
var g=Array.from(e.target.children).forEach(y=>console.log(y.value))
console.log(g);//here your values
}
<div id="{{ item3.id }}" (click)="getChildren(ch1, ch2)">
<input type="checkbox" name="status" #ch1 [checked]="item3.templatesFields.status"/>
<input type="checkbox" name="inMain" #ch2 [checked]="item3.templatesFields.inMain" />
</div>
via TS you will see the nativeElement of both your checkboxes
getChildren(ch1: any, ch2: any){
console.log(ch1);
console.log(ch2);
}

How to add tooltip in html?

I have the following code, but it doesn't work, can anyone help me out
<form id="myform" action="#">
<h3>Registration Form</h3>
<div id="inputs">
<!-- username -->
<label for="username">Username</label>
<input id="username" title="Must be at least 8 characters."/>
<br />
<!-- password -->
<label for="password">Password</label>
<input id="password" type="password" title="Make it hard to guess." />
<br />
<!-- email -->
<label for="email">Email</label>
<input id="email" title="We won't send you any marketing material." />
<br />
<!-- message -->
<label for="body">Message</label>
<textarea id="body" title="What's on your mind?"></textarea>
<br />
<!-- message -->
<label for="where">Select one</label>
<select id="where" title="Select one of these options">
<option>-- first option --</option>
<option>-- second option --</option>
<option>-- third option --</option>
</select>
<br />
</div>
<!-- email -->
<label>
I accept the terms and conditions
<input type="checkbox" id="check" title="Required to proceed" />
</label>
<p>
<button type="button" title="This button won't do anything">
Proceed
</button>
</p>
</form>
title attribute does the work.
Your code works in chrome, FF and IE 9 and 10
Why not use placeholder instead of title.
Supported overview
In other browsers you can use this javascript:
<script>
var doc = document;
var inputs = doc.getElementsByTagName('input'),
var supportPlaceholder = 'placeholder' in doc.createElement('input');
var placeholder = function(input) {
var text = input.getAttribute('placeholder');
var defaultValue = input.defaultValue;
input.value = text;
input.onfocus = function() {
if (input.value === defaultValue || input.value === text) {
this.value = '';
}
}
input.onblur = function() {
if (input.value === '') {
this.value = text;
}
}
};
if (!supportPlaceholder) {
for (var i = 0, len = inputs.length; i < len; i++) {
var input = inputs[i], text = input.getAttribute('placeholder');
if (input.type === 'text' && text) {
placeholder(input);
}
}
}
</script>
insert title="" attribute, it will work for you.
Try qTip - http://craigsworks.com/projects/qtip/ and see the demo - http://jsfiddle.net/ramsunvtech/zzZBM/