how to disable some touchableopacity in react native - react-native

I display in numbers scrolling app in TouchableOpacity and I want some of the buttons to be disabled and some not how do I do that?
<ScrollView contentContainerStyle={styles.contentContainerStyle}>
{hour.map((item, index) => {
return (
<TouchableOpacity
// delayPressIn={}
disabled={
isDisable
}
style={styles.item}
key={index}
onPress={() => {
setShow(true);
}}>
<Text style={styles.text}> {item}</Text>
</TouchableOpacity>
);
})}
</ScrollView>

Assuming that the hours array is like this [1, 2, 3, 4, 5, 6, 7, ...]
You can include an array of numbers you want to disable in the disabled condition
in this example TouchableOpacity will be disabled for numbers 1, 3, 5, 7 because it will check for the condition when the item is 1 then it will check if 1 is in that array if it is then the condition will be true and it will be like disabled={true} and if the item is 2 then condition will be false because 2 is not in that array and it will be like disabled={false}
your disabled condition will look something like this so you have to list the numbers you want to disable TouchableOpacity for will be in this array
disabled={[1,3,5,7].includes(item)} // TouchableOpacity will be disabled for numbers 1, 3, 5, 7
Example:
<ScrollView contentContainerStyle={styles.contentContainerStyle}>
{hour.map((item, index) => {
return (
<TouchableOpacity
// delayPressIn={}
disabled={[1,3,5,7].includes(item)}
// TouchableOpacity will be disabled for numbers 1, 3, 5, 7
style={styles.item}
key={index}
onPress={() => {
setShow(true);
}}>
<Text style={styles.text}> {item}</Text>
</TouchableOpacity>
);
})}
</ScrollView>

Related

React native list map() method add custom element below selected Item

When Item with id=1 selected
then the element appear below
the selected Item. And when
unselected the element disappear.
This is a list with map() method.
The element should be inside the
SrollView like Item
But isn’t a new Item
I have this code that can create a new Item below the selected Item but I don't want to create a new Item but only appear a custom View(element) like above.
Expo Snack> https://snack.expo.dev/#stefanosalexandrou/honest-cashew
You could store the selected index in a state, which you are already doing. Then, use conditional rendering in order to render a custom component below the selected item. Furthermore, if a selected item is pressed again, set the state to undefined.
The handleOnPress function.
function handleOnPress(idx) {
setSelectedId(prev => prev === idx ? undefined : idx)
}
The updated render function.
<View style={styles.container}>
<ScrollView>
<View>
{data.map((person, index) => {
const backgroundColor = index === selectedId ? "#6e3b6e" : "#f9c2ff";
return (
<View>
<TouchableOpacity
onPress={() => handleOnPress(index)}
style={{
padding:20,
backgroundColor: backgroundColor,
marginBottom:20,
}}
>
<Text>{person.name}</Text>
</TouchableOpacity>
{
index === selectedId ? <View style={{backgroundColor: "red", height: 100, width: "100%"}}><Text>Custom Super Component Visible on press of above item </Text></View> : null
}
</View>
);
})}
</View>
</ScrollView>
</View>
I have added a dummy component if the index is selected.
However, you might want to select multiple items one after the other and deselect them individually while having the same effect. For doing so, we change the state to store an array of indices instead.
The updated state and handleOnPress function.
const [selectedIndices, setSelectedIds] = useState([]);
function handleOnPress(idx) {
if (selectedIndices.includes(idx)) {
setSelectedIds(prev => prev.filter(i => i !== idx))
} else {
setSelectedIds(prev => [...prev, idx])
}
}
The updated render function.
return (
<View style={styles.container}>
<ScrollView>
<View>
{data.map((person, index) => {
const backgroundColor = selectedIndices.includes(index) ? "#6e3b6e" : "#f9c2ff";
return (
<View>
<TouchableOpacity
onPress={() => handleOnPress(index)}
style={{
padding:20,
backgroundColor: backgroundColor,
marginBottom:20,
}}
>
<Text>{person.name}</Text>
</TouchableOpacity>
{
selectedIndices.includes(index) ? <View style={{backgroundColor: "red", height: 100, width: "100%"}}><Text>Custom Super Component Visible on press of above item </Text></View> : null
}
</View>
);
})}
</View>
</ScrollView>
</View>
);

Generate touchable oppacity with map using nested array

I write a calculator app and i need to generate touchable opacity using map
I have a nested array
state= {
buttons:['+', '-', '*', '/', 'Del']
}
And I generate touchable opacity using map
<View style={styles.container}>
<View style={styles.second_con}>
{
this.state.buttons.map((item,index)=>{
return(
<TouchableOpacity style={styles.buttons} key={index}>
<Text>{item}</Text>
</TouchableOpacity>
)
}
)
}
</View>
</View>
And it works
How can i generate it using nested array ?
buttons1:[['√', ' ', 'x!', '+/-', '%'],
['e^x', '10^x', 1, 2, 3],
['ln', 'log', 4, 5, 6],
['e', '^2', 7, 8, 9],
['π', '^3', ',', 0, '='],
]
If you want to preserve the rows you have laid out in your nested array, map through the rows, and use your existing map for each row. Here's an example:
<View style={styles.container}>
<View style={styles.second_con}>
{
this.state.buttons1.map(row => (
<View style={style.row_con}>
{
row.map((item, index) => (
<TouchableOpacity style={styles.buttons} key={index}>
<Text>{item}</Text>
</TouchableOpacity>
))
}
</View>
))
}
</View>
</View>
You need to flatten the list. You can do this with the function below
const flattenLst = (lst)=>{
let res = []
lst.forEach(curSet=>{
res = [...res,...curSet] // TODO: read into spread operators in javascript
})
return res;
}
Then do
<View style={styles.container}>
<View style={styles.second_con}>
{
// flatten this.state.buttons
flattenLst(this.state.buttons).map((item,index)=>{
return(
<TouchableOpacity style={styles.buttons} key={index}>
<Text>{item}</Text>
</TouchableOpacity>
)
}
)
}
</View>
</View>

ReactNative; How to rerender component flipcard after update state

I use flipcard(show front - back) to show value but when I change value to show the new one,Flipcard don't back to the front. It still on same page(but value changed)
Example
data1:Front is "A" ,Back is "B"
data2:Front is "X" ,Back is "Y"
I flip A >> B ,Now on flipcard show "B" after that,I update value. Flipcard show "Y" it's not show "X",I have to flip again to "X" . But, I want to show the front of flipcard every new data. How can I do it?
Nextword() {
this.setState({ count: this.state.count + 1 });
}
render() {
return <View>
<View>
<CardFlip ref={(card) => this.card = card} >
<TouchableOpacity onPress={() => this.card.flip()}>
<Text>{this.state.info[this.state.count].item1}</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.card.flip()} >
<Text>{this.state.info[this.state.count].item2}</Text>
</TouchableOpacity>
</CardFlip>
</View >
<View>
<Button title="PRESS1" onPress={this.Nextword.bind(this)}></Button>
</View>
According to the documentation example of react-native-card-flip I just give a style like this to CardFlip component:
style={{
width: 320,
height: 470,
}}
and fix the issue and card flipped.
below the entire code I try:
<View>
<CardFlip
style={{
width: 320,
height: 470,
}}
ref={(card) => (this.card = card)}>
<TouchableOpacity
onPress={() => this.card.flip()}
style={{height: 100, width: 100, backgroundColor: 'green'}}>
<Text>{this.state.info[this.state.count].item1}</Text>
</TouchableOpacity>
<TouchableOpacity
style={{height: 100, width: 100, backgroundColor: 'green'}}
onPress={() => this.card.flip()}>
<Text>{this.state.info[this.state.count].item2}</Text>
</TouchableOpacity>
</CardFlip>
</View>
see the documentation example here: https://github.com/lhandel/react-native-card-flip/blob/master/Example/App.js

React-Native- Cannot Read Property '0' of Undefined

I'm new to react-native. I am building a calculator app through a tutorial where I'm at the point right now where I'm trying to set it up where pressing one of the calculator buttons will log to the console that digit or symbol.
When I press one of the buttons on the calculator, I receive an error in the console 'Cannot read property '0' of undefined' if I click the 1,4,7 buttons but does 1 and 2 as well for 2,5,8 and 3,6,9 buttons respectively. I figure this means that this.buttonPressed isn't able to process my horizontal array for whatever reason, or that there is some other problem.
I've tried binding buttonPressed in the constructor with
this.buttonPressed = this.buttonPressed.bind(this)
to no avail.
export default class App extends Component {
constructor(){
super()
this.state = {}
}
buttonPressed(text) {
console.log(text)
}
render() {
let rows = []
let nums = [[1, 2, 3], [4, 5, 6], [7, 8, 9,], ['.', 0, '=']]
for(i=0; i<4; i++){
let row = []
for(let j=0; j<3; j++){
row.push(
<TouchableOpacity onPress={() => this.buttonPressed(nums[i]
[j])} style={styles.btn}>
<Text style={styles.btnText}>{nums[i][j]}</Text>
</TouchableOpacity>
)
}
rows.push(<View style={styles.row}>{row}</View>)
}
...
return (
<View style={styles.container}>
...
<View style={styles.buttons}>
<View style={styles.numbers}>
{rows}
</View>
</View>
</View>
);
}
}
Use ES6 format.
change:
buttonPressed(text) {
console.log(text)
}
to:
buttonPressed = (text) => {
console.log(text)
}
A better way to approach this problem would be to remove the logic from the render function. This would help when debugging the problem.
The rows/numbers array can be taken outside of the component as it will not change, so no need to recreate it each time the component render function is called. You can then use the map function on the array to render each row and number item. This is the preferred approach when working with react.
You can try the code below, and see if it works. Although there is some code missing from your snippet.
const ROWS = [[1, 2, 3], [4, 5, 6], [7, 8, 9,], ['.', 0, '=']]
export default class App extends Component {
buttonPressed(text) {
console.log(text)
}
render() {
return (
<View style={styles.container}>
<View style={styles.buttons}>
<View style={styles.numbers}>
{ROWS.map(numbers => (
<View style={styles.row}>
{numbers.map(number => (
<TouchableOpacity style={styles.btn} onPress={() => this.buttonPressed(number)}>
<Text style={styles.btnText}>{number}</Text>
</TouchableOpacity>
))}
</View>
))}
</View>
</View>
</View>
);
}
}
An even better approach would be to use a pure component. Then if you need state, you can use react hooks.
const ROWS = [[1, 2, 3], [4, 5, 6], [7, 8, 9,], ['.', 0, '=']]
const App = () => {
const buttonPressed = (text) => {
console.log(text)
}
return (
<View style={styles.container}>
<View style={styles.buttons}>
<View style={styles.numbers}>
{ROWS.map(numbers => (
<View style={styles.row}>
{numbers.map(number => (
<TouchableOpacity style={styles.btn} onPress={() => buttonPressed(number)}>
<Text style={styles.btnText}>{number}</Text>
</TouchableOpacity>
))}
</View>
))}
</View>
</View>
</View>
);
}
export default App

Detect touch position in array of view (REACT NATIVE)

I am creating a planning application in react native and i couldn't handle the creation of a new view above a list of rendered views
I want to detect a user touch in map of views and show a view in the touch position, I tried to use
<TouchableOpacity onPress={(evt)=>{this.setTopNewViewPostion(evt.nativeEvent.locationY}}
but this was rendering the view for all slots that mean it is duplicated every time
Thanks
handleClick (){ this.setState({newSlotVisible: true});} renderSlotsOfTab(tab, i){
const ViewFlex = [1, 2, 3, 4];
return (
<TouchableOpacity
onStartShouldSetResponder={() => true}
onMoveShouldSetResponder={() => true}
onResponderMove={()=>this.hideNewSlot()}
ref={(ref) => i}
tabLabel={tab}
key={i}
activeOpacity={1}
>
{
ViewFlex.map((b , i)=>
{
return(
<TouchableOpacity
ref={i}
removeClippedSubviews
style={[styles.oneSlotView ,
{ flex: b }]}
key={i}
/** here get the touch position**/
onPress={this.handleClick.bind(this, i)}
>
<View
style={ styles.hoursIndicatorView}
>
<Text style={styles.textIndicatorTime}>00h00</Text>
</View>
</TouchableOpacity>)
}
)}
{this.state.newSlotVisible?
//the new view to render is this one
this.renderNewView();
:null}
</TouchableOpacity>
);
}