I want to copy value inside textview by clicking to icon. This is what I've done so far:
render() {
return (
<View style={{marginTop: 50, marginLeft: 50}}>
<View>
<Text>Логин:</Text>
<Text ref='myText'>45645546654</Text>
</View>
<TouchableOpacity onPress={() => Clipboard.setString(this.refs.myText.props.children)}>
<View>
<MaterialIcons
name='content-copy'
size={21}
/>
</View>
</TouchableOpacity>
</View>
);
}
Workspace: https://snack.expo.io/#jasurkurbanov/updated2
It is somewhat working on snack. But what when I am running it on my phone I am getting error.
Undefinied is not an object ('evaluating '_this.refs.myText.props.children')
You should defined your refs variable on constructor().
for example:
constructor() {
...
this.textViewRefs = React.createRef();
...
}
render() {
return (
...
<Text ref={this.textViewRefs}>45645546654</Text>
...
)
}
look this https://reactjs.org/docs/forwarding-refs.html for further information
Related
I'm new at react native.I have a problem that i've been dealing for a few days.I want to show my data with map.Can you guys show me where i did wrong?
(I think i made mistake in the results inside scrollview)
class Movie extends Component{
state= {
apiurl:'http://www.omdbapi.com/.............................',
s:'',
results: [],
selected:{}
}
searchFunc(s) {
this.setState({s: s})
axios(this.state.apiurl+ "&s="+s).then(response =>
this.setState({results: response.data.Search[0]}));
console.log(this.state.results)
}
render() {
return(
<View style={{flex:1,backgroundColor:'#356292'}}>
<View
style={styles.sectionContainer}>
<View style={styles.section}>
<TextInput style={styles.section2}
onChangeText = {(s) => this.searchFunc({s})}
value={this.state.s}
placeholder="Movies,Series.."
>
</TextInput>
<TouchableOpacity
style={{justifyContent: 'center', alignItems: 'center'}}
onPress={() => this.searchFunc()}>
<Image
source ={require('../img/seach.png')}
style={{width:width*0.05,height:height*0.03}}
>
</Image>
</TouchableOpacity>
</View>
</View>
<ScrollView style={styles.scroll}>
{this.state.results.map(results=>(
<View key={this.state.results.imdbID}
style={styles.scroll2}>
<Image source={{uri: this.state.results}}
style={{width:width*0.3, height:height*0.4}}>
</Image>
<Text style={styles.heading}>
{this.state.results.Title}
</Text>
</View>
))}
</ScrollView>
</View>
);
}
From the comments from your original post, i'm guessing response.data.Search[0] is also an array. If so your results state update is okay. Otherwise you should set the results state to response.data.Search.
Other problem I noticed in your code is in the map function, you are mapping the array with each item refering to the result variable, but in your jsx, you are trying to access the results state variable. It should be
<ScrollView style={styles.scroll}>
{
this.state.results.map(result => (
<View
key={result.imdbID}
style={styles.scroll2}
>
<Image
source={{uri: result.image}} // use correct key from result object
style={{width:width*0.3, height:height*0.4}}
/>
<Text style={styles.heading}>{result.Title}</Text>
</View>
))
}
</ScrollView>
Also in your Textinput onChangeText callback function, you dont have to pass that value as an object. You can change it to
<TextInput
style={styles.section2}
onChangeText={(s) => this.searchFunc(s)}
value={this.state.s}
placeholder="Movies,Series.."
/>
I quess you are supposed to pass Search to the state and not the Search[0], which is the object and not map, the reason map function is not working on it.
axios(this.state.apiurl+ "&s="+s).then(response =>
this.setState({results: response.data.Search}));
console.log(this.state.results)
Coincidently, I have created an app using same movie API, you can find it here: Github Repo, Movie App
I'm creating a shopping cart in react native with redux but I'm getting an error
undefined is not an object (evaluating 'this.props.items.length')
I'm following a tutorial of react redux someone suggest me to follow that tutorial to make cart,
but I'm getting that error
can someone please tell me what's going on.., below is my code
class Cart extends Component {
render() {
let addedItems = this.props.items.length ? (
<FlatList
data={this.props.items}
key={(items) => items.id.toString()}
numColumns={2}
renderItem={({ item }) => (
<View>
<Image style={styles.image} source={item.image} />
<View style={styles.detailContainer}>
<Text style={styles.title}>{item.title}</Text>
<Text style={styles.subTitle} numberOfLines={1}>
Quantity: {item.quantity}
</Text>
<Text style={styles.price}>Rs {item.price}</Text>
</View>
<TouchableOpacity>
<View style={styles.buy}>
<Text>Remove</Text>
</View>
</TouchableOpacity>
</View>
)}
/>
) : (
<Text>Nothing</Text>
);
return (
<View>
<View>
<Text>You Have Ordered:</Text>
</View>
<View>{addedItems}</View>
</View>
);
}
}
const mapStateToProps = (state) => {
return {
items: state.addedItems,
};
};
try like this
let addedItems = this.props.items && this.props.items.length ? (
I am trying to make cards clickable and expandable, but when updating state, it occurs in all the cards . I just want to make the state change in only one card (the one on which the event occurred , in this case, a click event).
However, the state gets updated for every other cards. Currently this does work on one item but it needs to work on others too.
export default class TransactionCards extends React.Component {
constructor(props) {
super(props);
this.state = {
isHidden: true
};
}
toggleHidden() {
this.setState({
isHidden: !this.state.isHidden
});
}
renderCards() {
return this.props.data.map((card, index) => (
<View key={card.id}>
<View style={styles.dateContainer}>
<Text style={styles.dateText}>{card.time}</Text>
</View>
<Card>
<TouchableWithoutFeedback onPress={this.toggleHidden.bind(this)}>
<View>
<View>
<View style={styles.transactionContainer}>
<Image
style={styles.countryImage}
source={require("../../assets/images/us-country-icon.png")}
/>
<Text style={styles.transactionTitle}>{card.title}</Text>
<Text style={styles.transactionAmount}>{card.cost}</Text>
<Icon
name={card.transactionType == "debit" ? "log-out" : "log-in"}
type="feather"
color={card.transactionType == "debit" ? "red" : "green"}
size={18}
iconStyle={styles.transactionIcon}
/>
</View>
<View>
<Text style={styles.transactionBankDetails}>{card.bankDetails}</Text>
</View>
</View>
{/* Setting visiblity condition */}
{!this.state.isHidden && (
<View>
<Divider style={styles.CardItemDivider} />
<View display="flex" flexDirection="row" justifyContent="space-between">
<View>
<Text style={styles.transactionBankDetails}>
{card.transactionCategory}
</Text>
<Text style={styles.transactionBankDetails}>{card.accountName}</Text>
</View>
<View>
<Icon name="bell" type="feather" iconStyle={styles.transactionIcon} />
</View>
</View>
</View>
)}
</View>
</TouchableWithoutFeedback>
</Card>
</View>
));
}
render() {
return <ScrollView showsVerticalScrollIndicator={false}>{this.renderCards()}</ScrollView>;
}
}
Create a new component for card and pass required params
Do the toggleHidden function inside the Card component
then inside the file it should look like
<Card {SetYourPassedParams} />
......
You have two items connected to the same state value on the same state. If you want to separate the behaviours you have to separate the values too.
So, I'm using 2 files: The components.js where I define all parts and molds I'll use in my app, and the App.js, which has the logic and major stuff.
To sum things up, I've defined a Card class in the components.js that has a button at the end. Here is the code for the Card:
export class Card extends Component {
render() {
return (
<View style={{height: 700}}>
<View style={{flex: 8, backgroundColor: 'white', borderRadius: 20}} >
<Image source={{uri: this.props.pic}} style={styles.img}/>
<Text style={{flex: 1, fontWeight: 'bold',fontSize: 30, paddingTop: 10}}> {this.props.nome}</Text>
<Text style={{flex: 1, fontSize: 20}}> {this.props.descricao}</Text>
<TouchableHighlight style={{flex: 1}} onPress={() => ???????} underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>Mais informações</Text>
</View>
</TouchableHighlight>
</View>
</View>
);
}
}
And I use it in the App.js as follows:
import {Card} from "./components.js";
class App extends Component {
render() {
return (
<View style={{flex: 1, backgroundColor:"#e6e6e1"}}>
<ScrollView>
{this.state.locations.map((pico, key) =>
<Card key={key} pic={pico.img[0]} nome= {pico.nome_do_pico} descricao={pico.how}/>
)}
</ScrollView>
</View>
);
}
}
(I've omitted the parts where it gets the info from the server and puts into the locations array)
What I need is for the button to navigate to another screen, called "Details", and I have tried a few things on the onPress but nothing has worked so far. The documentation for reactnavigation uses this.state.navigation.navigate("Details") as example, but since the Card is in another file it can't access the this.state.navigation. Any ideas?
Try if you can solve the problem by modifying the following part of your code:
in app.js
<Card key={key} pic={pico.img[0]} nome= {pico.nome_do_pico} descricao={pico.how} navigation={navigation}/>
in components.js:
<TouchableHighlight style={{flex: 1}} onPress={() => navigation.navigate('Details', {YourParameters: xx } } underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>Mais informações</Text>
</View>
</TouchableHighlight>
I have a View that contains a button - onPress it opens a modal showing a list of contacts.
onPress of any of those contacts (pickContact function) I would like to dynamically add a new View to _renderAddFriendTile (above button).
Also ideally, the 'Add' icon next each contact name (in the modal) should update ('Remove' icon) whether or not they are present in _renderAddFriendTile View.
What would be the best way to do it?
[UPDATED code]
import React, {Component} from 'react'
import {
Text,
View,
ListView,
ScrollView,
StyleSheet,
Image,
TouchableHighlight,
TextInput,
Modal,
} from 'react-native'
const friends = new ListView.DataSource({
rowHasChanged: (r1, r2) => r1 !== r2
}).cloneWithRows([
{
id: 1,
firstname: 'name01',
surname: 'surname01',
image: require('../images/friends/avatar-friend-01.png')
},
{
id: 2,
firstname: 'name02',
surname: 'surname02',
image: require('../images/friends/avatar-friend-02.png')
},
{
id: 3,
firstname: 'name03',
surname: 'surname03',
image: require('../images/friends/avatar-friend-03.png')
},
{
id: 4,
firstname: 'name04',
surname: 'surname04',
image: require('../images/friends/avatar-friend-04.png')
},
])
class AppView extends Component {
state = {
isModalVisible: false,
contactPicked: [],
isFriendAdded: false,
}
setModalVisible = visible => {
this.setState({isModalVisible: visible})
}
pickContact = (friend) => {
if(this.state.contactPicked.indexOf(friend) < 0){
this.setState({
contactPicked: [ ...this.state.contactPicked, friend ],
})
}
if(this.state.contactPicked.indexOf(friend) >= 0){
this.setState({isFriendAdded: true})
}
}
_renderAddFriendTile = () => {
return(
<View style={{flex: 1}}>
<View style={[styles.step, styles.stepAddFriend]}>
<TouchableHighlight style={styles.addFriendButtonContainer} onPress={() => {this.setModalVisible(true)}}>
<View style={styles.addFriendButton}>
<Text style={styles.addFriendButtonText}>Add a friend</Text>
</View>
</TouchableHighlight>
</View>
</View>
)
}
render(){
return (
<ScrollView style={styles.container}>
<Modal
animationType={'fade'}
transparent={true}
visible={this.state.isModalVisible}
>
<View style={styles.addFriendModalContainer}>
<View style={styles.addFriendModal}>
<TouchableHighlight onPress={() => {this.setModalVisible(false)}}>
<View>
<Text style={{textAlign:'right'}}>Close</Text>
</View>
</TouchableHighlight>
<ListView
dataSource={friends}
renderRow={(friend) => {
return (
<TouchableHighlight onPress={() => {this.pickContact()}}>
<View style={[styles.row, styles.friendRow]}>
<Image source={friend.image} style={styles.friendIcon}></Image>
<Text style={styles.name}>{friend.firstname} </Text>
<Text style={styles.name}>{friend.surname}</Text>
<View style={styles.pickContainer}>
<View style={styles.pickWrapper}>
<View style={this.state.isFriendAdded ? [styles.buttonActive,styles.buttonSmall]: [styles.buttonInactive,styles.buttonSmall]}>
<Image source={this.state.isFriendAdded ? require('../images/button-active.png'): require('../images/button-inactive.png')} style={styles.buttonIcon}></Image>
</View>
</View>
</View>
</View>
</TouchableHighlight>
)
}}
/>
</View>
</View>
</Modal>
{this._renderAddFriendTile()}
</ScrollView>
)
}
}
export default AppView
Since you need to update something dynamically, that's a clear indication you need to make use of local state for modelling that data. (Setting aside you are not using a state library management like Redux)
state = {
isModalVisible: false,
contactPicked: null,
}
Your pickContact function needs the friend data from the listView, so you need to call it with the row selected:
<TouchableHighlight onPress={() => {this.pickContact(friend)}}>
Then inside your pickContact function, update your UI with the new contactsPicked data model
pickContact = (friend) => {
this.setState({
contactPicked: friend,
});
}
That will make your component re-render and you can place some logic inside _renderAddFriendTile to render some extra UI (Views, Texts..) given the existence of value on this.state.contactPicked You could use something along these lines:
_renderAddFriendTile = () => {
return(
<View style={{flex: 1}}>
{this.state.contactPicked && (
<View>
<Text>{contactPicked.firstName}<Text>
</View>
)}
<View style={[styles.step, styles.stepAddFriend]}>
<TouchableHighlight style={styles.addFriendButtonContainer} onPress={() => {this.setModalVisible(true)}}>
<View style={styles.addFriendButton}>
<Text style={styles.addFriendButtonText}>Add a friend</Text>
</View>
</TouchableHighlight>
</View>
</View>
)
}
Notice you now hold in state the firstName of the contact picked, so point number 2 should be easy to address. Just inside renderRow of ListView, render a different Icon if friend.firstname === this.state.contactPicked.firstname
Note: Don't rely on firstname for this sort of check since you can have repeated ones and that would fail. The best solution is to provide to your list model an unique id property per contact and use that id property for checking the logic above.
Side Notes
The part {this.state.contactPicked && (<View><Text>Some text</Text></View)} is using conditional rendering. The && acts as an if so if this.state.contactPicked is truthy, it will render the view, otherwise it will render nothing (falsy and null values are interpreted by react as "nothing to render").
Of course, if you want to render more than one item dynamically, your state model should be an array instead, i.e contactsPicked, being empty initially. Every time you pick a contact you'll add a new contact object to the array. Then inside _renderAddFriendTile you can use map to dynamically render multiple components. I think you won't need a ListView, unless you wanna have a separate scrollable list.
_renderAddFriendTile = () => {
return(
<View style={{flex: 1}}>
{this.state.contactsPicked.length && (
<View>
{this.state.contactsPicked.map(contact => (
<Text>{contact.firstName}</Text>
)}
</View>
)}
<View style={[styles.step, styles.stepAddFriend]}>
<TouchableHighlight style={styles.addFriendButtonContainer} onPress={() => {this.setModalVisible(true)}}>
<View style={styles.addFriendButton}>
<Text style={styles.addFriendButtonText}>Add a friend</Text>
</View>
</TouchableHighlight>
</View>
</View>
)
}