constructor(props) {
super(props);
this.state = {
message: "..",
};
}
render() {
return (
<View style={styles.container}>
<View style={styles.textInput}>
<TextInput onChangeText={(message) => this.setState({message})} placeholder="Enter your message..." style={styles.text}/>
<TouchableHighlight style={styles.button} onPress={this.submit}>
<Text ref="message" onPress={this.submit}>Submit</Text>
</TouchableHighlight>
</View>
</View>
)
}
loadData(){
AlertIOS.alert(this.state.message);
}
componentDidMount(){
this.loadData()
}
submit(){
AlertIOS.alert(this.state.message);
}
When loadData is first called, it shows the current value of message: ".."
When my submit function is called, it throws an error: undefined is not an object (evaluating 'this.state.message')
I'm assuming that it is my onChangeText attribute that's setting message to undefined, but I'm not sure why.
The problem is that this isn't bound correctly in submit()
In your constructor, try adding the line:
this.submit = this.submit.bind(this);
Related
I have a class that I want the text input inside it to focus on the parent being selected.
class ListItem extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
editable: this.props.item.editable,
value: this.props.item.value,
heading: this.props.item.heading,
item: this.props.item.item,
}
}
_onPress = () => {
this.setState({ editable: true});
this.props.onPressItem(this.props.index, this.props, this.state);
}
_onSearchTextChanged = (event) => {
this.setState({ value: event.nativeEvent.text });
};
_handleSaveEvent = (e) => {
this.setState({ editable: false });
alert('works');
//Add in saving item
}
render() {
var editable = this.state.editable;
var heading = this.state.heading;
var value = this.state.value;
return (
<TouchableHighlight onPress={this._onPress} underlayColor='#dddddd'>
<View>
<View style={styles.rowContainer}>
<View style={styles.textContainer}>
<Text style={styles.title}>{heading}: </Text>
{this.state.editable?
<TextInput
style={styles.searchInput}
value={value.toString()}
onChange={this._onSearchTextChanged}
keyboardType="default"
returnKeyType="done"
onSubmitEditing={this._handleSaveEvent}/>
:
<Text style={styles.price}>{value}</Text>
}
{}
</View>
</View>
<View style={styles.separator}/>
</View>
</TouchableHighlight>
);
}
}
Ive tried adding
autoFocus={true}
Ive also tried adding
ref={this.props.index}
But when I try to focus that it tells me its not defined (this.refs[this.props.index].focus();)
I would like it to be focused when the 'editable' state is enabled, I am not sure why this seems so hard. My background is more in C#, Angular 2+ etc so maybe its just how react is structured is throwing me
on the onPress event of TouchableHighlight setState editable: true and set autoFocus={this.state.editable} in TextInput..it will work
<TextInput
style={styles.searchInput}
value={value.toString()}
onChange={this._onSearchTextChanged}
keyboardType="default"
autoFocus={this.state.editable}
returnKeyType="done"
onSubmitEditing={this._handleSaveEvent}
/>
You can try this. Provide ref as a function in <TextInput /> like this:
<TextInput
ref ={ref => this.inputText = ref}
style={styles.searchInput}
keyboardType="default"
placeholder="Type anything"
returnKeyType="done"/>
And now on <Button />onPress, focus the <TextInput /> like this:
<TouchableHighlight onPress={() => this.inputText.focus()}>
<Text>Click</Text>
</TouchableHightlight>
This should work. Let me know if there is any problem.
When i press the <TouchableOpacity> Button, i want the value 'abc' to be appended to the array selectedTags and then <Text> {this.list()} </Text> will print out my array.
But now when i press the Button, nothing display out.
Can anybody know what is the problem with my code?
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
selectedTags: []
}
}
list() {
return this.state.selectedTags.map(function(tags, i){
return(
<View key={i}>
<Text>{tags.name}</Text>
</View>
);
});
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => this.state.selectedTags.push('abc')} key = {1} style={styles.buttonContainer}>
<Text style={styles.buttonText}> Button </Text>
</TouchableOpacity>
<Text> {this.list()} </Text>
</View>
);
}
}
This is because you never call setState, which would trigger re-render of your component.
instead of using:
onPress={() => this.state.selectedTags.push('abc')}
try:
onPress={() => this.setState({selectedTags: this.state.selectedTags.concat('abc')})}
The function list only push data in array but does not rerender the view, todo so you have to use setState or forceUpdate.
You can implement the onpress function like this.
onPress = () =>{
this.state.selectedTags.push("abc");
this.setState({selectedTags : this.state.selectedTags});
}
on clicking the text, i get an error saying "undefined is not an object (evaluating '_this2.categoryClicked.bind')"
I think the error is "onPress={()=>this.categoryClicked.bind(this)}" there must be a different way to call the categoryClicked function when the button is clicked. What is wrong in my code ?
class CategoriesView extends React.Component {
constructor(props){
super(props)
}
categoryClicked(){
this.props.categoryPressed(this.props.Category);
}
renderSubCategory(){
return(
this.props.Category.sub_category.map(function(subCategory, i){
return(
<View style={styles.abcd}>
<TouchableHighlight onPress={()=>this.categoryClicked.bind(this)}>
<Text>{subCategory.title}</Text>
</TouchableHighlight>
</View>
)
})
)
}
render(){
return(
<View style={{flex:1}}>
<View style={styles.avf}>
<Text>{this.props.Category.heading}</Text>
</View>
<View style={styles.ddd}>
{this.renderSubCategory()}
</View>
</View>
)
}
}
I believe what you want to do is onPress={this.categoryClicked.bind(this)} instead of an arrow function. .bind(this) returns a function with the context correctly binded to this, therefore, it does not get invoked.
Also, I suggest putting the binding in constructor, as you don't want the binding to happen every time the component re-renders.
e.g.
constructor(props) {
super(props);
this.categoryClicked = this.categoryClicked.bind(this);
}
Then just use onPress={this.categoryClicked}
If you want to pass down sub-category, you can do
constructor(props) {
super(props);
this.subcategoryClicked = props.Category.sub_categories.map(sub_category => this.categoryClicked.bind(this, sub_category));
}
then use like this in render:
this.props.Category.sub_category.map(function(subCategory, i) {
<View style={styles.abcd}>
<TouchableHighlight onPress={this.subcategoryClicked[i]}>
<Text>{subCategory.title}</Text>
</TouchableHighlight>
</View>
P.S, I am not sure if this is a good pattern to follow. Stick to this.categoryClicked(bind, subcategory) if you are not comfortable with doing this. This is one of those things that I am not sure if the optimization is worth it.
this in onPress={()=>this.categoryClicked.bind(this)}> points to sub_category.map function. It should instead point to the class. Can be done this way instead
return (
this.props.Category.sub_category.map((subCategory, i) => { // <--- this way context is preserved
// other lines
onPress={()=>this.categoryClicked.bind(this, subCategory)}>
// other lines
})
);
in categoryClicked method should be accessible
categoryClicked(category){
this.props.categoryPressed(category);
}
Why im receiving this error, but I already add the Constructor at my class.
the error just appear when I execute the android-run start and im getting this error.
null is not an object (evaluating 'this.state.noteArray')
export default class testPoject extends Component {
constructor(props) {
super(props);
this.state = {noteArray: []}
}
render() {
let notes = this.state.noteArray.map((val, key) => {
return <Note key={key} keyval={key} val={val} deleteMethod={ () => this.deleteNote(key)} />
});
return (
<View style={styles.container}>
<View style={styles.header}>
<Text style={styles.headerText}>TODO LIST </Text>
</View>
<ScrollView style={styles.scrollConainer}>
</ScrollView>
<View style={styles.footer}>
<TouchableOpacity style={styles.addButton}>
<Text style={styles.addButtonText}>
+
</Text>
</TouchableOpacity>
<TextInput style={styles.noteInputText}
placeholder="> Note"
placeholderTextColor="#FFF"
underlineColorAndroid="transparent"
numberOfLines = {3}
/>
</View>
</View>
);
}
}
Well,
Do one thing and it will work. Add a constructor and in that constructor declare the state.
constructor() {
super();
this.state = {
noteArray:[{ 'note': 'Bingo'}],
noteText:'',
}
}
Why are you passing a val and key to your map function? noteArray is an array, not an object with key, value pairs. Ether write noteArray as noteArray: {} or change your map function to work with a single element.
I'm trying to add a TouchableHighlight component to a row in a list view.
The onPress function is throwing an undefined error in the code below. It works outside of the list view.
I suspect this is because I'm losing context of this but unsure how to fix. Anyone able to help?
export default class ConversationsList extends Component {
constructor(props) {
super(props);
this._handleChangePage = this._handleChangePage.bind(this);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows(Coversations.chats)
};
}
_handleChangePage(chat) {
this.props.navigator.push({
title: 'foo',
component: Chat,
passProps: {
chat: chat
}
});
}
renderRow(chat){
return (
<View>
<TouchableHighlight onPress={ () => this._handleChangePage.bind(this, chat) }>
<View>
/* more content removed */
</View>
</TouchableHighlight>
</View>
);
}
render() {
return (
<View style={styles.container}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
/>
</View>
);
}
}
I also suspect that I shouldn't really be doing things this way, that my component should be structured differently, so it is passed the press handler as a prop perhaps. any advice appreciated.
You can declare another variable globally like
var _this;
initialise it in render method
render:function(){
_this = this;
return(
...
)
}
and use it in your touchableHightlight
renderRow(chat){
return (
<View>
<TouchableHighlight onPress={ () => _this._handleChangePage(chat) }>
<View>
/* more content removed */
</View>
</TouchableHighlight>
</View>
);
}
I suggest to read this helpful article
export default class ConversationsList extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows(Coversations.chats)
};
}
_handleChangePage = () => {
this.props.navigator.push({
title: 'foo',
component: Chat,
passProps: {
chat: this
}
});
}
renderRow = (chat) => {
return (
<View>
<TouchableHighlight onPress={ this._handleChangePage }>
<View>
/* more content removed */
</View>
</TouchableHighlight>
</View>
);
}
render() {
return (
<View style={styles.container}>
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderRow}
/>
</View>
);
}
}