react-native-picker won't populate data on edit form - react-native

I'm using react-native-web and for the Native side, I'm using import { Picker } from '#react-native-picker/picker'
I'm using a reusable form modal for create and edit. On web, the data populates just fine but on iOS for example, the drop downs don't get set correctly. I've created a reusable component that has react-native-picker/picker as it's child component. So for example I set state on form mount like this:
const [languageAbility, setLanguageAbility] = useState<number>(
childProfile?.languageAbility?.id || 0,
)
const [grade, setGrade] = useState<number>(childProfile?.grade?.id || 0)
and on my components, they are set up like this:
<AccessibleSelect
selectedValue={grade}
options={childMenusData?.menus?.schoolGrades.map((sg) => ({
label: sg.title,
value: sg?.id,
}))}
onValueChange={(val: number) => setGrade(val)}
label={t('ChildForms.Grade')}
testID="grade"
inputStyle={styles.selectStyles}
tooltipText={isMobile ? 'What is a grade?' : ''}
tooltipContent={t('ChildForms.WhatIsAGradeContent')}
tooltipPlacement={'bottom'}
/>
</View>
{!isMobile && (
<View style={styles.inputContainerHalf}>
<Tooltip
text="What is a grade?"
content={t('ChildForms.WhatIsAGradeContent')}
placement={'right'}
/>
</View>
)}
</View>
<View
style={{
flexDirection: isMobile ? 'column' : 'row',
width: '100%',
margin: 0,
}}
>
<View
style={[
styles.inputContainerHalf,
{ marginRight: isMobile ? 0 : 30 },
]}
>
<AccessibleSelect
selectedValue={languageAbility}
options={childMenusData?.menus?.languageAbilities.map((la) => ({
label: la.title,
value: la.id,
}))}
onValueChange={(val: number) => setLanguageAbility(val)}
label={t('ChildForms.LanguageAbility')}
testID="languageAbility"
additionalContainerStyles={{ paddingTop: 0, paddingBottom: 0 }}
inputStyle={styles.selectStyles}
/>
</View>
</View>
And the actual Picker component (AccessibleSelect) looks like this:
return (
<View style={[styles.container, additionalContainerStyles]}>
<Picker
ref={refToAttachToInput}
style={[
Platform.OS === 'ios'
? styles.pickerIOS
: [
styles.picker,
{ borderColor, borderStyle: 'solid', borderWidth: 1 },
],
inputStyle,
]}
selectedValue={selectedValue}
onValueChange={onValueChange}
defaultValue={defaultValue && defaultValue}
itemStyle={styles.pickerText}
mode={isAndroid && 'dropdown'}
>
{options.map((o) => (
<Picker.Item label={o.label} key={o.value} value={o.value} />
))}
</Picker>
<View
style={[
styles.bottomContainer,
{ justifyContent: fieldError ? 'space-between' : 'flex-end' },
]}
>
{!!fieldError && (
<Text accessibilityLiveRegion="assertive" style={styles.errorText}>
{fieldError}
</Text>
)}
</View>
</View>
)
}

Related

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

Filtered object array length in React Native

I have an object array as shown below:
data = [
{
"shelf_name" : "Shelf A",
"shelf_size" : "9",
"shelf_color" : "red",
"shelf_height": "100",
"shelf_width" : "150",
},
{
"shelf_name" : "Shelf A",
"shelf_size" : "4",
"shelf_color" : "blue",
"shelf_height": "150",
"shelf_width" : "170",
},
{
"shelf_name" : "Shelf B",
"shelf_size" : "6",
"shelf_color" : "yellow",
"shelf_height": "175",
"shelf_width" : "200",
}
]
I am using the filter function to filter the data by shelf_name and then display the data on the screen. My return function looks like this:
return (
<View style={styles.container}>
{loading ? (
<ActivityIndicator size="large" color={COLORS.blue} />
) : (
<View style={styles.container1}>
<View style={{height: 250}}>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={styles.scrollViewStyle}>
{data
.filter(function (shelfName) {
return shelfName.shelf_name === 'Shelf A';
})
.map((item, index) => {
<View key={index} style={styles.productView}>
<Text
style={{
alignSelf: 'flex-start',
fontWeight: 'bold',
marginLeft: 5,
}}>
{item.product_name}
</Text>
<Text>Shelf Size: {item.shelf_size}</Text>
<Text>
Shelf Height: {item.shelf_height}
</Text>
<Text>
Shelf Width: {item.shelf_width}
</Text>
<Text>
Shelf Color: {item.shelf_color}
</Text>
</View>;
})}
</ScrollView>
</View>
</View>
</View>
Current Output:
If the data exists after the filter function it is displayed properly. If the data does not exists nothing is displayed on the screen
What I am trying to achieve:
Show the data if the data exists or else show a message that "The data does not exist". To achieve this I tried to check the length of the object after the filter function by using Object.keys(data).length inside an if condition. But, I am unable to do so. Please let me know how do I achieve this.
What I am trying to achieve: Show the data if the data exists or else show a message that "The data does not exist". To achieve this I tried to check the length of the object after the filter function by using Object.keys(data).length inside an if condition. But, I am unable to do so. Please let me know how do I achieve this.
Have you tried using data.length? By what it look like your data is always an array, so you don't need the Object.keys. In fact using it will always be true because beside the length key an array object have many other functions.
Try something like...
const filteredData = data.filter(function (shelfName) {
return shelfName.shelf_name === 'Shelf A';
});
return (
<View style={styles.container}>
{loading ? (
<ActivityIndicator size="large" color={COLORS.blue} />
) : (
<View style={styles.container1}>
<View style={{height: 250}}>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={styles.scrollViewStyle}>
{!filteredData.length && <Text>The data does not exist</Text>}
{filteredData
.map((item, index) => {
<View key={index} style={styles.productView}>
<Text
style={{
alignSelf: 'flex-start',
fontWeight: 'bold',
marginLeft: 5,
}}>
{item.product_name}
</Text>
<Text>Shelf Size: {item.shelf_size}</Text>
<Text>
Shelf Height: {item.shelf_height}
</Text>
<Text>
Shelf Width: {item.shelf_width}
</Text>
<Text>
Shelf Color: {item.shelf_color}
</Text>
</View>;
})}
</ScrollView>
</View>
</View>
</View>

Not able to render the data in input type on button click

I am very new in react native . i am building a module which increment the state hook variable and render it in my input , but the counter did't render it after 1,meanz when i click on plus button it increment the counter to 1 but after that if i re-press the plus button it did't change the value 1 to 2. here is my code snippet of my input and plus button.
<View style={{flex:1 ,flexDirection: 'row', backgroundColor: '#ebedf087',width: '100%' }} >
<View >
<Pressable onPress={ () => { addQtyItem( loadName , cardId ) } } style={{backgroundColor: Colors.primary,padding: 8}}>
<Icon name='plus' type='font-awesome' style={{fontSize: 25,color: 'white', textAlign: 'center'}} />
</Pressable>
</View>
<View style={{width: 87}}>
<TextInput value={ (UpdateQtyofItem[loadName+'__'+cardId] != undefined) ? (UpdateQtyofItem[loadName+'__'+cardId].value).toString() : '0' } key={cardId} onChangeText={(value) => { getinputValue( loadName , cardId , value ) }} placeholder="Qty" style={{textAlign: 'center'}} />
</View>
<View style={{backgroundColor: 'red',padding: 8}}>
<Icon name='minus' type='font-awesome' style={{fontSize: 25,color: 'white', textAlign: 'center'}} />
</View>
</View>
code snippet of addQtyItem function.
const [ UpdateQtyofItem , setUpdateQtyofItem] = useState({});
function addQtyItem(loadName , cardId){
let loadedName = loadName+'__'+cardId;
if( selectedLoadArray[loadedName] != undefined ){
selectedLoadArray[loadedName].value = (selectedLoadArray[loadedName].value+1);
}else{
selectedLoadArray[loadName+'__'+cardId] = {'value' : 1 ,'cardId' : cardId};
}
setUpdateQtyofItem(selectedLoadArray)
}
Try this
const [ UpdateQtyofItem , setUpdateQtyofItem] = useState({});
function addQtyItem(loadName , cardId){
let loadedName = loadName+'__'+cardId;
if( selectedLoadArray[loadedName] != undefined ){
let temp={...selectedLoadArray[loadedName]}
temp.value = (temp.value+1);
selectedLoadArray[loadedName]=temp
}else{
selectedLoadArray[loadName+'__'+cardId] = {'value' : 1 ,'cardId' : cardId};
}
setUpdateQtyofItem(selectedLoadArray)
}
This problem with shallow comparison.

How can I animate a component to another component?

I want to animate a card to the game table.
How can I move the component of the card to that of the game table?
Onpress
Result
I tried to with:
this.state.cards.find(c => c.id == id).ref.layout.animate({
from: { bottom: -20, bottom: 0 },
to: { bottom: 416, bottom: 196 },
But the .animate method is based on the x and y of the parent view and not on the x y of the screen.
Here is the part of my code:
<View style={styles.board}>
<ImageBackground source={require('../../assets/ornement.png')} resizeMode='contain' style={styles.ornement}>
<View onLayout={ref => this.test = ref}>
<Text style={boardStyle.message}>Test</Text>
</View>
<View style={boardStyle.boardContent} ref={event => this.view = event}>
{this.state.board.map((r, i) => <Image key={i} style={boardStyle.image} resizeMode='contain' source={CardUtils.PathOfimgCard(r.fullName)} />
)}
</View>
</ImageBackground>
</View>
<View style={styles.deck}>
{this.state.deck.map((r, i) =>
<Card onRef={(ref) => this.state.cards.push({ id: r.id, ref: ref })} key={i} ctx={r} action={this.play} select={this.state.cardSelect.find(c => c.id == r.id) != null} id={r.id} path={CardUtils.PathOfimgCard(r.fullName)} style={deckStyle} />
)}
</View>
The Card component:
<Animatable.View ref={event => this.layout = event} iterationCount={3} delay={5000} direction="alternate" style={this.props.style.touchZone} >
<TouchableOpacity onPress={() => this.props.action(this.props.id)} >
<View ref={event => this.view = event}>
<ImageBackground source={this.props.path} style={this.props.select ? this.props.style.active : this.props.style.image} resizeMode='contain' >
{!this.props.ctx.canPlay ? <Image style={[this.props.select ? this.props.style.active : this.props.style.image, styles.image]} resizeMode='contain' source={require('../../assets/black.png')} /> : <Image></Image>}
</ImageBackground>
</View>
</TouchableOpacity>
</Animatable.View>
thank you in advance

How to close swipe item in react-native?

I have this code (get from native-base example) that is working fine. But after click on either sides (right or left), the 'swipe' still open. I know that there is a method called closeRow(), but I don't know how to apply in this case.
Left button is for 'split' item into 2 or more, while right button is to delete current item. What I need is to close all opened rows in this list. Why all? Because in the case of 'delete' function, the current item is deleted in the right way, but the next-one get right button opened (since it's the same 'index' of list, even if the item itself is different).
This is my current code:
<Container style={styles.container}>
<Header>
<Left>
<Button transparent onPress={() => this.props.navigation.goBack()}>
<Icon name="arrow-back" />
</Button>
</Left>
<Body>
<Title>{translate("title", { ...i18n_opt, name })}</Title>
</Body>
</Header>
<Content>
<Modal
isVisible={this.state.visibleModal === true}
animationIn={"slideInLeft"}
animationOut={"slideOutRight"}
>
{this._renderModalContent()}
</Modal>
<View style={styles.line}>
<View style={{ flex: 2 }}>
<Text style={[styles.alignCen, styles.headerTitle]}>
{translate("lap", { ...i18n_opt })}
</Text>
</View>
<View style={{ flex: 10 }}>
<Text style={[styles.alignCen, styles.headerTitle]}>
{translate("time", { ...i18n_opt })}
</Text>
</View>
<View style={{ flex: 3 }}>
<Text
style={[
{ paddingRight: 10 },
styles.alignRig,
styles.headerTitle
]}
>
{translate("diff", { ...i18n_opt })}
</Text>
</View>
</View>
<List
enableEmptySections
dataSource={laps2}
ref={c => {
this.component = c;
}}
renderRow={data => <PersonalRankItem dados={data} />}
renderLeftHiddenRow={data => (
<Button
full
onPress={() => {
this.setState({
...this.state,
visibleModal: true,
cur_tx_id: tx_id,
cur_lap: data.lap
});
}}
style={{
backgroundColor: "#CCC",
flex: 1,
alignItems: "center",
justifyContent: "center",
marginBottom: 6
}}
>
<MaterialCommunityIcons
name="arrow-split-vertical"
size={20}
color="#5e69d9"
/>
</Button>
)}
renderRightHiddenRow={(data, secId, rowId, rowMap) => (
<Button
full
danger
onPress={_ => {
//alert("Delete");
//console.log("Data.lap:",data.lap);
dispatchDeleteLap(tx_id, data.lap, true);
}}
style={{
flex: 1,
alignItems: "center",
justifyContent: "center",
marginBottom: 6
}}
>
<Icon active name="trash" size={20} />
</Button>
)}
leftOpenValue={70}
rightOpenValue={-70}
/>
</Content>
</Container>
Goal
You need to close all the rows, each time one of row side button clicked. The next problem is when item deleted, the next row is opened even the content is different.
How?
All you need is first, collect the ref of each rows and then when the button clicked, trigger the closeRow method of all ref's row. And the important part, make your row key persistent and unique to avoid problem like in your case.
Quick Code Sample
class Screen extends Component {
constructor(props) {
super(props);
this._rowRefs = [];
}
// this is used to collect row ref
collectRowRefs = (ref) => {
this._rowRefs.push(ref);
};
// your render row function
renderRow = (data) => (
// make this row key consistent and unique like Id, do not use index counter as key
<PersonalRankItem key={data.id} dados={data} ref={this.collectRowRefs}/>
);
// When your hidden side button is clicked
onButtonClicked = (data) => {
// do the button normal action
// ....
// close each row
this._rowRefs.forEach((ref) => {
ref.closeRow();
});
};
// this is your hidden side button
renderLeftHiddenRow = () => (
<Button onClick={this.onButtonClicked} />
);
render() {
// Your List in here
return (
<List
renderRow={this.renderRow}
renderLeftHiddenRow={this.renderLeftHiddenRow}
/>
)
}
}