How to show different error message on button click? - javascript

Could you please tell me How to show different error message on button click ? Actually when pattern is not matched it should show pattern is not matched .Currently I am only able to show required message .here is my code
<TextField
inputRef={register({ required: true, pattern: /^[A-Za-z]+$/i })}
label="First name"
variant="outlined"
name="firstName"
required
helperText={errors.firstName && "First name is required"}
error={errors.firstName ? true : false}
/>
https://codesandbox.io/s/react-hook-form-get-started-j39p0

You could use something like react-validation package. Using it you will be able to reduce the amount of code you will need to write for your own validation, and also consider the corner cases.
You define your validation functions at first:
import validator from 'validator';
const required = (value) => {
if (!value.toString().trim().length) {
// We can return string or jsx as the 'error' prop for the validated Component
return 'require';
}
};
const email = (value) => {
if (!validator.isEmail(value)) {
return `${value} is not a valid email.`
}
};
...
And after that plug them into your form, wherever required:
export default class Login extends Component {
render() {
return <Form>
<h3>Login</h3>
<div>
<label>
Email*
<Input value='email#email.com' name='email' validations={[required, email]}/>
</label>
</div>
...
Check out their documentation. It is pretty widely used package and should be easy to implement.

Hope this will match with your example
Run it here
replace the regular expression with yours
import React from "react";
import ReactDOM from "react-dom";
import { useForm } from "react-hook-form";
import { TextField, Button } from "#material-ui/core";
import Autocomplete from "#material-ui/lab/Autocomplete";
import { object, string } from "yup";
class Usernames extends React.Component {
constructor(props) {
super(props)
this.state = { errorText: '', value: props.value }
}
onChange(event) {
if (event.target.value.match(/[abc]/g)) {
this.setState({ errorText: 'errr' })
} else {
this.setState({ errorText: 'Invalid format' })
}
}
render() {
return (
<TextField hintText="Firstname"
floatingLabelText="Firstname"
name="name"
helperText={this.state.errorText ? this.state.errorText : ""}
errorText= {this.state.errorText}
onChange={this.onChange.bind(this)}
/>
)
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<Usernames />, rootElement);

Related

How to pass helper text into typescript react component?

I am creating Input component with React and typescript. I have managed to do input and placeholder, but I still need to add helper text at the bottom, so it says ,,Please provide valid email address". Can you please advise how to add this property as a prop?
I tried to add this like below:
import { Meta } from '#storybook/react';
import Input from './Input';
const meta: Meta = {
title: 'Input',
component: Input,
};
export default meta;
export const Default = {
render: () => (
<>
<h1>{'email:'}</h1>
<input placeholder={'Type your email'}></input>
{'Please provide valid email address'}
</>
),
};
but I think that there might be a better way for doing it. Can you please check and advise?
Text will be displayed in storybook as follows:
import { Meta } from '#storybook/react';
import Input from './Input';
const meta: Meta = {
title: 'Input',
component: Input,
};
export default meta;
export const Default = {
render: () => (
<>
<h1>{'email:'}</h1>
<input placeholder={'Type your email'}></input>
{'Please provide valid email address'}
</>
),
};
For styles I will update them with tailwind later on.
Try something like this.
For better understanding, I'll leave to storybook documentation on how to create whats-a-story
// eg inside Input component file
// export interface InputProps {
// placeholder: string;
// }
import Input, { InputProps } from './Input'
export default {
title: 'Input',
component: Input,
};
const Template = args => (
<Input {...args} />
);
const defaultArgs: InputProps = {
placeholder: "Please provide valid email address",
};
export const Default = Template.bind({});
Default.args = { ...defaultArgs };

How to change the "error" prop of a material-ui element?

I am trying to validate a form field and have the following code:
import React, {Component} from 'react';
import {TextField} from '#material-ui/core';
class ProductField extends Component {
constructor(props) {
super(props);
this.isValid = this.isValid.bind(this);
}
isValid() {
console.log("Checking if valid...");
}
componentDidMount() {
console.log("this isn't working");
}
render() {
return (
<TextField style={{width:"100%"}} id={this.props.label} label={this.props.label} variant="outlined"
hintText={this.props.label}
helperText={this.props.meta.touched && this.props.meta.error}
onChange={event => {
console.log("changed");
const { value } = event.target;
this.setState({ searchValue: value });
}}
{...this.props.input}
/>
);
}
}
export default ProductField;
When onChange is called, I want to check the state of the TextField, and if this.props.meta.error is not empty I want to set the Text Field prop "error" and if it is empty then I want to unset the "error" prop.
Right now, even the console.log("Checking if valid...") isn't working, suggesting that the onChange event isn't being fired at all.
What am I doing wrong?
You have several issues in your code:
You need to initialize your state in the constructor, so the state will be reliable with you Textfield, also you have to set a property in the state that will handle if the field is valid or is an `error'.
You need to create a method to validate your TextField value, and inside this method update the state based on the validity of field, here you can add the this.props.meta.error or anything else that is validating your values, and remember to call the method that will validate your value after the state has been properly changed, maybe using it as a callback on the setStatemethod .
You have to add a prop to your TextField component to catch if it is an error or if it is valid.
import React, { Component } from "react";
import { TextField } from "#material-ui/core";
class App extends Component {
constructor(props) {
super(props);
this.state = {
searchValue: "",
isValid: false
};
this.isValid = this.isValid.bind(this);
}
isValid() {
console.log("Checking if valid...");
this.setState({ isValid: this.state.searchValue.length > 6 });
}
componentDidMount() {
console.log("this isn't working");
}
render() {
return (
<TextField
style={{ width: "100%" }}
id={this.props.label}
label={"example"}
variant="outlined"
error={!this.state.isValid && this.state.searchValue != ""}
onChange={event => {
console.log("changed");
const { value } = event.target;
this.setState({ searchValue: value }, () => {
this.isValid();
});
}}
/>
);
}
}
export default App;
Check this sandbox for a working example

Display info when no input in react input

I want to create an input field in React.
It basically should display the entered input real-time (managed this part).
However, it also should display a message "no data provided!" when nothing was entered.
My if statement isn't working? Why?
import React from "react"
import ReactDOM from "react-dom"
class Exercise1 extends React.Component {
constructor() {
super()
this.state = {
firstName:""
}
this.handleChange = this.handleChange.bind(this)
}
handleChange (event) {
this.setState({
[event.target.name]: event.target.value
})
}
render() {
let display
if(this.state.firstname != "") {
display=this.state.firstName
} else {
display="no data provided!"
}
return (
<div>
<form>Input:
<input
type="text"
name="firstName"
placeholder = "no data provided!"
value={this.state.firstName}
onChange={this.handleChange}
/>
</form>
<h1>{display}</h1>
</div>
)
}
}
export default Exercise1
PS: please stick with your answer as much as possible to the code above since I am a beginner and can't follow too different approaches.
You have a typo here. Your state variable is firstName (with capital N), but you are trying to check condition with firstname (with small n). You should do this,
if(this.state.firstName != "") {
display = this.state.firstName
} else {
display = "no data provided!"
}
Demo
Hi you can use your if like this
import React from "react"
import ReactDOM from "react-dom"
class Exercise1 extends React.Component {
constructor() {
super()
this.state = {
firstName:""
}
}
handleChange = (event) => {
this.setState({
[event.target.name]: event.target.value
})
}
render() {
const { firstName } = this.state
return (
<div>
<form>Input:
<input
type="text"
name="firstName"
placeholder = "no data provided!"
value={this.state.firstName}
onChange={this.handleChange}
/>
</form>
<h1>{firstName ? firstName : "no data provided!"}</h1>
</div>
)
}
}
export default Exercise1

React Firebase Timestamp Usage

So I am trying to get a timestamp on the time a post is made, but fire.database.ServerValue.TIMESTAMP doesn't seem to be working in the addTicket function. When I post the ticket, it doesn't load to the Pending page, and just has variables ticketTitle & ticketBody in the Ask URL. I think I am just confused on how the timestamp works in firebase. How do I properly add the timestamp of the post to the database tuple?
Ask.js:
import React, { Component } from 'react';
import AskForm from '../../components/AskForm.js';
import fire from '../../config/Fire.js';
import { Link, withRouter } from 'react-router-dom'
class Ask extends Component {
constructor(props){
super(props);
this.addTicket = this.addTicket.bind(this);
this.database = fire.database().ref().child('tickets');
this.state = {
tickets: [],
userId: this.props.user.uid
}
}
componentDidMount(){
fire.database().ref('/users/' + this.props.user.uid).once('value').then(function(snapshot) {
var FirstName = (snapshot.val() && snapshot.val().userFirstName);
// ...
console.log(FirstName);
});
}
addTicket(title, body){
this.database.push().set({ ticketUserId: this.props.user.uid, ticketTitle: title, ticketBody: body, ticketStatus: 'pending', ticketTime: fire.database.ServerValue.TIMESTAMP});
alert("Your question has been submitted.")
this.props.history.push('/pending')
}
render() {
return (
<div>
<div className="m-container">
</div>
<div>
<AskForm addTicket={this.addTicket} />
</div>
</div>
);
}
}
export default withRouter(Ask);
AskForm.js
import React, { Component } from 'react';
class AskForm extends Component{
constructor(props){
super(props);
this.state = {
ticketBody: '',
ticketTitle: ''
};
this.handleChange = this.handleChange.bind(this);
this.writeTicket = this.writeTicket.bind(this);
}
// When the user input changes, set the ticketTitle or ticketBody
// to the value of what's in the input box.
handleChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
writeTicket(){
if(this.state.ticketTitle === '' || this.state.ticketBody === ''){
alert('Please complete all fields.')
} else {
// Call a method that sets the ticketTitle and ticketBody for a ticket to
// the value of the input
this.props.addTicket(this.state.ticketTitle, this.state.ticketBody);
// Set inputs back to an empty string
this.setState({
ticketBody: '',
ticketTitle: ''
})
}
}
render(){
return(
<div class="s-container">
<form>
<label for="ticketTitle">Title: </label>
<input
id="ticketTitle"
name="ticketTitle"
type="text"
placeholder="A short sentence to identify your issue"
value={this.state.ticketTitle}
onChange={this.handleChange}
/>
<br/>
<br/>
<label for="ticketBody">Description: </label>
<textarea
id="ticketBody"
name="ticketBody"
placeholder="Placeholder"
value={this.state.ticketBody}
onChange={this.handleChange}
/>
<button
className="m-btn"
onClick={this.writeTicket}>
Submit
</button>
</form>
</div>
)
}
}
export default AskForm;
Revisited my question:
I need to import firebase directly using import * as firebase from 'firebase'; instead of from my config file. Then just pushed the time value to the database with my other values. See below for example.
Code:
import * as firebase from 'firebase';
addMessage(body){
this.questionDatabase.child(this.state.questionId).child('messages').push().set({
messageUserId: fire.auth().currentUser.uid,
messageBody: body,
time: firebase.database.ServerValue.TIMESTAMP
});
}
This works to create a timestamp client side is using firestore: (In this case I export it from my main firebase.js file)
import firebase from "firebase/compat/app";
import "firebase/compat/firestore";
export const serverStamp = firebase.firestore.Timestamp
To use it after importing serverStamp:
var stampNow = serverStamp.now()

Unit testing custom Input React Component to be used with redux-form Fails

I am having a tough time testing the custom React Input Element.
I have implemented a reusable Input React Component to be used both inside a ReduxForm and outside as well. It is as follows:
<!-- Unit Test -->
import React from 'react';
import ReactDOM from 'react-dom';
import { shallow, mount } from 'enzyme';
import 'jest-enzyme';
import InputField from '../InputField';
import { Field, reduxForm } from 'redux-form';
describe('InputField tests', () => {
// MyForm.js
function MyForm (props) {
return (
<form>
<Field label="firstName" name="firstName" placeholder="test" component={InputField}/>
</form>
);
}
var testForm = reduxForm({form: 'test'})(MyForm);
test('InputField used as a Field on the redux-form', () => {
let formFieldFixture = mount(<testForm />);
// let formFieldFixture = shallow(<Field label="firstName" name="firstName" placeholder="test" component={InputField} withRef/>);
let fieldElem = formFieldFixture.find('label');
expect(labelElem.text()).toEqual('firstName');
});
});
<!-- InputField.js -->
/**
* InputField is a generic React component to be used for html input field both in the redux-form and otherwise.
*/
import React, { Component, PropTypes } from 'react';
const InputField = ({ name, input, label, placeholder, value, readOnly, meta }) => {
const { touched, error, warning, dirty } = meta ? meta : {};
let inputClasses = `text-input input--regular ${(touched && error) ? 'validation-error' : ((touched && warning) ? 'validation-warning' : '')}`;
return (<div>
<label htmlFor={name}>{label}</label>
{(readOnly) ? <input type="text" value={value} className={inputClasses} placeholder={placeholder} readOnly /> :
<input {...input} type="text" className={inputClasses} placeholder={placeholder} />}
{touched &&
((error && <div className="validation-error">{error}</div>) ||
(warning && <div className="validation-error">{warning}</div>))}
</div>);
};
export default InputField;
It fails on the line
expect(labelElem.text()).toEqual('firstName'); with error
ReferenceError: labelElem is not defined.
What am I missing? or doing wrong.

Categories