React - problems with checkbox - reactjs

I am trying to create a component with four options. The user is supposed to choose only one option. So if the user chooses another option, the previosluy selected ones should change to false. This is my code:
const riddles_ = [{
id:2,
options: ['A grandson','A daughter','A father','A nephew'],
state_: [false,false,false,false]
}]
function toggleToDo(o){
riddles_.state_ = [false,false,false,false]
riddles_.state_[o] = true
console.log(riddles_.state_)
}
return (
<div>
<input type="checkbox" id="check1" checked={riddles_.state_[0]} onClick={(o)=>toggleToDo(0)}/>
{riddles_.options[0]}
<div className='space'></div>
<input type="checkbox" id="check2" checked={riddles_.state_[1]} onClick={(o)=>toggleToDo(1)}/>
{riddles_.options[1]}
<div className='space'></div>
<input type="checkbox" id="check3" checked={riddles_.state_[2]} onClick={(o)=>toggleToDo(2)}/>
{riddles_.options[2]}
<div className='space'></div>
<input type="checkbox" id="check4" checked={riddles_.state_[3]} onClick={(o)=>toggleToDo(3)}/>
{riddles_.options[3]}
</div>
)
}
When the user clicks on a checkbox, it just turns true or false, and generates no change in the others. I know the riddles_.state_ array is changing but the checkbox donĀ“t seem to be able to take its value.

Its a best practice to use set method frome useState hooks when u work with state, using react functional components.
Example :
const init_state = [false,false,false,false]
const [checked_state, setCheckedState] = useState(init_state);
function toggleToDo(o){
const current_state = [false,false,false,false]
current_state[o] = true;
setCheckedState(current_state);
}
return (
<div>
<input type="checkbox" checked={checked_state[0]} onClick={(o)=>toggleToDo(0)}/>
option1
<div className='space'></div>
<input type="checkbox" checked={checked_state[1]} onClick={(o)=>toggleToDo(1)}/>
option2
<div className='space'></div>
<input type="checkbox" checked={checked_state[2]} onClick={(o)=>toggleToDo(2)}/>
option3
<div className='space'></div>
<input type="checkbox" checked={checked_state[3]} onClick={(o)=>toggleToDo(3)}/>
option4
</div>
)
}

Related

Two handleChange events using multiple select option in react js

I'm trying to write (two) multiple selected options using two handle change functions, I don't think it's not a good practice, in that two selected options I have to bind that data separately without disturbing the other multiple selected option.
import React, { Component } from 'react';
class AddEvent extends Component {
constructor() {
super();
this.state = {
speaker: [''],
hash_tag: ['']
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
var options = event.target.options;
var value = [];
for (var i = 0, l = options.length; i < l; i++) {
if (options[i].selected) {
value.push(options[i].value);
}
}
this.setState({ value: value });
}
handleChange(event2) {
var options2 = event2.target.options;
var value2 = [];
for (var j = 0, l = options2.length; j < l; j++) {
if (options2[j].selected) {
value2.push(options2[j].value);
}
}
this.setState({ value: value2 });
}
render() {
return (
<div className="col-md-12">
<h3>Add Events</h3>
<form onSubmit={this.handleSubmit}>
<div className="col-md-6">
<div className="form-group">
<label>Event Speaker:</label>
<select
data-style="btn-default"
className="form-control"
multiple
data-max-options="3"
value={this.state.value}
onChange={this.handleChange}
>
<option value="Vivek Srinivasan">Vivek Srinivasan</option>
<option value="Salma Moosa">Salma Moosa</option>
<option value="Rengaprasad">Rengaprasad</option>
</select>
</div>
</div>
<div className="col-md-6">
<div className="form-group">
<label>Event Hash Tags:</label>
<select
data-style="btn-default"
className="form-control"
multiple
data-max-options="3"
value={this.state.value}
onChange={this.handleChange2}
>
<option value="hash_tag_1">hash_tag_1</option>
<option value="hash_tag_2">hash_tag_2</option>
<option value="hash_tag_3">hash_tag_3</option>
<option value="hash_tag_4">hash_tag_4</option>
<option value="hash_tag_5">hash_tag_4</option>
</select>
</div>
</div>
<div className="col-md-12">
<div className="form-group">
<label>Event Content</label>
<textarea
id="summernote"
value="Type Here "
onChange={val => this.setState({ content: val.target.value })}
/>
</div>
</div>
<div className="col-md-3">
<button className="btn btn-block btn-primary btn-lg" type="submit">
Save Event
</button>
</div>
</form>
</div>
);
}
}
export default AddEvent;
I don't quite understand why you don't want to use different handlers for each select element. Especially since you've already written two handler functions. Perhaps I've misunderstood your question.
You got three main problems, as I see it.
1) You can't have two functions with the same name, as you do with handleChange.
2) In your current code, you're referencing a function that doesn't exist (handleChange2).
3) In both handleChange functions, you're overriding the value property in the state with the other, as both are changing the property value in the state.
Renaming the latter handleChange function to handleChange2 would solve problems 1 and 2.
The third problem would be solved by having two value properties in your state, e.g. value1 and value2 (though I would suggest using more descriptive names).

React.js Template Not Rendering Properly

I'm working on the React.js tutorial here: https://facebook.github.io/react/docs/tutorial.html
I have everything working as expected, but for some reason, when I apply additional HTML to my form with classes, the styling doesn't apply. I have checked out a bit of additional documentation, but can't find a reason why the additional HTML won't render.
The form elements will render, but nothing with the 'large-XX columns' classes will render.
Any thoughts?
var CommentForm = React.createClass({
handleSubmit: function(e) {
e.preventDefault();
var creator = this.refs.creator.value.trim();
var mr = this.refs.mr.value.trim();
var message = this.refs.message.value.trim();
var csrfmiddlewaretoken = this.refs.csrfmiddlewaretoken.value.trim();
if (!creator || !mr || !message || !csrfmiddlewaretoken ) {
return;
}
this.props.onCommentSubmit({creator:creator, mr:mr, message:message, csrfmiddlewaretoken: csrfmiddlewaretoken})
this.refs.creator.value = '';
this.refs.mr.value = '';
this.refs.message.value = '';
return;
},
render: function() {
return (
<form className="commentForm" onSubmit={this.handleSubmit}>
<div class="row">
<div class="large-10 columns">
<input type="hidden" ref="csrfmiddlewaretoken" value="{{ csrf_token }}" />
<input type="hidden" ref="creator" value="{{ globalEmployee.id }}" />
<input type="hidden" ref="mr" value="{{ mr.id }}" />
<input type="text" ref="message" placeholder="Add a comment..." />
</div>
<div class="large-12 columns">
</div>
<div class="large-2 columns">
<input type="submit" value="Post" class="button tiny expand" />
</div>
</div>
</form>
);
}
});
Instead of class use className as you did in the form element.
From HTML Tags vs. React Components:
Since JSX is JavaScript, identifiers such as class and for are
discouraged as XML attribute names. Instead, React DOM components
expect DOM property names like className and htmlFor, respectively.

Angular directive for horizontal Bootstrap form

I'm trying to build a directive for my Angular to help with the integration of form fields. I've implemented Scott Allens solution from his Angular playbook, and it works fine for a normal stacked form.
I need however to adapt it to a horizontal form instead. Here's my code:
Markup
<div form-group>
<label for="name">Name</label>
<input type="text" id="name" ng-model="vm.name">
</div>
formGroup directive
function link(scope, element) {
setupDom(element[0]);
}
function setupDom(element) {
var label = element.querySelector("label");
label.classList.add("control-label");
var input = element.querySelector("input, textarea, select");
var type = input.getAttribute("type");
if (type !== "radio" && type !== "checkbox"){
input.classList.add("form-control");
}
element.classList.add("form-group");
}
function formGroup() {
return {
restrict: "A",
link: link
}
}
The output becomes:
<div form-group="" class="form-group">
<label for="name" class="control-label">Name</label>
<input type="text" id="name" ng-model="vm.name" class="form-control">
</div>
And that's fine for stacked form. Since I need a horizontal form, my output needs to look like this:
<div form-group="" class="form-group">
<label for="name" class="control-label col-sm-3">Name</label>
<div class="col-sm-9">
<input type="text" id="name" ng-model="vm.name" class="form-control">
</div>
</div>
I've tried many solutions and I can get it work with single elements like an input, textarea or a select. It becomes much more tricky when I have something like two radio buttons inside my markup like this:
<div form-group>
<label>Active</label>
<div class="radio">
<label>
<input type="radio" name="active" ng-value="true" ng-model="vm.active"> Yes
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="active" ng-value="false" ng-model="vm.active"> No
</label>
</div>
</div>
The desired output of the above mentioned code should be:
<div form-group class="form-group">
<label class="control-label col-sm-3">Active</label>
<div class="col-sm-9">
<div class="radio">
<label>
<input type="radio" name="active" ng-value="true" ng-model="vm.active"> Yes
</label>
</div>
<div class="radio">
<label>
<input type="radio" name="active" ng-value="false" ng-model="vm.active"> No
</label>
</div>
</div>
</div>
Please notice that the input(s) in the form-group is not fixed. It can be either a single input, textarea, select, a group of radio buttons or checkboxes. I'm lost for how I can make that happen. Any help is appreciated. Thanks!
UPDATE
I made some small changes to Mark Veenstra's code to make it (sort of) working:
function setupDom(element) {
element.classList.add("form-group");
var label = element.querySelector("label");
label.classList.add("control-label", "col-sm-3");
var input = element.querySelector("input, textarea, select");
var type = input.getAttribute("type");
if (type !== "radio" && type !== "checkbox"){
input.classList.add("form-control");
angular.element(input).wrap(angular.element('<div class="col-sm-9"></div>'));
}
var div_radio = element.querySelector("div[class='radio']");
angular.element(div_radio).wrap(angular.element('<div class="col-sm-9"></div>'));
}
This does not work completely as intended with multiple radio inputs since it only wraps the <div> on the first radio input element.
The output from radio button example in my original post using Marks code is:
<div form-group="" class="form-group">
<label class="control-label col-sm-3">Active</label>
<div class="col-sm-9">
<div class="radio">
<label>
<input type="radio" name="active" ng-value="true" ng-model="vm.active" value="true"> Yes
</label>
</div>
</div>
<div class="radio">
<label>
<input type="radio" name="active" ng-value="false" ng-model="vm.active" value="false"> No
</label>
</div>
</div>
SOLUTION
Check out the Plunker with the final result: http://plnkr.co/edit/Wv6V86hHTCz3URS9DhdU?p=preview
In the angular.element documentation you can find the method wrap() to be able to wrap HTML around a selected element. Or see this direct link.
So what you could do in your directive is change the setupDom() function to match your requirements per type of form element.
function link(scope, element) {
setupDom(element[0]);
}
function setupDom(element) {
element.classList.add("form-group");
var label = element.querySelector("label");
label.classList.add("control-label col-sm-3");
var input = element.querySelector("input, textarea, select");
var type = input.getAttribute("type");
if (type !== "radio" && type !== "checkbox"){
input.classList.add("form-control");
input.wrap(angular.element('<div class="col-sm-9"></div>'));
}
var div_radio = element.querySelectorAll("div[class='radio']");
div_radio.wrap(angular.element('<div class="col-sm-9"></div>'));
}
function formGroup() {
return {
restrict: "A",
link: link
}
}
NOTE: This code is not tested, maybe there are some minor mistakes, but I guess you'll get the point now.
Mark's suggestion came close, but it didn't solve my problem completely. I ended up using the following code in my formGroup directive:
(function (module) {
"use strict";
function link(scope, element) {
setupDom(element[0]);
}
function setupDom(element) {
element.classList.add("form-group");
var children = angular.element(element).children();
var labels = children.splice(0, 1);
// Set label classes
labels[0].classList.add("control-label", "col-sm-3");
// Wrap children in div
angular.element(children).wrapAll(angular.element("<div class='col-sm-9'></div>"));
// Handle inputs
var inputs = element.querySelectorAll("input, textarea, select");
for (var i = 0, len = inputs.length; i < len; i++) {
var input = inputs[i],
type = input.getAttribute("type");
if (type !== "radio" && type !== "checkbox") {
input.classList.add("form-control");
}
}
}
function formGroup() {
return {
restrict: "A",
link: link
}
}
module.directive("formGroup", formGroup);
}(angular.module("app.core")));
Check out this Plunker to see it in action: http://plnkr.co/edit/Wv6V86hHTCz3URS9DhdU?p=preview

Display button only on form input change in angular.js

HTML:
<ul>
<li><a><i class="icon-white icon-save"></i></a></li>
</ul>
<form>
<input type="text" value="{{ selectedUser.firstname }}" ng-model="selectedUser.firstname">
<input type="text" value="{{ selectedUser.lastname }}" ng-model="selectedUser.lastname">
</form>
I am dealing with user objects fetched from my REST API. So basically there is a list of users. On click the above form is revealed.
function UserController($scope, User){
$scope.users = User.query();
$scope.selectedUser = null;
$scope.select = function(user){
$scope.selectedUser = user;
}
}
I want to display the save link only when form values have changed. Any ideas how to do this with angular.js?
Give your form a name, such as:
<form name="dataForm">
<input type="text" name="firstname" ng-model="data.firstname" />
<input type="text" name="lastname" ng-model="data.lastname" />
</form>
The form will now be a named model in your scope and you can hide/show the save button based on whether the form is pristine:
<ul ng-hide="dataForm.$pristine">
<li><a><i class="icon-white icon-save"></i></a></li>
</ul>
This approach has the advantage of showing the save button if you change any of the form elements inside the form and the drawback of not checking the input values against their original values, just the fact that they have been edited.
Here is an example of showing your element only when both fields have data:
<div ng-controller="TestCtrl" ng-app>
<ul ng-show="enableSave(data)">
<li><a><i class="icon-white icon-save"></i></a></li>
</ul>
<form>
<input type="text" name="firstname" ng-model="data.firstname" />
<input type="text" name="lastname" ng-model="data.lastname" />
</form>
</div>
And here is your controller:
function TestCtrl($scope) {
$scope.data = {firstname: "", lastname: ""};
$scope.enableSave = function(data) {
return data.firstname.length > 1 && data.lastname.length > 1;
};
}
You can put any logic you want into enableSave. I've chosen to require that they both have at least two characters... you can do whatever you need.
Here is a jsFiddle that illustrates it: http://jsfiddle.net/nDCXY/1/
EDIT by OP: my solutions
$scope.enableSave = function(user) {
if(!angular.equals(user, oldUser)){
return true
}else{
return false;
}
};

How to know if a checkbox or radio button is checked in Dart?

I have a checkbox and a radio button group and I want to know if the checkbox is checked and which radio button is selected.
How do I do this in dart?
Let's say we have your HTML with something like this:
<form >
<input type="radio" name="gender" id="gender_male" value="male">Male<br>
<input type="radio" name="gender" id="gender_female" value="female">Female
</form>
<form>
<input type="checkbox" id="baconLover">I like bacon<br>
</form>
Your Dart code to obtain their values would be something like the following, I also added an event to know when the checkbox is clicked.
import 'dart:html';
void main() {
// Adds a click event when the checkbox is clicked
query("#baconLover").on.click.add((MouseEvent evt) {
InputElement baconCheckbox = evt.target;
if (baconCheckbox.checked) {
print("The user likes bacon");
} else {
print("The user does not like bacon");
}
});
// Adds a click event for each radio button in the group with name "gender"
queryAll('[name="gender"]').forEach((InputElement radioButton) {
radioButton.onclick.listen((e) {
InputElement clicked = e.target;
print("The user is ${clicked.value}");
});
});
}
I found this solution for radio button, where catch event by "html" ... I have used this solution into my project.
my_example.html
<polymer-element name="my-example">
<template>
<div on-change="{{updateRadios}}">
Your favorite color is:
<div>
<label for="red">Red <input name="color" type="radio" id="red" value="red"></label>
</div>
<div>
<label for="green">Green <input name="color" type="radio" id="green" value="green"></label>
</div>
<div>
<label for="blue">Blue <input name="color" type="radio" id="blue" value="blue"></label>
</div>
</div>
<div>
You selected {{favoriteColor}}
</div>
</template>
<script type="application/dart" src="my_example.dart"></script>
</polymer-element>
my_example.dart
import 'package:polymer/polymer.dart';
import 'dart:html';
#CustomTag('my-example')
class MyExample extends PolymerElement {
#observable String favoriteColor = '';
MyExample.created() : super.created();
void updateRadios(Event e, var detail, Node target) {
favoriteColor = (e.target as InputElement).value;
}
}

Resources