Access string of selected place in StandaloneSearchBox in react-google-maps/api - reactjs

I'm wondering how I can access the actual value in a <StandaloneSearchBox ..> component after the user selected it from the autocomplete dropdown menu. I basically want to make it a controlled component.
I tried getPlaces() but that does not give me the actual value visible on the page but rather a bunch of structured data.
Take the example from the official docs (https://react-google-maps-api-docs.netlify.app/#standalonesearchbox), I basically want to do something like:
...
const [inputFieldValue, setInputFieldValue] = useState ("")
const onPlacesChanged = () => {
...
const value = ... // 1. access value
setInputFieldValue (value) // 2. store in state
}
...
<input
type="text"
placeholder="Customized your placeholder"
style={{...}}
value= {inputFieldValue}
/>
...

Related

unable to edit pre populated textboxes using react

I have a form that has textboxes that are prepopulated from an WebAPI. When I try to delete the text in the textbox to make a change it doesn't delete the prepopulate text. If I try to type over the text, I can see only the first letter of the word I'm typing in the console, but nothing changes on the UI: It' like the textbox is in readonly mode WHICH IT IS NOT
const Details = () => {
const [ server, setServer] = useState([]);
useEffect(() = > {
getServerNames();
}
const getServerName = async() => {
//gets the list of server and their details from the API
}
const serverNameChange = (e) => {
setServer(e.target.value);
}
return (
<div>
{ details.map((data) => {
<input type="text" name="server" onChange={serverNameChange} value={data.serverName} />
))}
</div>
)
};
What am I missing to allow the users to edit the textbox? The textbox is prepopulated with data, however, it can be changed. This is only happening on textboxes that are prepopulated. I don't want to click an Edit button, I want to give the user the ability to make a change in the textbox and then save it.
That might be due to the fact, that data.serverName never changes. It’s basically a static value. If you set the value of an Input, you have to handle the changes (when typing) in the onchange event.
From what I assume, according to your code is that you have multiple input boxes with preloaded values in them and you want to change your serverName if one of them get changed by the value that is in the textinput.
If so, map your details into a state variable:
const [serverNames, setServerNames] = useState(details.map( data => data.serverName));
Map the inputs from your state variable like so:
{serverNames.map((name,index) => {
< input type="text" name="server" onChange={(e) => {updateServerState(e, index)}} value={serverNames[index]} />
}
}
And your updateServerState method looks like that:
updateServerState(e, index) {
let myStateData = [...serverNames];
myStateData[index] = e.target.value;
setServerNames(myStateData);
setServer(e.target.value);
}
Caution: I haven‘t tested the code, just wrote it down. But that should give you an idea of how to solve your issue.
TL;DR; Never use non-state variables for a dynamic value.

Can't get jest to recognize var value changed in onClick

I've got an Address react component which contains an address object defined by {streetAddress, additionalStreetAddress, city, jurisdiction, zipCode}.
Within the JSX I have jurisdiction as a dropdown Select of all the US states.
<Select
id={`${id}-jurisdiction`}
name="jurisdiction"
placeholderOption=" "
labelVisual="State"
value={jurisdiction}
>
{JURISDICTIONS.map((currentJurisdiction) => (
<SelectOption
id={`jurisdiction-${currentJurisdiction}`}
key={currentJurisdiction}
value={currentJurisdiction}
onClick={(e) => { jurisdiction = e.currentTarget.value; }}
>
{currentJurisdiction}
</SelectOption>
))}
</Select>
As you can see, onClick is setting address.jurisdiction to the selected option (i.e. the selected state).
In my test suite I am trying to test that this works by using the following test:
it('should update selected option and updated address jurisdiction when user makes a selection', async () => {
const jurisdictionDropDown = screen.getByRole('combobox');
const user = userEvent.setup();
const selectedJurisdiction = 'MA';
await user.selectOptions(jurisdictionDropDown, [selectedJurisdiction]);
expect(address.jurisdiction).toEqual('MA');
});
The issue I'm seeing is jest is expecting 'MA' but receiving an empty string. Is jurisdiction not being set, or am I referencing it wrong in the expect statement?
From the code, and the fact that you used the word "var" to describe your problem, it sounds like you are setting a normal variable rather than setting and keeping track of state.
Normally, in React you use state to keep track of values changing between renders, otherwise they get lost and you end up with the same initial values. You need to use the useState hook and use that to keep track of your state which hopefully will hopefully make the test pass (assuming it is written correctly).
import React, { useState } from 'react';
const [jurisdiction, setJurisdiction] = useState(JURISDICTIONS[0]);
<Select
id={`${id}-jurisdiction`}
name="jurisdiction"
placeholderOption=""
labelVisual="State"
value={jurisdiction}
>
{JURISDICTIONS.map((currentJurisdiction) => (
<SelectOption
id={`jurisdiction-${currentJurisdiction}`}
key={currentJurisdiction}
value={currentJurisdiction}
onClick={(e) => setJurisdiction(e.currentTarget.value)}
>
{currentJurisdiction}
</SelectOption>
))}
</Select>

How to conditionally render extra form options on checking dynamically generated check boxes in React?

can anyone help, i'm trying this in React but i'm really stuck.
I have 3 checkboxes on a child component that i have rendered dynamically using an array of options in state (in the parent component):
What i need to be able to do is, as per the below image: click on each checkbox and get further options.
https://discourse-user-assets.s3.dualstack.us-east-1.amazonaws.com/original/3X/d/3/d385407399b0fa130741e653c9650ff9953282df.png
The checked options and the sub options (not just dropdowns, the third checkbox has input fields) all need to be available in state so i can collect them up and post them to a database
What i have so far is the below:
Array of options in state:
sowType: [
"ProductSow",
"Teradata Customer SOW",
"Custom Professional Services SOW"
]
Final rendered checkboxes:
https://discourse-user-assets.s3.dualstack.us-east-1.amazonaws.com/original/3X/4/5/45702836b84abe764917f4bdf5172258f4d3e39c.png
My problem is, i don't know what to do next. I have dynamically rendered the initial 3 check boxes but i don't know how to add the conditional rendering to get the sub boxes to appear on clicking the check boxes) and add the info selected from them to state.
i.e. can i only add the conditional rendering on checkboxes that have NOT been dynamically rendered from map or is there a way to do it, in which case how is it done?
My code so far is as below, it may not be the best setup for what i am trying to do:
Can anyone help??
This is the reference to the component in the parent with the props passed down:
<SowType
title={"SOW Type"}
setName={"SOW Type"}
subtitle={"What type of SOW do you want to generate?"}
type={"checkbox"}
controlFunc={this.handleSOWTypeCheckbox}
options={this.state.sowType}
selectedOptions={this.state.sowTypeSelectedOption}
/>
This is the child component dynamically rendering the array of items from state:
class SOWType extends React.Component {
render() {
// console.log(this.props);
return (
<div className="form-group">
<label htmlFor={this.props.name} className="form-label">
{this.props.title}
<h6>{this.props.subtitle}</h6>
</label>
<div className="checkbox-group">
{this.props.options.map(option => {
return (
<label key={option}>
<input
className="form-checkbox"
name={this.props.setName}
onChange={this.props.controlFunc}
value={option}
checked={this.props.selectedOptions.indexOf(option) > -1}
type={this.props.type}
/>
{option}
</label>
);
})}
</div>
</div>
);
}
}
This is the method i am currently using in the parent when a checkbox is clicked in the child component (this basically takes the selected option from the array in state and puts the checked options into another array in state called 'sowTypeSelectedOption: [ ]',
handleSOWTypeCheckbox(e) {
const newSelection = e.target.value;
let newSelectionArray;
if (this.state.sowTypeSelectedOption.indexOf(newSelection) > -1) {
newSelectionArray = this.state.sowTypeSelectedOption.filter(
item => item !== newSelection
);
} else {
newSelectionArray = [...this.state.sowTypeSelectedOption, newSelection];
}
this.setState(
{
sowTypeSelectedOption: newSelectionArray
} /*() =>
console.log("sow Type Selection: ", this.state.sowTypeSelectedOption) */
);
}
If I understand your question correct, you want the additional sub menu to show once the checkbox is selected, then you can use conditional rendering. Just show/hide the menu on select or deselect of checkbox like so.
{ this.props.selectedOptions.indexOf(option) > -1 ? (
<h5>submenu options component renders here</h5>
) : " "
}

React Radio Button event on "checked" attribute

I'm trying to handle an event based on the 'checked' attribute of a radio button in React.js. I want the buttons to allow for selecting more than one value, so I removed the 'name' attribute which seemed to disallow multiple selections.
The base radio button component looks like
export function Radio_Button_Multiple_Selection (props) {
return (
<label>
<input type="radio"
checked={props.form_data[props.field_name].indexOf(props.btn_value) > -1}
onClick={props.radio_effect} />
{props.btn_value}
</label>
)
}
I have a form_data objec that has an array of values that correspond to the btn_value of the radio buttons, where if the value is found in the array it should come up as checked. (And this part is working fine right now, they do in fact show up checked as expected):
const form_data = {
...
occupations: ['student', 'merchant', 'paladin', 'troll'],
...
}
Now, I also have a react class with a method for manipulating the values in the occupations array,responding to whether the radio button being licked was already checked or not:
handleRadioButton (event) {
const target = event.target;
const value = target.value;
const isChecked = target.checked;
console.log(isChecked) // this undefined. why?!?
if (isChecked) {
// remove it from array
// etc.
} else {
// add it to array
// etc.
}
}
My main issue is that following:
When I console.log the "checked" logic that returns a boolean inside the RadioButton component's checked attribute, it comes up as expected (true of false if it is or isnt in the array). But it always comes up as checked = undefined in the class method for handling the buttons.
You cannot uncheck a radio button in HTML either. You have to control the checked attribute with your props or state:
Even more, you should rely only on your state, instead of a mix, e.target.checked & state.
class Radio extends Component {
state = {}
render() {
return <input
type="radio"
checked={this.state.checked}
onClick={e => this.setState({
checked: !this.state.checked
})}
/>
}
}
<input type="radio" />
I found the workaround:
use the 'value' attribute to store the same information that I am storing under the 'checked' attribute, with an array that has the button's value AND the checked logic boolean; e.g., value=[boolean, btn_value]
then access the 'value' attribute in the event handler. the value arrives as a full string, so I just split it at the comma and work from there.
it's hacky, but it worked.

React Redux way of handling enable-disable of DOM elements

I have a form where i have to enable/disable certain DOM elements based on the state of other DOM elements. For e.g. I have a radio button, on the click of which a drop down should be enabled.
Now for implementing this, should I again follow the redux way of disposing an action when the radio is clicked and then within the reducer change the state and then enable/disable the dropdown?
Does redux-form in any way simplify this process? What is the best practice to implement this in a react-redux setup?
I use redux-form for conditional inputs. For example, I have a checkbox that when checked, should display a text area to explain the true input. That looks like this:
<div className="checkbox">
<label for="trueInput">
<input type="checkbox" {...trueInput} />
Is this input true?</label>
</div>
<div className={!trueInput.value ? 'conditional-input' : ''}>
<label for="trueInputExplanation">Why is this input true?</label>
<input className="form-control" {...trueInputExplanation} />
</div>
The class .conditional-input has styling to hide the element. I'd imagine you could do this the same way for disabled, by way of using a ternary function that returns true or false, depending on the conditions you need.
Redux Form keeps track of everything in the store. (It's easy to see what's going on with the Redux Chrome dev tool.) Say I have a master checkbox whose enablement allows me to toggle a slave checkbox. So I want to put the master state read from the form into props:
const mapStateToProps = (state) => {
const isMasterChecked = state.mySetting.isMasterChecked;
const form_mySetting = state.form.mySetting;
const form_isMasterChecked = form_mySetting ? form_mySetting.values.isMasterChecked : null;
return {
isMasterChecked,
form_isMasterChecked
}
};
and then for the form you have
const {isMasterChecked, form_isMasterChecked} = props;
const shouldDisable_slaveCheckbox= () => {
if (form_isMasterChecked == null) return isMasterChecked; // the form is not fully built yet, so use "real" store value instead of reading the form via store
return form_isMasterChecked;
};
<Field name="isSlaveChecked" component="input" type="checkbox" disabled={shouldDisable_slaveCheckbox() ? "" : "disabled"}/>
Use sparingly, as this approach may cause entire form redraw.

Resources