How to set ErrorMessage on TextField dynamically on Button onClick method - reactjs

I need to bind ErrorMessage to textfield only when user press button. In this there are nice examples how to use errormessage but the problem is that I don't know how to make append errorMeesage after user click
<TextField id='titleField' value={titleValue} required={true} label={escape(this.props.description)} onGetErrorMessage={this._getErrorMessage} validateOnLoad={false} />
And this is a call of a button:
private _buttonOnClickHandler() {
let textvalue = document.getElementById('titleField')["value"];
if(textvalue === "")
{
//call onGetErrorMessage or something that will set ErrorMeesage and input will be red
}
return false;
}
Thank you

The easiest way I can think of to accomplish this is by predicating the onGetErrorMessage on a state check, which tracks whether the button has been clicked.
<TextField
id='titleField'
value={titleValue}
required={true}
label={escape(this.props.description)}
// Only allow showing error message, after determining that user has clicked the button
onGetErrorMessage={this.state.buttonHasBeenClicked ? this._getErrorMessage : undefined}
validateOnLoad={false}
/>
Then in your button click handler, simply set that state value:
private _buttonOnClickHandler() {
this.setState({ buttonHasBeenClicked: true });
return false;
}
As long as you instantiate buttonHasBeenClicked to be false, then this method will meet the requirement that (a) before the user clicks the button, no error messages are shown by the TextField, and (b) after the user clicks the button, error messages start to be shown. You retain the ability to use _getErrorMessage(value) to customize the error message based upon the current value in the TextField.

You need to set state for displaying/hiding error messages based on user input, Check below code
import React, { Component } from 'react';
class App extends Component {
state = {
isErrorMessageHidden: true
}
clickHandler = () => {
let textValue = document.getElementById('titleField').value;
if(textValue === '')
this.setState({isErrorMessageHidden: false});
else
this.setState({isErrorMessageHidden: true});
}
render() {
return (
<div>
<button onClick={this.clickHandler}>Check</button>
<input type='text' id='titleField' />
<p
style={{'color':'red'}}
hidden={this.state.isErrorMessageHidden}
>Please fill the form</p>
</div>
);
}
}
export default App;
I hope this helps.

Yet another approach would be to handle all the validations via state values.
The control definition goes like this
<TextField placeholder="Enter a venue location" required onChange={this._onVenueChange} {...this.state.errorData.isValidVenue ? null : { errorMessage: strings.RequiredFieldErrorMessage }}></TextField>
On the Onchange event, you validate the control's value and set the error state value as below,
private _onVenueChange = (event: React.FormEvent<HTMLTextAreaElement | HTMLInputElement>, newValue?: string): void => {
this.setState(prevState => ({
errorData: {
...prevState.errorData,
isValidVenue: newValue && newValue.length > 0,
isValidForm: this.state.errorData.isValidForm && newValue && newValue.length > 0
}
}));
this.setState(prevState => ({
formData: {
...prevState.formData,
venue: newValue
}
}));
}
In the above example, I am using two objects within states, one for capturing the values and other for capturing whether the field is error-ed or not.
Hope this helps..
Cheers!!!

Related

Input tag value update after onChange but want to update it instantly

I am working on a input box where when useState detailsData is true (which is on a radio button) then setName will be my name otherwise it will be user input , but problem is if it is true then it shows nothing unless i click on input and try to type a word and after that it shows string 'tejendra'.
<input
type="text"
className="form_control"
value={name}
onChange={(e) => {
if (DetailsData === true) {
// setName(() => userDetailsData[1]?.name);
setName("tejendra");
} else {
setName(e.target.value);
}
}}
/>
You should use useEffect to trigger a change in something else
useEffect(() => {
if (DetailsData) {
setName("tejendra");
}
}, [detailsData]);

React JS - disable a button if the input field is empty?

React Code:
import { useState } from "react";
export default function IndexPage() {
const [text, setText] = useState("");
const autoComplete = (e) => {
setText({ value: e.target.value });
};
return (
<form>
<input type="text" placeholder="search here" onChange={autoComplete} />
<button type="submit" disabled={!text}> find </button>
</form>
);
}
SandBox Link: https://codesandbox.io/s/practical-panini-slpll
Problem:
when Page Loads, the find button is disabled at first because the input field is empty which is good. But,
Now, when I start typing something. then delete them all with Backspace key. the find button is not disabling again.
I want:
I just want to have my find button disabled if the input field is empty
Where I'm doing wrong?
It's a common mistake coming from Class Components, state setter in hooks does not merge state value as in classes.
You initialized your state as a string (useState('')) and then assigned it as an object
const autoComplete = (e) => {
setText({ value: e.target.value });
};
// State is an object { value: 'some text' }
Fix your set state call:
const autoComplete = (e) => {
setText(e.target.value);
};
// State is a string 'some text'
Then to be more verbose you want to check if the string is empty:
<button disabled={text === ''}>find</button>
disabled={!text.value}
Should do the trick.
With this function
const autoComplete = (e) => {
setText({ value: e.target.value });
};
you are writing your input in text.value, not in text.
use this code for check text
<button type="submit" disabled={text==''}> find </button>

(React-redux) BlueprintJs Suggest cannot backspace in input after making a selection

class MySuggest extends React.Component<Props, State> {
....
....
private handleClick = (item: string, event: SyntheticEvent<HTMLElement, Event>) => {
event.stopPropagation();
event.preventDefault();
this.props.onChange(item);
}
public render() {
const { loading, value, error} = this.props;
const { selectValue } = this.state;
const loadingIcon = loading ? <Icon icon='repeat'></Icon> : undefined;
let errorClass = error? 'error' : '';
const inputProps: Partial<IInputGroupProps> = {
type: 'search',
leftIcon: 'search',
placeholder: 'Enter at least 2 characters to search...',
rightElement: loadingIcon,
value: selectValue,
};
return (
<FormGroup>
<Suggest
disabled={false}
onItemSelect={this.handleClick}
inputProps={inputProps}
items={value}
fill={true}
inputValueRenderer={(item) => item.toString()}
openOnKeyDown={true}
noResults={'no results'}
onQueryChange={(query, event) => {
if (!event) {
this.props.fetchByUserInput(query.toUpperCase());
}
}}
scrollToActiveItem
itemRenderer={(item, { modifiers, handleClick }) => (
<MenuItem
active={modifiers.active}
onClick={() => this.handleClick(item) }
text={item}
key={item}
/>
)}
/>
</FormGroup>
);
}
}
Everything works fine, I am able to make a selection from drop-down list, however I cannot use backspace in input if I made a selection. I checked the official documentation(https://blueprintjs.com/docs/#select/suggest), it has the same issue in its example. Does anyone has the similar problems and solutions?
The reason for this is once you type something in the field, it becomes an element of the page, so once you make a selection, it assumes you highlighted an element, so will assume you are trying to send the page a command for that selection (backspace is the default page-back command for most browsers).
Solution:
Create a new dialog input every time the user makes a selection, so the user can continue to make selections and edits.
It took forever.. post my solution here:
be careful about two things:
1. query = {.....} needed to control the state of the input box
2. openOnKeyDown flag, it makes the delete not working

Changing the label of required in text-field with react and material ui

I am using Material-UI in react application. What I am trying to do is to change the label "Please fill out this field" of text-field when we set the required attribute.
I tried to use setCustomValidity with inputProps, but nothing happens.
There are two types of this label. One is a tooltip that showed up when the mouse is hovered on the text-field, the other when we submit the form.
The error message you are getting is not material-ui, but is the browser handling the error. This cannot be changed since the browser renders this based on the "required" attribute. You can only change this by doing custom error handling on your form.
Here is the code snippet which i used in my personal project:
<TextField
error={this.props.error_val
? true
: false
}
required={this.props.isRequired ? true : false}
type={this.props.type}
label={this.props.label}
variant={this.props.VARIANT}
className={classes.root}
/>
You can use required and error attribute combination for deciding whether the input is filled or not.
Secondly, you can write a validate() which is basically a switch statement where you will pass "label name", "value" and put the return value into your <TextField/> component.
Snippet:
validate = (name, value) => {
let error = "";
switch (name) {
case "name":
error = (!value || value.length == 0) && "Please enter the name";
break;
}
return error;
}
You can replace the 'required' validation message for the TextField component with a custom-validation message (when submitting the form) as follows:
<TextField
onInvalid={() => {
document
.getElementById("business-email-textfield")
.setCustomValidity("Please type a valid email address");
}}
required
id="business-email-textfield"
label="Business Email"
name="email"
onChange={handleInput}
variant="standard"
/>
In the handleInput function you should handle the input of course, but you should also reset the custom-validation message. For example:
const [formInput, setFormInput] = useReducer(
(state, newState) => ({ ...state, ...newState }),
{
email: "",
businessType: "",
}
);
const handleInput = (evt) => {
const name = evt.target.name;
const newValue = evt.target.value;
setFormInput({ [name]: newValue });
//the line below clears the custom-validatio message
document.getElementById(evt.target.id).setCustomValidity("");
};

Updating a selected object when user changes inputs in a form

When a user clicks a square it becomes currentHtmlObject. I want people to be able to update it's properties in the right sidebar.
I have no idea how to take a single input field and update an object's property that I'm holding in a react-redux state and update the main viewing area DrawingCanvas.
I got kinda close where the info I was entering into the form was activating my reducers and actions. But I couldn't figure out how to distinguish between left and top.
// React
import React from 'react'
export class RightSidebar extends React.Component {
constructor(props) {
super(props)
}
handleChange(evt) {
console.log(evt)
this.props.onUpdateCurrentHtmlObject(evt.target.value)
}
render() {
const { currentHtmlObject } = this.props
return (
<form>
{this.props.currentHtmlObject.id}
<div className="right-sidebar">
<div className="form-group">
<label>Position X</label>
<input
type="number"
name="left"
className="form-control"
value={this.props.currentHtmlObject.styles ? this.props.currentHtmlObject.styles.left : ''}
onChange={this.handleChange.bind(this)} />
</div>
<div className="form-group">
<label>Position Y</label>
<input
type="number"
className="form-control"
value={this.props.currentHtmlObject.styles ? this.props.currentHtmlObject.styles.top : ''}
onChange={this.handleChange.bind(this)} />
</div>
</div>
</form>
)
}
}
RightSidebar.defaultProps = {
currentHtmlObject: {
styles: {
left: null,
top: null
}
}
}
There is no need to distinguish between left and top, let's assume you have an action named update and all it does is to update a selected object's property. Here is what the action method may look like:
updateSelectedObj(id, payload){
return {
type: UPDATE_SELECTED_OBJ,
id: id,
payload: payload
}
}
Here is what your event handler might look like in class RightSidebar:
handleChange(evt) {
// since your top and left input fields have a corresponding name property, evt.target.name will return either `left` or `top`
store.dispatch(updateSelectedObj({styles:{evt.target.name:evt.target.value}})
}
Here is your reducer:
[UPDATE_SELECTED_OBJ]: (state, action) => {
// I assume you have a list of objects in the canvas but only one can
// be selected at a time. and I assume the name of the list is objList
let selectedObj = state.objList.filter(obj => obj.id == action.id)[0]
selectedObj = Object.assign({}, selectedObj, action.payload)
return { objList: state.objList.map(obj => obj.id === action.id? Object.assign({}, obj, selectedObj : obj) }
}
I might suggest simplifying the component itself. Sorry for being brief :). I can update w/ more context when I get some time.
This is a stripped down example, but basically thinking of each "number input" as only needing a value and onChange (emits value, not an event).
You would make use of react-redux's connect so that updateObject is a callback accepting the "patch data" to be merged into the currentObject's state.
/**
* #param currentObject
* #param updateObject An already bound action creator that accepts payload to "update object"
*/
function SideBar({currentObject, updateObject}) {
const {styles} = currentObject;
return (
<div>
<NumberInput
value={styles.left}
onChange={left => updateObject({left})}
/>
<NumberInput
value={styles.top}
onChange={top => updateObject({top})}
/>
</div>
)
}
The connect statement might look something like
const SideBarContainer = connect(
(state, {objectId}) => ({
currentObject: _.find(state.objects, {id}),
}),
(dispatch, {objectId}) => ({
updateObject: data => dispatch(
actions.updateObject(objectId, data)
)
})
)(SideBar);
And the actual usage, maybe something like
<SidebarContainer objectId={currentObjectId} />

Resources