How to set the default value of a dropdown list to a state variable in Reactjs - javascript

I have a React component which contains a textbox, dropdown list, and a submit button.
I capture values of the textbox and a dropdown list using an 'OnChange' event as follows.
<div className="form-group">
<label htmlFor="accountName">Account Name</label>
<input type="text" id="accountName" className="form-control" name="accountName" value={this.state.accountName} onChange={(e)=>this.change(e)}></input>
</div>
<div className="form-group">
<label htmlFor="originatedBy">Originated By</label>
<select className="form-control" id="originatedBy" name="originatedBy" value={this.state.originatedBy} onChange={(e)=>this.change(e)}>
<option>value1</option>
<option>value2</option>
<option>value3</option>
</select>
</div>
<div className="form-group row ml-md-1">
<button type="submit" className="btn btn-outline-primary btn-block" onClick={(e)=>this.addRecord(e)}>Add Record</button>
</div>
And in the Js section, I have,
class AddRecordView extends Component{
state={
accountName:"",
originatedBy:""
}
change(e){
this.setState({[e.target.name]:e.target.value});
}
addRecord(e){
e.preventDefault(e);
const user={
accountName : this.state.accountName,
originatedBy : this.state.originatedBy,
}
console.log(user);
var url = <url_of_the_endpoint>";
axios.post(url, {
user
},{
headers: {
'Accept': 'application/json'
}
})
.then(function(response){
console.log(response);
})
.catch(function(error){
console.log(error);
});
}
render(){
return(
<html_section>
);
}
}
export default AddRecordView;
The 'accountName' and the 'originatedBy' values are simply set when there is a change in the textbox and dropdown-list respectively.
However, if I let the default value (the value which shows when the form is loaded) of the dropdown-list remains unchanged and Submit the data, it doesn't trigger the 'OnChange' event and passes,
{accountName: 'some_value', originatedBy: ""} to the backend.
How can I make the 'originatedBy' attribute to take the default value of the dropdown-list. Please share your ideas on how to make it work (maybe from the constructor or any other suitable method).
Any suggestions will be helpful.

Related

How do I send data from a WYSIWYG to a database (Vue.js)

I just started using the Vue2Editor with the intention to replace the many forms that I use to send text and image data to my Firebase database.
My problem is that I cannot get it to add the data entered in the editor.
When using forms, I would just attach an event handler to the form itself and make a function that allowed the transfer.
Example:
<form #submit.prevent="addText">
<label for="fname">First name:</label>
<input type="text" id="fname" name="fname" v-model="fname">
</form>
<button type="submit" variant="success">Save</button>
But when using the Vue2Editor, I do not get any form tags.
I just get a "vue-editor" tag. I tried adding the event handler inside this tag, but nothing happens.
I don't get any errors, but the data is not transferred to the database upon submitting it.
This is the code:
<template>
<div class="container">
<div class="text_editor">
<h2>Add new content</h2>
<vue-editor #submit.prevent="addText" v-model="textblock" />
<button type="submit" class="textblock_btn" variant="success">Save</button>
</div>
</div>
</template>
<script>
import db from '#/firebase/init'
import Vue from "vue";
import Vue2Editor from "vue2-editor";
Vue.use(Vue2Editor);
export default {
name: 'textblock',
data () {
return {
textblock: null
}
},
methods: {
addText(){
db.collection('textblock').add({
textblock: this.textblock
}).then(() => {
this.$router.push({ name: 'Index' })
}).catch(err => {
console.log(err)
})
}
}
}
</script>
You can still wrap the component in a form as the WYSIWYG editor's data is bound to the v-model property.
<form #submit.prevent="addText">
<div class="text_editor">
<h2>Add new content</h2>
<vue-editor v-model="textblock" />
<button type="submit" class="textblock_btn" variant="success">Save</button>
</div>
</form>
Within the addText method you now have this.textblock with the appropriate data on form submission.

Is it possible to to make this delete button and input form work?

So iv been stuck for quite some time now, i need to make my delete button work on every row and make inputs spit info to my table.
My question is : Is it even possible to do it? (I just started to learn react/js literally today).
The final product should look like "to do list" but when i open it it automatically has values from api that i can delete and add new.
My code:
export default class FetchRandomUser extends React.Component {
state = {
loading: true,
people: []
};
async componentDidMount() {
const url = "https://swapi.dev/api/people/";
const response = await fetch(url);
const data = await response.json();
const pirmadata = data;
this.setState({ people: pirmadata.results, loading: false });
console.log(pirmadata)
}
render() {
if (this.state.loading) {
return <div>loading...</div>;
}
if (!this.state.people.length) {
return <div>didn't get a person</div>;
}
return (
<div className="listas">
{this.state.people.map(person => (
<tr className="taras" key={person.name + person.age}>
<th className="name">{person.name}</th>
<th className="birth">{person.birth_year}</th>
<th className="genders">{person.gender}</th>
<th><button type="submit" className="delete">Delete</button></th>
</tr>
))}
</div>
);
}
}
My form is made on different .js file and basically is a function which holds this form:
<div className="forma">
<form>
<input type="text" placeholder="Enter name :"></input>
<input type="text" placeholder="Enter birth date :"></input>
<input type="text" placeholder="Enter gender :"></input>
<button type="submit">Submit entry!</button>
</form>
</div>
Add a click handler for the Delete button that is the onSubmit handler of the form element. That way when you click it, it will call the form's handler function.
Pass the handlerFunc to the component with the th elements as a prop to be able to use it as the following:
function YourComponent({ handler }){
return <th><button onClick={handler} className="delete">Delete</button></th>);
}
Form onSubmit handler:
<form onSubmit={handlerFunc}>
<input type="text" placeholder="Enter name :"></input>
<input type="text" placeholder="Enter birth date :"></input>
<input type="text" placeholder="Enter gender :"></input>
<button type="submit">Submit entry!</button>
</form>
<YourComponent handler={handlerFunc} />

Conditional rendering in React not working after onClick event

I was trying to conditionally show/hide a set of input fields based on a button click event. If the button was clicked, the value of showExtraDetails div will be toggled between true and false.
Here's what I've tried:
state = {
ItemName: '',
ItemPrice:'',
ItemDate: '',
ItemPlace: '',
ItemType: '',
}
/*On hitting submit button, I'm logging the state and resetting the form fields after the state was stored in to newArray after appending*/
handleSubmit = (e) => {
e.preventDefault();
console.log(this.state);
newArray = [...newArray, this.state];
console.log(newArray)
this.setState({
ItemName: '',
ItemPrice:'',
ItemDate: '',
ItemPlace: '',
ItemType: '',
})
}
/*When the input fields change, I'm updating the state*/
change =e =>{
// this.props.onChange({[e.target.name]:e.target.value})
this.setState({
[e.target.name]:e.target.value
})
}
/* toggling the showExtraDetails value after button was hit */
addExtraFoodDetails=() =>{
// e.preventDefault()
showExtraDetails = !showExtraDetails
console.log(showExtraDetails)
// e.preventDefault()
}
render(){
return(
<div>
<h5>Add Item</h5>
<form onSubmit={e => this.handleSubmit(e)}>
<input type="text" name="ItemName" placeholder="Enter the Item name"
value={this.state.ItemName}
onChange={e=> this.change(e)}
/>
<input type="number" name="ItemPrice" placeholder="Enter the item price"
value={this.state.ItemPrice}
onChange={e=>this.change(e)}
/>
<input type="date" name="ItemDate"
value={this.state.ItemDate}
onChange={e=>this.change(e)}
/>
<br/>
<input type="submit" name="submitItem" value="Save" />
</form>
<button onClick={this.addExtraDetails}>Add extra details</button>
<br/>
{showExtraDetails ?
(<div>
<input type="text" name="ItemPlace" value={this.state.ItemPlace}/>
<select name="ItemType" value={this.state.ItemType}>
<option value="none" disabled>--Select--</option>
<option value="type1">Type1</option>
<option value="type2">Type2</option>
<option value="type3">Type3</option>
<option value="others">Others</option>
</select>
</div>) : null
}
<br/>
<ul>
{newArray.map(item => <li>{item.ItemName}</li>)}
</ul>
</div>
)
}
But, when I hit the Add extra details button, I can only see the value of showExtraDetails as true/false after toggling, but the div is not getting updated with Showing/Hiding of the extra fields.
Am I missing something here? What is the best way to handle this?
I've seen in angular ngIf would do this. But I don't see such equivalent in React. I got some suggestions to make use of CSS styles by toggling the id's of the div. But I'm trying to apply something which is React specific.
Thanks.
In all probability, react is not re rendering. I suggest putting showExtraDetails in the state, and updating this state variable to cause a re render and thus cause your component to toggle correctly.

Multiple Registration Form with redux and react

I have been trying to develop a dashboard form similiar to airbnb listing form for understanding more deeply about react redux but i am stuck in the middle of my project. I have a multiple form where when user clicks on continue button the user will get another form to fill and so on and if user clicks on back button the user will get form of one step back with previously filled values. I could not decide what should i do for this. Do i have to create a object in action as listingName . summary, name, email etc as empty value and update it with reducer using Object.assign() or what. Till now i could only develop like when user clicks on personal tab a form related to personal information is shown and when user clicks on basic tab, a form related to basic information is shown. I want all form data to be send to server at last submit. What should i do now ? Do i use increment and decrement action for the continue and back button and use submit action on the last form button ? Could you please provide me an idea ?
Here's my code
actions/index.js
export function selectForm(form){
return{
type: 'FORM_SELECTED',
payload: form
};
}
reducers/reducer_active_form.js
export default function(state=null, action){
let newState = Object.assign({},state);
switch(action.type){
case 'FORM_SELECTED':
return action.payload;
}
return state;
}
reducers/reducer_form_option.js
export default function(){
return[
{ option: 'Personal Information', id:1},
{ option: 'Basic Information', id:2 },
{ option: 'Description', id:3},
{ option: 'Location', id:4},
{ option: 'Amenities', id:5},
{ option: 'Gallery', id:6}
]
}
containers/form-details
class FormDetail extends Component{
renderPersonalInfo(){
return(
<div className="personalInfo">
<div className="col-md-4">
<label htmlFor='name'>Owner Name</label>
<input ref="name" type="textbox" className="form-control" id="name" placeholder="Owner name" />
</div>
<div className="col-md-4">
<label htmlFor="email">Email</label>
<input ref="email" type="email" className="form-control" id="email" placeholder="email" />
</div>
<div className="col-md-4">
<label htmlFor="phoneNumber">Phone Number</label>
<input ref="phone" type="textbox" className="form-control" id="phoneNumber" placeholder="phone number" />
</div>
<div className="buttons">
<button className="btn btn-primary">Continue</button>
</div>
</div>
);
}
renderBasicInfo(){
return(
<div>
<h3>Help Rent seekers find the right fit</h3>
<p className="subtitle">People searching on Rental Space can filter by listing basics to find a space that matches their needs.</p>
<hr/>
<div className="col-md-4 basicForm">
<label htmlFor="price">Property Type</label>
<select className="form-control" name="Property Type" ref="property">
<option value="appartment">Appartment</option>
<option value="house">House</option>
</select>
</div>
<div className="col-md-4 basicForm">
<label htmlFor="price">Price</label>
<input type="textbox" ref="price" className="form-control" id="price" placeholder="Enter Price" required />
</div>
<div className="buttons">
<button className="btn btn-primary">Back</button>
<button className="btn btn-primary">Continue</button>
</div>
</div>
);
}
renderDescription(){
return(
<div>
<h3>Tell Rent Seekers about your space</h3>
<hr/>
<div className="col-md-6">
<label htmlFor="listingName">Listing Name</label>
<input ref="name" type="textbox" className="form-control" id="listingName" placeholder="Be clear" />
</div>
<div className="col-sm-6">
<label htmlFor="summary">Summary</label>
<textarea ref="summary" className="form-control" id="summary" rows="3"></textarea>
</div>
<div className="buttons">
<button className="btn btn-primary">Back</button>
<button className="btn btn-primary">Continue</button>
</div>
</div>
);
}
renderLocation(){
return(
<div>
<h3>Help guests find your place</h3>
<p className="subtitle">will use this information to find a place that’s in the right spot.</p>
<hr/>
<div className="col-md-6">
<label htmlFor="city">City</label>
<input ref="city" type="textbox" className="form-control" id="city" placeholder="Biratnagar" />
</div>
<div className="col-md-6">
<label htmlFor="placeName">Name of Place</label>
<input ref="place" type="textbox" className="form-control" id="placeName" placeholder="Ganesh Chowk" />
</div>
<div className="buttons">
<button className="btn btn-primary">Back</button>
<button className="btn btn-primary">Continue</button>
</div>
</div>
);
}
render(){
if ( !this.props.form){
return this.renderPersonalInfo();
}
const type = this.props.form.option;
console.log('type is', type);
if ( type === 'Personal Information'){
return this.renderPersonalInfo();
}
if ( type === 'Basic Information'){
return this.renderBasicInfo();
}
if ( type === 'Description'){
return this.renderDescription();
}
if ( type === 'Location'){
return this.renderLocation();
}
}
}
function mapStateToProps(state){
return{
form: state.activeForm
};
}
export default connect(mapStateToProps)(FormDetail);
The first thing you're missing is controlled components. By giving the inputs a value property, and an onChange function, you will link the input with an external state.
Your components should have access, via react-redux, to the state and actions needed. The value of the form should be your state for that object. So you might have a state like:
location: {
listingName: '123 Main St',
summary: 'The most beautiful place!'
}
Then, you'd just pass each property to inputs. I'm assuming, in this example, that you've passed the location prop in mapStateToProps, and an actions object with all the related actions in mapDispatchToProps:
changeHandler(ev, fieldName) {
const val = ev.target.value;
this.props.actions.updateField(fieldName, val);
},
render() {
return (
<input
value={this.props.location.listingName}
onChange={(ev) => { this.changeHandler(ev, 'listingName'}}
/>
);
}
You provide it an action that can be used to update the state:
function updatefield(field, val) {
return {
type: UPDATE_FIELD,
field,
val
};
}
Then, you just merge it in, in your reducer
switch (action.type) {
case UPDATE_FIELD:
state = { ...state, [action.field]: val };
(using dynamic keys and spread operator for neatness, but it's similar to Object.assign)
All of your form state lives in the Redux store this way. When you are ready to submit that data to the server, you can either use async actions with redux-thunk, or set up some middleware to run the calls. Either way, the strategy is the same; your state lasts locally and populates all your forms, and then is sent to the server when the user submits.
I went through this pretty quick, let me know if you need me to elaborate on anything :)
As you are using react-redux you can use the redux-form. It will greatly help you with the coding as it will simplify your work load and it is also bug-free (as far as I know). In my opinion you would want to use all the libraries/frameworks provided to you as you want to be as agile as possible.
Also the redux-form has a wizard form implementation. I think that is exactly what you are looking for.
http://erikras.github.io/redux-form/#/examples/wizard?_k=yspolv
Just follow the link and you will see a very good tutorial on how to implement it. Should be a piece of cake.

How to use Refs Properly in React js?

I am confused with how the react refs works.
The issue for me is, whenever I change the input select value, update_cart function is called.
I then call actions to set the value using relevant APIs.
However, currently, whenever I change the value, the whole component refreshes and the refs value are set to undefined.
What am I doing wrong?
Please note I have included only relevant codes.
/** #jsx React.DOM */
'use strict'
var React = require('react')
var connect = require("react-redux").connect
var moment = require('moment')
var actions=require("../actions");
var Calendar=require("./calendar");
var utils=require("../utils");
var CartChangeQty = require('./cart_change_qty')
var Table = require('react-bootstrap').Table
var Input = require('react-bootstrap').Input
var Register = require('./register')
var GroceryCheckout = React.createClass({
getInitialState: function() {
return {provinces: [], postal_codes: []};
},
render: function() {
console.log("GroceryCheckout.render");
var day_slots=[];
if (this.props.grocery_cart) {
var delivery_date=this.props.grocery_cart.delivery_date;
if (!delivery_date) delivery_date=this.props.grocery_cart.delivery_slots[0][0];
_.each(this.props.grocery_cart.delivery_slots,function(obj) {
if (obj[0]==delivery_date) {
day_slots=obj[1];
}
}.bind(this));
console.log("###### day_slots",day_slots);
}
return <div className="plr-grocery-checkout">
<a className="plr-anchor" id="checkout"></a>
<h2>Grocery Checkout</h2>
{function() {
if (!this.props.grocery_cart) return <p>Your grocery cart is empty.</p>;
if (!this.props.user_data) {
return <div>
<p>
Is this your first time ordering? <input type="radio" name="first_time" ref="first_time_yes" onClick={this.onchange_first_time.bind(this,true)}/> Yes <input type="radio" name="first_time" ref="first_time_no" onClick={this.onchange_first_time.bind(this,false)}/> No
</p>
{function() {
if (this.state.first_time==true) {
return <Register/>
} else if (this.state.first_time==false) {
return ///something
} else {
return <div>
///something
<div>
<h4><i className="glyphicon glyphicon-home"> </i> Delivery Address</h4>
<Input type="select" onChange={this.update_cart} ref="ship_address" style={{width:'auto',padding:'inherit',height:'auto'}}>
{this.props.user_data.contact_id.addresses.map(function(obj) {
return <option key={obj.id} value={obj.id}>{obj.address}</option>
})}
</Input>
<h4><i className="glyphicon glyphicon-calendar "> </i> Please select your preferred delivery time slot:</h4>
<Calendar />
<div className="form-group">
<label className="col-sm-2 control-label">Payment Method</label>
<div className="col-sm-6">
<Input type="select" onChange={this.update_cart} ref="pay_method" style={{width:'auto',padding:'inherit',height:'auto'}}>
{this.props.grocery_cart.payment_methods.map(function(obj) {
console.log("********************** payment method",obj.name)
return <option key={obj.id} value={obj.id}>{obj.name}</option>
}.bind(this))}
</Input>
</div>
</div>
<div className="form-group">
<label className="col-sm-2 control-label">Payment Amount</label>
<div className="col-sm-6">
<p>{this.props.grocery_cart.amount_total} ฿</p>
</div>
</div>
</div>
<hr/>
<h4><i className=" glyphicon glyphicon-list-alt"> </i> Other Information</h4>
<div className="form-horizontal">
<div className="form-group">
<label className="col-sm-2 control-label">Return Foam Box</label>
<div className="col-sm-6">
<input type="checkbox" onChange={this.update_cart}/>
<span style={{margin:10}}>For this delivery, would you like us to take back the foam box for recycling?</span>
</div>
</div>
</div>
<div className="form-horizontal">
<div className="form-group">
<label className="col-sm-2 control-label">No Call</label>
<div className="col-sm-6">
<input type="checkbox" onChange={this.update_cart}/>
<span style={{margin:10}}>For this delivery, please do NOT call me one hour before delivery to re-confirm unless delayed</span>
</div>
</div>
</div>
<button className="btn btn-lg btn-primary" onClick={this.send_order} disabled={this.props.grocery_cart.amount_total<1500?true:false}><span className="glyphicon glyphicon-ok"></span> Send Order</button>
{this.props.sending_grocery_order?<span><img src="/static/img/spinner.gif"/> Sending order...</span>:null}
{function() {
if (this.props.grocery_cart.amount_total>=1500) return;
return <span className="plr-warning" style={{marginLeft:"20px"}}>Min. order: 1500 ฿!</span>
}.bind(this)()}
</div>
}
}.bind(this)()}
</div>
},
onchange_first_time: function(value) {
console.log("GroceryCheckout.onchange_first_time",value);
this.setState({first_time: value});
},
update_cart: function() {
console.log("GroceryCheckout.update_cart");
console.log("this.refs.pay_method.value",this.refs.pay_method.value);
var vals={
customer_id: this.props.user_data.contact_id.id,
ship_address_id: this.refs.ship_address.value||null,
bill_address_id: this.refs.bill_address.value||null,
pay_method_id: parseInt(this.refs.pay_method.value),
};
this.props.dispatch(actions.grocery_cart_update(vals));
},
onchange_qty: function(product_id,qty) {
console.log("GroceryItem.onchange_qty",product_id,qty);
this.props.dispatch(actions.grocery_cart_set_qty(product_id,qty));
},
})
var select=function(state) {
return {
grocery_cart: state.grocery_cart,
grocery_cart_loading: state.grocery_cart_loading,
user_data: state.user_data,
user_data_loading: state.user_data_loading,
sending_grocery_order: state.sending_grocery_order,
}
}
module.exports=connect(select)(GroceryCheckout);
The reason your setup breaks down is probably because:
on_change_first_time() includes a setState(), which re-renders your component.
update_cart() dispatches an action. Probably this action triggers a new set of props for the component, causing the component to be re-rendered.
In both cases, your refs are probably preserved, but the values are not. Because they are not part of props, nor state. Because the props and state do not include value, react will empty the values upon re-rendering.
It is generally not good practice to read values from input components usings this.refs. In React, refs are for reading and updating DOM, but intended to be used only for stuff that you cannot do through pure react. Examples would be to read the height or width of HTMl components, or to add or remove event listeners to DOM components.
In your case, your update_cart() sends all values to some sort of other function, which presumably stores them somewhere.
I would advise:
put all values of all inputs in props, and pass them to the component.
in your render function, give all your input components a value={this.props.foo} value or similar.
That way, after your cart is sent of and updated, the component will be re-rendered with the new values.
Optionally, you could include optimistic rendering, by adding:
in getInitialState(), copy all your prop values to state values (as initial state of the component).
include parameters in input fields like value={this.state.foo}
in update_cart(), after your dispatch, add a setState() to update the state to the new input values.
The input i am using is a react bootstrap
<Input type="select" onChange={this.update_cart} ref="ship_address" style={{width:'auto',padding:'inherit',height:'auto'}}>
{this.props.user_data.contact_id.addresses.map(function(obj) {
return <option key={obj.id} value={obj.id}>{obj.address}</option>
})}
</Input>
The problem was whenever the onchange was called the render method was again called.
It rerenders because i am calling the set state in here.
One way to fix the issue is to put the input into a different component , where it just re renders that component on change .
Cheers.

Categories