This is a simple registration page with username, email, phone num, password and repeat password. The problem lies in repeat password input. This input is supposed to trigger verifyRePassword on text change (just like every other input, and their respective functions). While other inputs have no problem triggering their functions, Repeat Password seems to not trigger its function (verifyRePassword) on text change.
I have tried switching each input with another function, and other inputs seem to trigger the function verifyRePassword just fine.
//FUNCTIONS
verifyPassword = (text) => {
this.setState({password:text})
console.log("verifyPassword Called");
let reg = /\w{6,}/ ;
if(reg.test(text) === false)
{
this.setState({errMsgPassword: "Password must be longer than 6 characters"})
this.setState({password:text})
}
else {
this.setState({errMsgPassword: ""})
this.setState({password:text})
}
}
verifyRePassword = (text) => {
this.setState({repassword: text})
console.log("verifyRePassword Called !!!");
const passStr = toString(this.state.password)
const repassStr = toString(this.state.repassword)
if (passStr === repassStr) {
this.setState({
errMsgRePassword: ""
})
}
else{
this.setState({
errMsgRePassword: "Password must match."
})
}
}
//INPUT
<Text style={stsh.textError}>{this.state.errMsgPhonenum}</Text>
<Text style={stsh.text1}>Password</Text>
<TextInput style={stsh.text2}
onChangeText={this.verifyPassword}
secureTextEntry={true}
/>
<Text style={stsh.textError}>Error {this.state.errMsgPassword}</Text>
<Text style={stsh.text1}>Repeat Password</Text>
<TextInput style={stsh.text2}
onChangeText={this.verifyRePassword.bind(this)}
secureTextEntry={true}
/>
<Text style={stsh.textError}>Error {this.state.errMsgRePassword}</Text>
Since the two are structured similarly, they both should work just fine. Password works, but not Repeat Password.
*edit: some more bits from the code
//CONSTRUCTOR
constructor(){
super()
this.state = {
username: "",
emailadd: "",
phonenum: "",
password: "",
repassword: ""
}
this.verifyUsername = this.verifyUsername.bind(this)
this.verifyEmailadd = this.verifyEmailadd.bind(this)
this.verifyPhonenum = this.verifyPhonenum.bind(this)
this.verifyPassword = this.verifyPassword.bind(this)
}
//COMPLETE FUNCTIONS
verifyUsername = (text) => {
this.setState({username:text})
console.log(text);
let reg = /\w{5,30}/ ;
if(reg.test(text) === false)
{
this.setState({errMsgUsername: "Username must contain 5 to 30 characters"})
this.setState({username:text})
return false;
}
else {
this.setState({errMsgUsername: ""})
this.setState({username:text})
}
}
verifyEmailadd = (text) => {
this.setState({emailadd:text})
console.log(text);
let reg = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/ ;
if(reg.test(text) === false)
{
this.setState({errMsgEmailadd: "Enter a valid email address"})
this.setState({emailadd:text})
return false;
}
else {
this.setState({emailadd:text})
this.setState({errMsgEmailadd: ""})
}
}
verifyPhonenum = (text) => {
this.setState({phonenum:text})
console.log(text);
let reg = /\d{10,11}/ ;
if(reg.test(text) === false)
{
this.setState({errMsgPhonenum: "Phone number must be 10 to 11 characters long consisting only of digits"})
this.setState({phonenum:text})
return false;
}
else {
this.setState({errMsgPhonenum: ""})
this.setState({phonenum:text})
}
}
verifyPassword = (text) => {
this.setState({password:text})
console.log("verifyPassword Called");
let reg = /\w{6,}/ ;
if(reg.test(text) === false)
{
this.setState({errMsgPassword: "Password must be longer than 6 characters"})
this.setState({password:text})
}
else {
this.setState({errMsgPassword: ""})
this.setState({password:text})
}
}
verifyRePassword = (text) => {
this.setState({repassword: text})
console.log("verifyRePassword Called !!!");
const passStr = toString(this.state.password)
const repassStr = toString(this.state.repassword)
if (passStr === repassStr) {
this.setState({
errMsgRePassword: ""
})
}
else{
this.setState({
errMsgRePassword: "Password must match."
})
}
}
//COMPLETE RENDER
render() {
return (
<View style={{flex: 1}}>
<SafeAreaView>
<ScrollView style={stsh.container}>
<Text style={{fontSize:40, fontWeight: "bold", borderBottomWidth: 2, color: "#515151", borderColor: "#515151"}}>Sign Up</Text>
<Text style={{color: "#515151",fontSize: 20,fontWeight: "bold",paddingTop: 60}}>Username</Text>
<TextInput style={stsh.text2}
onChangeText={this.verifyUsername}
maxLength={30}
t
/>
<Text style={stsh.textError}>{this.state.errMsgUsername}</Text>
<Text style={stsh.text1}>Email</Text>
<TextInput style={stsh.text2}
value={this.state.email}
onChangeText={this.verifyEmailadd.bind(this)}
/>
<Text style={stsh.textError}>{this.state.errMsgEmailadd}</Text>
<Text style={stsh.text1}>Phone number</Text>
<TextInput style={stsh.text2}
onChangeText={this.verifyPhonenum}
maxLength={11}
/>
<Text style={stsh.textError}>{this.state.errMsgPhonenum}</Text>
<Text style={stsh.text1}>Password</Text>
<TextInput style={stsh.text2}
onChangeText={this.verifyPassword}
secureTextEntry={true}
/>
<Text style={stsh.textError}>Error {this.state.errMsgPassword}</Text>
<Text style={stsh.text1}>Repeat Password</Text>
<TextInput style={stsh.text2}
onChangeText={this.verifyRePassword}
secureTextEntry={true}
/>
<Text style={stsh.textError}>Error {this.state.errMsgRePassword}</Text>
<Text style={{paddingBottom: 50}}></Text>
<Button color='#515151'
onPress={this.submitRegister}
type="outline"
title="Sign Up"
titleStyle={{paddingVertical: 10, fontSize: 30, fontWeight: "bold", color: "#515151"}}
buttonStyle={{borderColor:"#515151", borderWidth: 10, borderRadius: 20}}
/>
<Text style={{paddingBottom: 100}}></Text>
</ScrollView>
</SafeAreaView>
</View>
);
}
}
I've rewrite your verifyRePassword function (I removed the "toString()" as I don't see why it's needed there), try the code below:
verifyRePassword = (text) => {
console.log("verifyRePassword Called !!!", text);
this.setState(()=>{
return {repassword: text};
}, ()=>{
const {password, repassword} = this.state;
this.setState({
errMsgRePassword: password === repassword? "" : "Password must match.",
});
});
}
The issue with comparing the values like you did is that; there is actually a time gap before setState change the value of repassword. Which means; when the line
const repassStr = toString(this.state.repassword)
runs, it actually gets the previous value of "repassword". For this reason, you should use the callback for setState as shown above.
Related
I'm trying to make a basic login screen. However, I'm struggling with the e-mail validation.
Every time I press a button, I want to make sure that the user inputs the correct e-mail format, or give them a small alert under the e-mail TextInput if they write something other than a valid e-mail (this alert will be hidden by default.). However, when I try, it always gives me this error (regardless of the user input):
undefined is not an object (evaluating 'this.state.username')
This is my code so far
class HomeScreen extends Component {
state = { username: null, password: null }
show = false;
_validar = (text) => {
let reg = /^\w+([\.-]?\w+)*#\w+([\.-]?\w+)*(\.\w{2,3})+$/ ;
if(reg.test(text) === false) {
return false;
} else {
return true;
}
}
_onSubmit() {
if(this._validar(this.state.username) == true) {
const { username, password } = this.state;
} else {
this.show = true;
}
}
render() {
return (
<KeyboardAwareScrollView contentContainerStyle={styles.container} scrollEnabled
enableOnAndroid={true} resetScrollToCoords={{x:0, y:0}}>
<View style={styles.logo}>
<Image source = {logo} style={styles.img}/>
<Text style={styles.textLogoPrimary}>Neuron App</Text>
<Text style={styles.textLogoSecondary}>Test</Text>
</View>
<View style={styles.formElement}>
<Text style={styles.formText}>Correo Electrónico</Text>
<TextInput keyboardType='email-address' placeholder='Email' onChangeText={value => this.setState({ username: value })}
style={styles.formInput} />
{this.state.show ? (
<Text style={styles.textAlert}>Correo Electrónico no valido.</Text>
) : null}
</View>
<View style={styles.formElement}>
<Text style={styles.formText}>Contraseña</Text>
<TextInput style={styles.formInput} onChangeText={value => this.setState({ password: value })} secureTextEntry={true}/>
</View>
<View style={styles.buttonView}>
<TouchableOpacity style={styles.button} onPress={this._onSubmit}>
<Text style={styles.buttonText}>Iniciar</Text>
</TouchableOpacity>
</View>
</KeyboardAwareScrollView>
);
}}
Just change your onSubmit funciton to "
_onSubmit = () =>{
if(this._validar(this.state.username) == true) {
const { username, password } = this.state;
} else {
this.show = true;
}
}
ES^ binds this automatically. Hope it solves the error
This error is raised because you are accessing the this.state.username before it is assigned. I would recommend you to change the initial state value of username into a string, as it ends up being a string, instead of null.
state = { username: '', password: '' };
null can be avoided in string case, by just assigning it '' an empty string. If you are to evaluate it logically, it would give you same result as null as it is 'falsy'.
render(){
return (
<ImageBackground
source={require('../images/back02.png')}
style={styles.bgscreen}
>
<KeyboardAvoidingView behavior='position'>
<Image
style={styles.headImage}
source={require('../images/login_img.png')}
/>
<ImgBack/>
</KeyboardAvoidingView>
<BottomButton navigation={this.props.navigation} />
</ImageBackground>
);}
}
ImgBack contains username and password textinput.
BottomButton contains the submit button
I want to navigate to new activity when submit button clicked. navigation to new screen is working perfectly but before navigating i want to null check the TextInput which are on
I am new to React-Native. Complete Beginner here. I want even know what to do. Help.
ImgBack.js file
class imgBack extends React.Component {
constructor()
{
super();
this.state = { hidePassword: true }
}
managePasswordVisibility = () =>
{
this.setState({ hidePassword: !this.state.hidePassword });
}
usernameValidate = (EnteredValue) =>{
var TextLength = EnteredValue.length.toString();
if(TextLength == 10 ){
Alert.alert("Sorry, You have reached the maximum input limit.")
}
else if(TextLength == 0){
Alert.alert("Username can't be blank")
}
}
passValidate = (EnteredValue) =>{
var TextLength = EnteredValue.length.toString();
if(TextLength == 10 ){
Alert.alert("Sorry, You have reached the maximum input limit.")
}
else if(TextLength == 0){
Alert.alert("Username can't be blank")
}
}
render(){
return (
<ImageBackground resizeMode='contain'
source={require('../images/login_back.png')}
style={{
marginHorizontal: 10,
height: 290,
padding: 30,
}}>
<View style={
styles.textInputContainer
} >
<TextInput
placeholder="Username"
underlineColorAndroid = "transparent"
placeholderTextColor="#000000"
maxLength={10}
onChangeText={ EnteredValue => this.usernameValidate(EnteredValue) }
/>
</View>
<View style = { styles.textInputContainer }>
<TextInput
onChangeText={ EnteredValue => this.passValidate(EnteredValue) }
underlineColorAndroid = "transparent"
secureTextEntry = { this.state.hidePassword }
placeholder="Password"
placeholderTextColor="#000"
/>
<TouchableOpacity style = { styles.visibilityBtn } onPress = { this.managePasswordVisibility }>
<Image source = { ( this.state.hidePassword ) ? require('../images/eye_close_icon.imageset/eye_close_icon.png') : require('../images/eye_icon.imageset/eye_icon.png') } style = { styles.btnImage } />
</TouchableOpacity>
</View>
</ImageBackground>
)
}
} ```
**Bottombutton File**
class bottomButon extends Component {
render(){
return (
<ImageBackground
style={{ height: 80, marginLeft: '20%', marginTop: 10 }}
resizeMode={'center'}
source={require('../images/btn_back.png')} >
<TouchableOpacity
onPress={ this.login } >
<Text style={{ textAlign: 'center', marginTop: 25 }}>Submit & SYNC</Text>
</TouchableOpacity>
</ImageBackground>
)
} }
export default bottomButon; ```
solution:
constructor(props) {
super(props);
this.state = {
hidePassword: true,
username: '',
password: '',
};
}
validUserPass = async () => {
try {
if (this.state.username === '') {
Alert.alert('Username is required !');
} else if (this.state.password === '') {
Alert.alert('Password is required !');
} else {
this.props.navigation.navigate('selectEmoji');
}
} catch (error) {
console.warn(error);
}
};
it helped me solve my issue.
I've a screen where there is a button to add textInputs. Any no. of inputs can be added by the user. There is another button named submit. When it is tapped, how can I get the appropriate input values. I need them in array eg: [{name1, designation1}, {name2, designation2}, ...].
Code:
App.js
export default class App extends React.Component {
state = {
myArr: []
}
_onPressOut() {
let temp = index ++
this.state.myArr.push(temp)
this.setState({
myArr: this.state.myArr
})
}
_getData() {
//how can I get the data from input values here?
}
render() {
let Arr = this.state.myArr.map((a, i) => {
return <NewComponent />
})
return (
<ScrollView>
<View style={styles.container}>
<Text>Event 1st</Text>
{ Arr }
<Text>Eventlast</Text>
</View>
<TouchableOpacity onPress={() => this._onPressOut()}>
<Text style={{ color: 'green' }}>Add New Component</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this._getData()}>
<View style={{ backgroundColor: 'blue', marginTop: 30 }}>
<Text style={{ color: 'white', textAlign: 'center', marginVertical: 10 }}>Submit</Text>
</View>
</TouchableOpacity>
</ScrollView>
);
}
}
NewComponent.js
class NewComponent extends React.Component{
state = {
name: '',
designation: '',
}
onNameChange = (text) => {
this.setState({
name: text,
});
}
render () {
return (
<View style={{ borderTopWidth:2, borderBottomColor: 'red', paddingTop: 20, marginTop: 30 }}>
<TextInput
placeholder={'Enter Your Name'}
onChangeText={text => {
this.onNameChange(text);
// this.onPropValueChange('SignUpName', text);
}}
value={this.state.name}
style={[{borderBottomColor:'red', borderBottomWidth: 1}]}
/>
<TextInput
placeholder={'Designation'}
onChangeText={text => {
this.onDesignationChange(text);
// this.onPropValueChange('SignUpDesignation', text)
}
}
value={this.state.designation}
style={[{borderBottomColor:'red', borderBottomWidth: 1}]}
/>
</View>
);
}
}
Considering the following assumptions that,until the name is filled,the designation cannot be filled and until the one set of name and designation are filled, the next set of inputs should not be rendered,
In NewComponent.js for the destinationTextInput, make the following changes.
<TextInput
placeholder={'Designation'}
onChangeText={text => {
this.onDesignationChange(text);
// this.onPropValueChange('SignUpDesignation', text)
}
}
value={this.state.designation}
style={[{borderBottomColor:'red', borderBottomWidth: 1}]}
onBlur = {() => {this.props.onNameAndDesignationAdded(this.state.name,this.state.designation)}}
/>
And in App.js add the following
in state object, introduce a new state called resultArr as follows:
state = {
myArr: [],
resultArr : []
}
The _getData function will be as follows:
_getData(name,designation) {
//how can I get the data from input values here?
if(name,designation) {
let tempArr = this.state.resultArr;
tempArr.push({name, designation})
this.setState({resultArr : tempArr})
}
}
The NewComponent called in App.js will have a callback from the TextInput of destination input onBlur method.
let Arr = this.state.myArr.map((a, i) => {
return <NewComponent onNameAndDesignationAdded = {(name,designation) => {
this._getData(name,designation)
} } />
})
I'm currently encounter a particular issue with my Edit page code. The problem is as follow: when the user wants to edit their username (on the application), if the user types the (new) username in the textInput field (called 'name')and clicks on the button (Image button of a pencil) , the application is not changing the username. During debugging, the debugger tells me that name is undefined. below follows the code snippet:
edit(name) {
let { user } = this.state;
if (user) {
user.updateProfile({
displayName: name, // here i get the error of 'Undefied'
}).then(() => {
// Update successful.0
}).catch((error) => {
// An error happened.
});
}
}
Below follows the full code of the page:
//constructor
constructor() {
super();
this.state = {
user: {},
fetching: true,
}
this.onAuthStateChanged = this.onAuthStateChanged.bind(this);
}
componentDidMount() {
//Functionality
this.unsubscribeOnAuthChange = firebase.auth().onAuthStateChanged(this.onAuthStateChanged);
}
componentWillUnmount() {
this.unsubscribeOnAuthChange();
}
onAuthStateChanged(user) {
this.setState({ user, fetching: false })
}
edit(name) {
let { user } = this.state;
if (user) {
user.updateProfile({
displayName: name,
}).then(() => {
// Update successful.0
}).catch((error) => {
// An error happened.
});
}
}
ok = () => {
this.props.navigation.navigate('Home');
}
//Styles Account
render() {
let { user, fetching } = this.state;
if(fetching) return null;
return (
<ScrollView>
<View style={styles.container}>
<Text style={styles.text}>Account</Text>
<View style={styles.row}>
<Image source={require('./Picture/userImage1.png')} />
<TouchableOpacity onPress={() => this.edit(user.name)}>
<Image source={require('./Picture/pencil.png')} style={styles.pencil} />
</TouchableOpacity>
</View>
<Text style={styles.text1}>Welcome {user.displayName}</Text>
<TextInput
style={styles.textInput} placeholder='Username'
onChangeText={(name) => this.setState({name})}
underlineColorAndroid='transparent'
autoCapitalize='none'
/>
<TouchableOpacity
style={styles.btn}
onPress={() => this.ok()}>
<Text style={{ fontSize: 17, color: '#fff' }}>Ok</Text>
</TouchableOpacity>
</View>
</ScrollView>
);
}
}
Can anyone give me some advice of why i'm getting an 'undefined" error when the user clicks on the image button?
<TextInput
style={styles.textInput} placeholder='Username'
onChangeText={(name) => this.setState({name})} //<---Here you set value in state call `name`
underlineColorAndroid='transparent'
autoCapitalize='none'
/>
While HERE you are passing the value of object key name
<TouchableOpacity onPress={() => this.edit(user.name)}>
Just simply define name state in this.state and pass the value of state this.state.name in edit function.
In my application, I want to navigate to another screen from a button in a modal. I tried the normal workout and it didn't work. The modal closes properly but the navigation doesn't happen. What am I doing wrong here? Im trying to navigate from navigateToMainFeed() and it stays in the same screen without navigating.
class TrainerRegistraionScreen extends Component {
constructor(props) {
super(props);
this.state = {
statement: {
value: "",
valid: false,
touched: false,
validationRules: {
minLength: 1
}
},
keyboardVisible: false,
buttonTouched: false,
displayModal: false
}
}
// handle statement changes
statementChangedHandler = value => {
this.setState(prevState => {
return {
statement: {
...prevState.statement,
value: value,
touched: true,
valid: validate(value, prevState.statement.validationRules)
},
buttonTouched: false
};
});
};
// check for empty fields of the screen
_getFiledsNotEmptyStatus = () => {
return this.state.statement.value.length > 0 ? true : false;
}
// display message
_displayMessage = () => {
let { keyboardVisible } = this.state;
let content = (
<View style={{ width: "90%", marginBottom: 10, alignSelf: 'center' }}>
<Text style={{ fontSize: 16, color: "#707070", fontWeight: "300" }}>
Please write a short statement about your focuses as a trainer.
It is important to show your capabilities and knowledge base in
exercise and nutrition science. Inclue all certification details.
</Text>
</View>
);
if (keyboardVisible) {
content = null;
}
return content;
}
// navigate to main feed
navigateToMainFeed = () => {
this.props.navigation.navigate("mainfeed");
this.setState({
displayModal: false
});
}
// register trainer
async registerTrainer() {
let {
firstName,
lastName,
email,
password
} = this.props;
this.setState({
buttonTouched: true
});
let trainer = {
firstName: firstName,
lastName: lastName,
email: email,
password: password
}
await this.props.registerTrainer(trainer);
if (!this.props.signUpHasError) {
this.setState({
displayModal: true
});
}
}
// render popup modal
_renderPopupModal() {
return (
<ModalPopup visible={this.state.displayModal}>
<TrainerMessage
onPress={() => this.navigateToMainFeed()}
/>
</ModalPopup>
);
}
// render
render() {
let { userRegistrationInProgress } = this.props;
return (
<View>
<ImageBackground source={BackgroundOnly} style={{ width: width, height: height }} >
<View style={{ marginTop: "5%" }}>
<ClickableIcon
source={BackArrow}
height={30}
width={30}
onIconPressed={() => {this.props.navigation.navigate("trainerExperience");}}
/>
</View>
<View style={styles.headerStyles}>
<HeadingText
fontSize={26}
fontWeight={300}
textAlign="left"
fontColor="#707070"
>
Personal Statement
</HeadingText>
</View>
<View>
{this._displayMessage()}
</View>
<View style={styles.detailInput}>
<DetailInput
inputStyle={styles.inputStyles}
height={120}
width={width - 40}
multiline={true}
numberOfLines={6}
underlineColorAndroid="transparent"
maxLength={500}
editable={!userRegistrationInProgress}
onChangeText={value => this.statementChangedHandler(value)}
/>
</View>
<View>
<RoundedButton
buttonStyle={styles.buttonStyle}
text="FINISH"
submitting={userRegistrationInProgress}
onPress={() => this.registerTrainer()}
disabled={!this._getFiledsNotEmptyStatus()}
/>
</View>
{this._renderPopupModal()}
</ImageBackground>
</View>
);
}
static navigationOptions = { header: null }
}
First close the modal and navigate the screen
this.setState({
displayModal: false
},()=>{
this.props.navigation.navigate("mainfeed");
});