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).
Related
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>
)
}
I have an array with multiple input-fields with v-model inside a v-for loop. One of these the fields for each array-item contains a price. In the object this price should be in cents, but in the input fields it should be in whole euro's.
I made a computed property to basically devide (getter) and multiple (setter) the price by 100.
The getter works fine, but the setter seems to not do anything.
This is my (simplified) code:
<template>
<div>
<div v-for="(item, index) in geleverd" :key="index">
<div>
<label for="Omschrijving">Omschrijving</label>
<input v-model="item.naam" type="text" name="Omschrijving">
</div>
<div>
<label for="Aantal">Aantal</label>
<input
v-model="item.aantal"
type="number"
name="Aantal"
min="0"
step="1"
>
</div>
<div>
<label for="Prijs">Prijs</label>
<input
v-model="item.prijs"
type="number"
name="Prijs"
min="0"
step=".50"
>
</div>
<div>
<label for="Btw">Btw</label>
<input
v-model="item.btw"
type="number"
name="Btw"
min="0"
step="1"
>
</div>
</div>
</div>
</template>
<script>
export default {
computed: {
factuur () {
const foundFactuur = this.$store.state.facturen.list.find((factuur) => {
return factuur.info.id === this.$route.params.factuur
})
if (foundFactuur) {
return JSON.parse(JSON.stringify(foundFactuur))
} else {
return JSON.parse(JSON.stringify(this.$store.state.facturen.empty))
}
},
geleverd: {
get () {
return this.factuur.geleverd.map((item) => {
const newPrijs = (item.prijs / 100).toFixed(2)
return {
aantal: item.aantal,
naam: item.naam,
prijs: newPrijs,
btw: item.btw
}
})
},
set (newArray) {
const newGeleverd = newArray.map((item) => {
const newPrijs = (item.prijs * 100).toFixed(0)
return {
aantal: item.aantal,
naam: item.naam,
prijs: newPrijs,
btw: item.btw
}
})
this.factuur.geleverd = newGeleverd
}
}
}
}
</script>
Is there something wrong with my code, or is this just not possible in Vue?
I know I can probably achieve my goal by using a method which gets called #input, but a computed property seems better suited to me.
I don't really like to set up the computed property for an entire object, since I just have to modify 1 item. Any way to get around this?
I have a problem on my code. After submitting the form I have a function for validation checking but it seems that the condition on my function won't identify my form name. Here's my code:
Template form part:
<div class="modal-body">
<form name="form.addeditcoursewareModal">
<div class="row">
<div class="small-12 medium-12 large-12 columns">
<label class="stacked">
Question
<input name="question" type="text" class="form-field" placeholder="Question" ng-model="$ctrl.question.data.attributes.question" >
</label>
</div>
</div>
<div class="row">
<div class="small-12 medium-6 large-6 columns">
<label class="stacked">
Question Type: {{ $ctrl.question.data.attributes.question_type }}
<select name="question_type" class="form-field" id="questionType" ng-model="$ctrl.question.data.attributes.question_type" ng-change="$ctrl.getSelectedQuestionType()">
<option value="single">Single</option>
<option value="multiple">Multiple</option>
<option value="true_or_false">True or False</option>
<option value="free_text">Free Text</option>
</select>
</label>
</div>
Validation part:
validateForm(){
this.validatingForm = true;
if (this.question.data.attributes.question_type === 'true_or_false'){
this.question.data.attributes.choices.data[0].attributes.choice = 'True';
this.question.data.attributes.choices.data[1].attributes.choice = 'False';
}
if (this.modalOptions.actionType == 'duplicate'){
this.question.data.attributes.choices.data.forEach((value) => {
delete value.id;
});
}
if (this.modalOptions.type === 'multiple'){
this.validateCheckbox();
}
console.log(this);
if (this.form.addeditcoursewareModal.$invalid || this.invalidMultiple) { // ERROR DETECTED
// Check for an invalid field
angular.forEach(this.form.addeditcoursewareModal.$error, (field) => {
angular.forEach(field, (errorField) => {
if (errorField.$name === 'dynamicForm'){
errorField.dynamicInput.$setTouched();
} else {
// Set field as touched to display invalid field message
if (errorField.$name === 'single') {
this.invalidRadio = true;
}
errorField.$setTouched();
}
});
});
this.validatingForm = false;
} else {
Here's the error I got:
angular.js:14791 TypeError: Cannot read property 'addeditcoursewareModal' of undefined
I already tried renaming my form but the error is the same.
It seems that you are using the controller as syntax. You would need to add $ctrl in front of form.addeditcoursewareModal.
<form name="$ctrl.form.addeditcoursewareModal">
is there any way to get value of checkbox using ref in React. Normal way return always value "on" to me.
var MyForm = React.createClass({
save: function(){
console.log(this.refs.check_me.value);
},
render: function(){
return <div><h1>MyForm</h1>
<div className="checkbox">
<label>
<input type="checkbox" ref="check_me" /> Check me out
</label>
</div>
<button className="btn btn-default" onClick={this.save}>Submit</button>
</div>
}
});
For checkbox, use "checked" instead of "value":
var MyForm = React.createClass({
save: function () {
console.log(this.refs.check_me.checked);
},
render: function () {
return <div><h1>MyForm</h1>
<div className="checkbox">
<label>
<input type="checkbox" ref="check_me" /> Check me out
</label>
</div>
<button className="btn btn-default" onClick={this.save}>Submit</button>
</div>
}
});
As a result:
There is a classic way to catch the event and corresponding values with the help of:
event.target.checked, event.target.name
You can see an example:
class MyForm extends React.Component {
onChangeFavorite(event){
console.log(event.target.checked, event.target.name);
};
render(){
return (<div><h1>MyForm</h1>
<div className="checkbox">
<label>
<input type="checkbox" name="myCheckBox1"
onChange={this.onChangeFavorite}
defaultChecked={false} />
Check me out
</label>
</div>
<button className="btn btn-default" onClick={this.save}>Submit</button>
</div>)
};
};
You can make the checkbox a controlled element by listening to onChange and giving it a state value. Try the following:
var MyForm = React.createClass({
save: function(){
console.log(this.refs.check_me.value);
},
toggleCheckboxValue: () => {
this.setState({checkBoxValue: !this.state.checkboxValue});
},
render: function(){
return <div><h1>MyForm</h1>
<div className="checkbox">
<label>
<input type="checkbox" ref="check_me" value={this.state.checkboxValue} onChange={this.toggleCheckboxValue} /> Check me out
</label>
</div>
<button className="btn btn-default" onClick={this.save}>Submit</button>
</div>
}
});
whenever the checkbox is clicked it will run the toggleCheckboxValue function, which will toggle the value of this.state.checkboxValue.
Just don't forget to initialize the this.state.checkboxValue function in your code.
Note: As ivarni pointed out, you may want to control the checked value specifically for checkboxes rather than value. Though both solutions will work.
I'm not sure why you want it using ref specifically, but it can be done nativily:
import React from 'react';
function CheckBox() {
const [isSave, setIsSave] = React.useState(false);
const handler = (value) => {
console.log(value);
setIsSave(value);
};
return (
<div>
<input type="checkbox" onChange={(ev) => handler(ev.target.checked)} />
<label> Save me..</label>
</div>
);
}
export default CheckBox;
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.