Open Mottoweb opened 8 years ago
@Mottoweb can you provide me a little example. You should be able to call validate on mount.
here is my component
import React from 'react'
import { ExnessBaseComponent } from 'exness-libraries'
import validation from 'react-validation-mixin'
import strategy from 'react-validatorjs-strategy'
import classNames from 'classnames'
import { verificationValidatorTypes } from './helpers/verification-validator-types'
if (!window.Signup) window.Signup = {}
const Signup = window.Signup
class EmailForm extends ExnessBaseComponent {
state = {
email: 'adere@adere.com',
phone: '+357 99911330',
countdownState: true,
emailCode: '',
phoneCode: '',
}
i18n = Signup.i18n
constructor(props) {
super(props)
this.i18n = Signup.i18n
this.validatorTypes = verificationValidatorTypes
this.bindAll(
'renderPhoneText',
'renderEmailText',
'renderPhoneResendText',
'renderEmailResendText',
'onSubmit',
'startTimer',
'tick',
'replaceString',
'handleCallback',
'handleEmailResend',
'handlePhoneResend',
'getValidatorData',
'onChange',
'onBlur',
'renderValidationIcon',
'getButtonClasses',
'setInterval',
'validate',
)
}
validate(name) {
if (!name) return this.props.isValid()
return this.props.isValid(name)
}
getValidatorData() {
return this.state
}
onChange(field, e) {
const state = {}
state[field] = e.target.value
this.setState(state)
}
componentDidMount() {
this.startTimer()
const resendEmailLink = document.getElementById('verification-email-resend-link')
if (!resendEmailLink) return
resendEmailLink.addEventListener('click', this.handleEmailResend)
this.props.validate()
}
componentDidUpdate() {
const resendPhoneLink = document.getElementById('verification-phone-resend-link')
const callbackLink = document.getElementById('verification-call-back-link')
if (!resendPhoneLink || !callbackLink) return
if (!this.state.countdownState) {
resendPhoneLink.addEventListener('click', this.handlePhoneResend)
callbackLink.addEventListener('click', this.handleCallback)
} else {
resendPhoneLink.removeEventListener('click', this.handlePhoneResend)
callbackLink.removeEventListener('click', this.handleCallback)
}
}
componentWillUnmount() {
clearInterval(this.interval)
const resendEmailLink = document.getElementById('verification-email-resend-link')
if (!resendEmailLink) return
resendEmailLink.removeEventListener('click', this.handleEmailResend)
}
startTimer() {
this.setState({
secondsRemaining: 60,
countdownState: true,
}, this.setInterval())
}
setInterval() {
this.interval = setInterval(this.tick, 1000)
}
tick() {
this.setState({
secondsRemaining: this.state.secondsRemaining - 1,
})
if (this.state.secondsRemaining <= 0) {
clearInterval(this.interval)
this.setState({
countdownState: false,
})
}
}
replaceString(string, value) {
return string.replace(/<%([^%>]+)?%>/, value)
}
onSubmit(event) {
if (event) event.preventDefault()
const onValidate = error => {
if (error) {
// yo
} else {
// yo
}
}
this.props.validate(onValidate)
}
render() {
return (
<div>
<div className="signup-verification__wrapper">
<input
type="text"
className="ui-input ui-input__middleBigTidy"
value={this.state.phoneCode}
onChange={this.onChange.bind(this, 'phoneCode')}
onBlur={this.props.handleValidation('phoneCode')}
/>
{this.renderValidationIcon('phoneCode')}
</div>
<div className="signup-verification__wrapper">
<input
type="text"
className="ui-input ui-input__middleBigTidy"
value={this.state.emailCode}
onChange={this.onChange.bind(this, 'emailCode')}
onBlur={this.props.handleValidation('emailCode')}
/>
{this.renderValidationIcon('emailCode')}
</div>
<button
className={this.getButtonClasses()}
onClick={this.onSubmit}
>
{this.i18n.Confirm}
</button>
</div>
)
}
renderValidationIcon(name) {
const isValid = this.validate(name)
const className = classNames({
'verification-text': true,
valid: isValid,
invalid: !isValid,
})
return (
<p className={className}>
{isValid ? this.i18n.Valid : this.i18n.Invalid}
</p>
)
}
getButtonClasses() {
return classNames({
'ui-btn': true,
'signup-verification__margin-top': true,
'ui-btn__disabled': !this.validate(),
})
}
}
export default validation(strategy)(EmailForm)
@Mottoweb hmm my guess is that you need to create your state object in your constructor. It looks like your getValidatorData
call is returning undefined initially after mount.
Try this:
constructor(props) {
// ...
this.state = {};
}
Hmm ok second look I see you have the state define on the class? try moving it into the constructor:
constructor(props) {
// ...
this.state = {
email: 'adere@adere.com',
phone: '+357 99911330',
countdownState: true,
emailCode: '',
phoneCode: '',
};
}
Did not help :( Temporary workaround for me - set this.props.errors in constructor to invalidate specific field and/or form. Once the true validations takes place, parent state.errors is empty or repopulated with true error messages.
Can you try binding the getValiadatorData
method in the constructor? Or even put a dubugger inside this function to see if it's called. It seems to me that this.state
must not be resolving correctly when getValidatorData
is called on Mount.
constructor(props) {
//...
this.getValidatorData = this.getValidatorData.bind(this);
}
Edit: I now see the binding for getValidatorData
, try the debugger inside the method and inspect this.state
. Let me know what you see.
Follow up ? - Can you try to extend React.Component
instead of the ExnessBaseComponent
there could be some conflict in the extention of this base class. We may need to simplify your example to find the root issue.
Hey, I’m having the exact same problem. I have a component that used to work as expected when I was using React.createClass
but today I refactored it to use ES6 class
and got this problem. I have to validate the data when the component mounts to enable the button that will allow the user to proceed depending on the data that loads in the state. The component has a lot of stuff but I simplified the code to the maximum to test it out and still got the problem. The form validates as expected if I remove the validation call from componentDidMount
but when I add it I get this error and the validation doesn't work at all after that. Also, from what I can see getValidatorData
is not even being called. Here is my problematic code: https://gist.github.com/camilacnery/4be2543e5803f95481b17f42b0a14652
I managed to get around the problem by starting with an empty state and calling a function in componentDidMount
to set the state with the information I want. It's not ideal but it'll do for now... Let me know if I can do anything else to help find the source of the problem.
Here is the code that works: https://gist.github.com/camilacnery/96e60d283faae4bf4a9dda7a7e7c822a
@camilacnery thanks for putting together these examples. I'll try to get a resolution soon.
I need to invalidate the form on mount. Calling this.props.validate in componentDidMount return an invariant error.
Invariant Violation: Data was not provided to the Validator. Implement "getValidatorData" to return data.
Adding directly to wrapped component looks like terrible thing to me, is there any other way to make this work?