Cannot get value from TextInput - react-native

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.

Related

Basic API Login Authentication with React-Native

I need to make basic API login authentication with email and password, but I didn't find good working examples. I need help...
1- It should make a POST request to URL of the base
2- The email and password needs to be as variables like "...this.state.email/this.state.password" (something like that) so then I can set them in the input fields like "...this.handleEmail/.thishandlePassword" (something like that I think)
3- I need a log in the console or response from the api for success or fail authentication
4- Need to show error if the fields are empty or there is no user with this email or password
class LoginScreen extends Component {
constructor(){
super();
this.state = {
email: '',
password: '',
result: false,
}
}
_userLogin() {
let email = this.state.username;
let password = this.state.password;
if (email && password) {
fetch("https://URL/api/login", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
email: email,
password: password,
})
})
.then((response) => response.json())
.then((responseData) => {
console.log(responseData),
this._onValueChange(STORAGE_KEY, responseData.id_token)
})
.done();
renderResults();
}
}
renderResults = () => {
if(responseData){
this.setState({
result: true
})
}
}
handleEmail = (text) => {
this.setState({ email: text })
}
handlePassword = (text) => {
this.setState({ password: text })
}
render() {
return (
<Container style={styles.container}>
<StatusBar translucent backgroundColor="transparent"/>
<Content>
<View style={styles.imageContainer}>
<Image style={styles.imageWave} source={require("./pictures/Group723.png")}/>
<Text style={styles.headerTextContainer}>
<Text style={styles.boldHeaderText}>Hotel </Text>
<Text style={styles.thinHeaderText}>Maids</Text>
</Text>
</View>
<Text style={styles.loginThinText}>Log In</Text>
<CardView
cardElevation={3}
cardMaxElevation={4}
cornerRadius={15}
style={{
marginTop: 1,
width: 322,
height: 104,
alignSelf: 'center',
}}>
<View style={styles.textAreaLogin}>
{this.state.result ? <View></View> : <View>
<TextInput
keyboardType="email-address"
style={styles.textAreaEmail}
placeholderTextColor="#C8C8C8"
placeholder="Username-HK"
onChange={this.handleEmail}
/>
<TextInput
secureTextEntry={true}
style={styles.textAreaPassword}
placeholderTextColor="#C8C8C8"
placeholder="Password-HK"
onChange={this.handlePassword}
/>
<Button onPress={() => {this._userLogin(); this.props.navigation.navigate(IntroScreen);}}>LOGIN</Button>
</View>}
</View>
</CardView>
Assuming you're connected to a backend that's sending you the appropriate responses
function LoginScreen(props) {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
const onChangeEmail = (text) => setEmail(text);
const onChangePassword = (text) => setPassword(text);
const handleSubmit = () => {
fetch('https://reactnative.dev/movies.json')
.then((response) => response.json())
.then((json) => {
// You can navigate here as well
navigation.navigate('SomeScreen');
return json.movies;
})
.catch((error) => {
console.error(error);
});
};
return (
<View>
<TextInput value={email} onChangeText={onChangeEmail} />
<TextInput
value={password}
onChangeText={onChangePassword}
autoCompleteType="password"
textContentType="password"
secureTextEntry
/>
<TouchableOpacity onPress={handleSubmit}>
<Text>Log In</Text>
</TouchableOpacity>
</View>
);
}

Validate e-mail address when pressing a button

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'.

null is not object: ( evaluating this.state.email)

I am creating login form. But having some issue about that problem. this is what I have done so far.
loginUser = async(email, password) => {
if(email != '' && password != ''){
try {
let user = await auth.signInWithEmailAndPassword(email,password);
console.log(user);
} catch (error) {
console.log(error);
}
} else {
alert("some error")
}
}
and inside the render:
render(){
return(
<View>
<Text>Email</Text>
<TextInput
onChangeText={(text) => this.setState({email: text})}
value={this.state.email}
/>
<Text>Password</Text>
<TextInput
onChangeText={(text) => this.setState({password: text})}
value={this.state.password}
secureTextEntry={true}
/>
<TouchableHighlight style={{backgroundColor: "green"}}
onPress={() => this.loginUser(this.state.email, this.state.password)}>
<Text>Login!</Text>
</TouchableHighlight>
<TouchableHighlight style={{backgroundColor: "green"}}
onPress={()=> this.loginWithFacebook()}>
<Text>Login with Facebook!</Text>
</TouchableHighlight>
</View>
);
}
}
What am I doing wrong here? Because loginUser function not working properly... Thank you for helping!
Add, this code after the decleration of your class:
state = {
email: '',
password: '',
}
The code is failing because you're trying to get an obj's key which does not exist. You need to creat it first.
I can't see the constructor in the code. Try to add this.
constructor(props){
super(props);
this.state = {
}
}

How to pass message from children Input to parent Chat in react-native-gifted-chat

I got a chat based on react-native-gifted-chat, with a children InputBox component that has the layout for the input and some buttons plus the Send button.
I'm passing 2 functions to handle onSend and the camera, but I was wondering how to send the text that I'm writing on the InputBox to parent that contains the GiftedChat.
GiftedChat handles an array of messages, but how do I create a new text message based on the input and the button onPress ?
Here's my current code:
On Parent
constructor(props) {
super(props)
this.handleCameraPress = this.handleCameraPress.bind(this);
this.onSend = this.onSend.bind(this);
this.state = {
chatData: {},
messages: []
}
}
onSend(messages = []) {
alert('sending message');
this.setState(previousState => ({
messages: GiftedChat.append(previousState.messages, messages),
}))
}
handleCameraPress() {
alert('camera tapped');
}
renderInputToolbar(props) {
return ( <InputBox
{...props}
messages={ this.messages }
onSend={ this.onSend }
handleCameraPress={ this.handleCameraPress }
containerStyle={ styles.inputToolbarStyle }
/>);
}
This is how the GiftedChat looks like:
<GiftedChat
style={{ zIndex: 1 }}
messages={this.state.messages}
bottomOffset={Platform.OS === "ios" ? 335 : 0}
maxComposerHeight={150}
isAnimated={true}
user={{ _id: 1 }}
renderInputToolbar={ this.renderInputToolbar.bind(this) }
/>
On Children
render() {
return (
<View style={ styles.container }>
<TouchableOpacity
activeOpacity={0.6}
style={styles.cameraButton}
onPress={ this.props.handleCameraPress }>
<Icon name='md-camera' style={ styles.cameraIcon } />
</TouchableOpacity>
<TextInput
style={ styles.textInput }
placeholder={i18n.t('chatInputPlaceholder')}
returnKeyType={'send'}
// onChangeText={ message => this.setState({ message })}
// value={this.props.message}
blurOnSubmit={false}
ref={'chatInputRef'}
/>
<Button
onPress={ this.props.onSend }
style={ styles.sendButton}>
<Icon name='md-send' style={ styles.sendIcon } />
</Button>
</View>
);
}
I have to I guess pass a this.props.message to this.props.onSend? And then merge it to parent's messages?
You have to create a state variable , which will be your current Message , and then in Gifted chat , you implement :
onInputTextChanged={text => {this.setState({typingMessage: text});}}
So now your "this.state.typingMessage" , will always have the value that you are writing in your InputToolbar
If you have a custom render you can access to Input Toolbar value like this with "props.text" :
renderSend(props) {
return (
<TouchableOpacity onPress={() => props.onSend({
_id: 10,
text: props.text,
createdAt: new Date(),
user: {
_id: 1,
name: 'Mike',
},
})}>
</TouchableOpacity>
);
}

react native navigation via a button in a modal

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");
});