Give styling to placeholder in TextInput in React Native - reactjs

So I've a TextInput and the placeholder has a styling.
For this, I place a Text with position: 'absolute' and zIndex: 1 before the TextInput
activeField(){
this.setState({active: true})
}
render(){
return(
{ !this.state.active &&
<Text style={STYLES.textInputPlaceholder}>
{this.props.placeholder}
</Text>
}
<TextInput
style={STYLES.textInputField}
onFocus={() => this.activeField()}
/>
)
}
Now, the Text component which has the placeholder, when I press on it, I should be able press at the placeholder, which is the Text component here and be able to call the onFocus method of TextInput
I hope I'm able to clearly explain my problem.

We would not be able to trigger the onFocus event-listener of the TextInput by clicking on the Text. However, we can make it appear like that is happening with some clever CSS.
Make sure that the background of the TextInput is transparent or
at least matching that of the Text. That way Text is still visible when we give position: absolute.
Then we
We need the zIndex of the Text to be lower than the zIndex of the
TextInput. That way TextInput is actually in front of Text. So while it looks like you're clicking on the placeholder, you are actually just clicking on the TextInput and that will trigger the onFocus event.
Try this:
import React, { Component } from "react";
import { StyleSheet, Text, TextInput } from "react-native";
class App extends Component {
state = {
active: false,
text: ""
};
activeField = () => {
console.log("focused");
this.setState({
active: true
});
};
handleOnBlur = () => {
if (this.state.text.length === 0) {
this.setState({
active: false
});
}
};
render() {
return (
<div>
{!this.state.active && (
<Text style={STYLES.textInputPlaceholder}>
{this.props.placeholder}
</Text>
)}
<TextInput
style={STYLES.textInputField}
onChangeText={text => this.setState({ text })}
onFocus={this.activeField}
value={this.state.text}
onBlur={this.handleOnBlur}
/>
</div>
);
}
}
const STYLES = StyleSheet.create({
app: {
marginHorizontal: "auto"
},
textInputField: {
zIndex: 1,
width: 300,
borderColor: "black",
borderWidth: 1
},
textInputPlaceholder: {
zIndex: -1,
color: "blue",
position: "absolute",
backgroundColor: "transparent"
}
});
export default App;
App.defaultProps = {
placeholder: "Hello"
};
Here's the working sandbox: https://codesandbox.io/s/react-native-on23p

Related

Problem with React-Native Output View Component

this code does not Display the list(places) which places i added to it using add_Button.
Generally working of this code is this that i input text into this react-native app using TextInput Component, after this i press the Add Button to add this text into a list(places), after this it automatically display all the entered text.
e.g if i enter the place by 1st time it only display that text, but if i enter another text it displays that text as well as the first one.
import React, {Component} from 'react';
import {View, TextInput, StyleSheet, Button, Text} from 'react-native';
export default class App extends Component
{
state = {
placeName: "",
places: []
};
placeNameChangeHandler=(val)=>
{
this.setState({
InputValue: val
})
};
placeSubmitHandler = () =>{
if(this.state.placeName.trim() === "")
{
return;
}
this.setState(prevState => {
return {
places : prevState.places.concat(prevState.placeName)
};
});
};
render()
{
const placesOutput = this.state.places.map((place, i) =>(
<Text key={i} backgroundColor = 'black' >{place}</Text>
));
return(
<View style={Styles.container}>
<View style = {Styles.inputContainer}>
<TextInput
placeholder = "Search place?"
value = {this.setState.placeName}
onChangeText = {this.placeNameChangeHandler}
style={Styles.placeInput}
/>
<Button
title='Add'
style = {Styles.placeButton}
onPress = {this.placeSubmitHandler}
/>
</View>
<View>{placesOutput}</View>
</View>
);
}
}
const Styles = StyleSheet.create({
container: {
flex:1,
padding: 10,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'flex-start'
},
inputContainer: {
width: "100%",
flexDirection : 'row',
justifyContent: 'space-between',
alignItems:'center'
},
placeInput: {
width: "70%"
},
placeButton: {
width: "30%"
}
})
This is not 100% correct, but I'll write it down.
This seems to happen because of setState.
First.
Change to value = {this.setState.placeName} to value = {this.state.placeName}
<TextInput
placeholder = "Search place?"
value = {this.state.placeName}
onChangeText = {this.placeNameChangeHandler}
style={Styles.placeInput}
/>
Next.
Change setState in placeNameChangeHandler
placeNameChangeHandler=(val)=>{
this.setState({
placeName: val
})
};
And
Add Initializing placeName
placeSubmitHandler=()=>{
if(this.state.placeName.trim() === "")
{
return;
}
this.setState(prevState => {
return {
places : prevState.places.concat(prevState.placeName),
placeName : ""
};
});
};
Sorry for my stupid English.
I hope you understand :)

displaying input field after clicking button react-native

I am learning react-native and I wanted to do something simple where the user can enter some information like name or something and then when he/she clicks the button, it will display on the screen hello so and so. I have my onChangeText setting the state to what the user passes but it doesn't update. Also clicking the button doesn't show anything. I will paste my code down below. Any help or suggestions.
app.js
import { Button } from "react-native";
import React, { Component } from "react";
import {
Platform,
StyleSheet,
Text,
View,
Alert,
TextInput
} from "react-native";
const instructions = Platform.select({
ios: "Press Cmd+R to reload,\n" + "Cmd+D or shake for dev menu",
android:
"Double tap R on your keyboard to reload,\n" +
"Shake or press menu button for dev menu"
});
type Props = {};
export default class App extends Component<Props> {
constructor() {
super();
this.state = {
text: "Hello "
};
this.handleChange = this.handleChange.bind(this);
}
handleChange = typedText => {
this.setState({
text: typedText
});
console.log(text);
};
render() {
return (
<View style={styles.container}>
<Text>{this.state.value}</Text>
<Button onPress={this.handleChange} title="Click Me " />
<TextInput
placeholder="Type your name here"
onChangeText={typedText => {
this.setState({
text: typedText
});
}}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#F5FCFF"
},
welcome: {
fontSize: 20,
textAlign: "center",
margin: 10
},
instructions: {
textAlign: "center",
color: "#333333",
marginBottom: 5
}
});
You are setting the state in handlechange (the onpress function) as well which is not required at all. There wont be an argument of text in your onPress you are resetting the text value in the state. And the text inside the handleChange will be undefined as you dont set it anywhere.
the code should be something like below.
export default class App extends Component {
constructor() {
super();
this.state = {
text: "Hello "
};
this.handleChange = this.handleChange.bind(this);
}
onPress = () => {
console.log("current ==> ", this.state);
alert(this.state.text);
};
handleChange = typedText => {
console.log("update => ", typedText);
this.setState(
{
text: typedText
}
);
};
render() {
return (
<View style={styles.container}>
<Text>{this.state.value}</Text>
<Button onPress={this.onPress} title="Click Me " />
<TextInput
placeholder="Type your name here"
onChangeText={this.handleChange}
/>
</View>
);
}
}
The issue was, on Press of button we are calling a function which expects a 'text' but in actual it is an event.
Check this codesandbox

How can I change the color of an icon without re-render (TextField loosing focus)

I am using the package called react-native-phone-input, and when the phone number is changed it runs the function this.updateInfo() which updates the state. In my code, the icon color is dependent on the state and changes based on whether the phone number is valid. This works, however, when the state is changed, the screen re-renders and the keyboard is dismissed since the text field loses focus. Is there another way I can change the icons color? Or is there a way that I can keep the focus on the text field?
This is what I am referring to:
import React, { Component } from 'react';
import { View, Text, StyleSheet, TouchableOpacity, TextInput, Keyboard} from 'react-native';
import { Icon } from 'react-native-elements';
import KeyboardAccessory from 'react-native-sticky-keyboard-accessory';
import PhoneInput from 'react-native-phone-input';
export default class PhoneLogin extends Component {
constructor() {
super();
this.state = {
valid: "",
type: "",
value: "",
iconColor: "#D3D3D3",
};
this.updateInfo = this.updateInfo.bind(this);
}
updateInfo() {
this.setState({
valid: this.phone.isValidNumber(),
type: this.phone.getNumberType(),
value: this.phone.getValue().replace(/[- )(]/g,''),
});
}
render() {
return (
<View style={styles.container}>
<PhoneInput
ref={ref => {
this.phone = ref;
}}
style={{height: 50, borderColor:'#44c0b9', borderBottomWidth:2}}
onChangePhoneNumber={ (phone) => {this.updateInfo()} }
/>
<KeyboardAccessory backgroundColor="#fff">
<View style={{ alignItems: 'flex-end', padding:10 }}>
<Icon
raised
reverse
color={(this.state.valid) ? "#44c0b9" : "#D3D3D3"}
name='arrow-right'
type='font-awesome'
onPress={ Keyboard.dismiss()}
/>
</View>
</KeyboardAccessory>
</View>
);
}
}
let styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
padding: 20,
paddingTop: 60
},
info: {
// width: 200,
borderRadius: 5,
backgroundColor: "#f0f0f0",
padding: 10,
marginTop: 20
},
button: {
marginTop: 20,
padding: 10
}
});
In your onPress of your Icon you need to send an arrow function.
The Icon should be like this
<Icon
raised
reverse
color={(this.state.valid) ? "#44c0b9" : "#D3D3D3"
name='arrow-right'
type='font-awesome'
onPress={() => Keyboard.dismiss()}
/>
The problem was the Keyboard.dismiss() was immediately running every time the component re-rendered thus dismissing your keyboard.
Hope this helps!

Using a button to change the color of text

I'm trying to create a simple React Native app that:
Renders "Hello, [name]!" when a user enters a name (this part works)
Changes the "Hello, [name]!" text color when a button is pressed.
Any ideas as to how I should go about this?
I gave this an initial state of black, but that doesn't even seem to be doing anything.
What I want to happen is to trigger makeRed when the red button is clicked, which will turn the text red. Once I have this working, I'll add more color buttons.
Thank you!
See below for my App.js code. All other files were left in their default state.
import React, { Component } from 'react';
import {
AppRegistry,
Platform,
StyleSheet,
Text,
TextInput,
View,
Button
} from 'react-native';
export default class App extends Component<{}> {
constructor(props) {
super(props);
this.state = {
text: 'World',
color: 'black'
};
}
makeRed = () => {
this.setState({
color: 'red'
});
}
render() {
return (
<View style={styles.container}>
<Text style={[styles.welcome, {color: undefined}]}>
Hello, {this.state.text}!
</Text>
<TextInput
style={styles.instructions}
placeholder="Enter a name here!"
onChangeText={(text) => this.setState({text})}
/>
<Button
title='⬤'
onPress={this.makeRed}
color='red'
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 40,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});
Here's a screenshot of the app for reference:
app screenshot
All you need to do is change this :
style={[styles.welcome, {color: undefined}]}
To
style={[styles.welcome, {color : this.state.color }]}
Please check : WORKING DEMO
color is not referenced as a property of state , in the style of the Text component. Try this as the Text element:
<Text style={{color: this.state.color, ...styles.welcome}}>
Hello, {this.state.text}!
</Text>
And, makeRed needs to be have it's context bound in the constructor, or else this.setState will be undefined. Like this (under super(props)):
this.makeRed = this.makeRed.bind(this)

React-native rendering button but not showing its height

I am trying to render logout button and its rendering it but its not showing height for the button. i am also adding the files which have data for Both button.js and app.js. now the problem is its showind button but the height of the button is 1 dont know why. i copied this code from somewhere and trying to make something out of it. some other place i am easily able to use button width. but not here.
and my common/index.js has all exported files like Button.js and all
getting button in this form.its showing but not with the size
Button.js
import React from 'react';
import { Text, TouchableOpacity } from 'react-native';
const Button = ({ onPress, children }) => {
const { buttonStyle, textStyle } = styles;
return (
<TouchableOpacity onPress={onPress} style={buttonStyle}>
<Text style={textStyle}>
{children}
</Text>
</TouchableOpacity>
);
};
const styles = {
textStyle: {
alignSelf: 'center',
color: '#007aff',
fontSize: 16,
fontWeight: '600',
paddingTop: 10,
paddingBottom: 10
},
buttonStyle: {
flex: 1,
alignSelf: 'stretch',
backgroundColor: '#fff',
borderRadius: 5,
borderWidth: 1,
borderColor: '#007aff',
marginLeft: 5,
marginRight: 5
}
};
export { Button };
App.js
import React, {Component} from 'react';
import { View } from 'react-native';
import firebase from 'firebase';
import { Header, Button, Spinner, Card } from './components/common';
import LoginForm from './components/LoginForm';
class App extends Component {
state = { loggedIn: null };
componentWillMount() {
firebase.initializeApp({
apiKey: '***********************************',
authDomain: '*********************************',
databaseURL: '***********************************',
projectId: '***************************************',
storageBucket: '*************************************',
messagingSenderId: '32810678085'
});
firebase.auth().onAuthStateChanged((user) => {
if(user){
this.setState({ loggedIn: true });
}else {
this.setState({ loggedIn: false });
}
});
}
renderContent(){
switch (this.state.loggedIn){
case true:
return <Button> Log out </Button>
case false:
return <LoginForm />;
default:
return <Spinner size="large" />;
}
}
render() {
return (
<View>
<Header headerText="Authentication" />
{this.renderContent()}
</View>
)
}
}
export default App;
I've had the exact same problem.
First of all, the version of React Native in the tutorial was different to the version that you used judging by the date of the post, this could point to a possible explanation of why the code worked in the tutorial but not in our code, although I can't know.
On the other side, it's not exactly true that the button code works in other
parts of the code.
When you render the login form, the button is enclosed in a CardSection component.
<Card>
...
<CardSection>
{this.renderButton()}
</CardSection>
</Card>
The CardSection component defines the flexDirection of its children as
'row' (horizontal) and the flex property of the Button "flex: 1" expands the width of the button along the horizontal (row) axis of its parent.
So, to make that code work in current versions of react-native, you have two options:
1.- Enclose the logout button in a CardSection:
import { Header, Button, CardSection } from './components/common';
renderContent() {
if (this.state.loggedIn) {
return (
<CardSection>
<Button>Log Out</Button>
</CardSection>
);
}
return <LoginForm />;
}
2.- Enclose the button in a View and give it at least a style property of "flexDirection: row":
renderContent() {
if (this.state.loggedIn) {
return (
<View style={style.containerStyle}>
<Button>Log Out</Button>
</View>
);
}
return <LoginForm />;
}
const style = {
containerStyle: {
flexDirection: 'row',
}
};
Usually you should wrap your TouchableOpacity sections in Views, they respond much better to styling. When learning react-native i often ran into a similar error.
I like to structure my implementation of buttons like so:
//Note i have edited this to tie in with your code
//
//Button.js file
//
//
return (
<View style = {buttonStyle}>
<TouchableOpacity onPress={onPress}>
<Text style={textStyle}>
{children}
</Text>
</TouchableOpacity>
</View>);
EDIT: Now, you should be able to add a height component to the buttonStyle, and then the button should display as you expect :-) Pseudo code:
//Other styling components...
height: 50,
//Other styling components...
Just add this:
marginTop:5
to the buttonStyle object.

Resources