I have a form where there is an input field for adding the user. It is a different kind of field. When user click on that field, the user is routed to another page where there is already a list of users and there a user can search as well. From that page, if user selects the particular user, he/she is redirected back to that form page and fill that field with the selected user name.
For now I have tried it as following
<Row>
<InputFieldWrapper label="Assigned to">
<Field
name="assigned_to"
input=""
placeholder="Search for contacts to assign"
readonly={false}
component={InputTextWithSearchField}
onPress={() => Actions[routeConstants.SEARCH_ASSIGNEE]({
keys : 'user',
data : taskValues ? taskValues.assigned_to : [],
faFetched: faFetched.users,
fieldName: 'assigned_to',
label : 'Assignee',
})}
/>
</InputFieldWrapper>
</Row>
const InputTextWithSearchField = props => {
let value = props.input.value || {};
makeUpdate = text => {
props.update(text);
};
return (
<View style={styles.inputFieldWrapper}>
<View style={styles.field}>
<TextInput
style={styles.inputField}
onChangeText={makeUpdate}
value={value.label}
placeholder={props.placeholder} />
</View>
<View style={styles.rightSideContent}>
<Icon
name="search"
size={26}
onPress={() => props.onPress()}
style={styles.searchField} />
</View>
</View>
);
};
class Search extends React.Component { // eslint-disable-line
state = {
items: [],
}
componentDidMount() {
this.update(' ');
}
// handleChange = data => {
// console.log('change', data);
// };
update = text => {
this.props.faFetched.sync(
{ search: text, priority_fields: 'personal.first_name,personal.last_name' }
).
then(res => this.setState({ items: res })).
catch(err => console.log(err)); // eslint-disable-line
};
itemSection = item => {
if(item)return alphabetic.map(alpha => {
return ({
title: alpha,
data : (item || []).filter(contact => contact.personal.first_name[0] === alpha)
});
});
};
renderHeader = ({ section }) => {
return <View style={styles.sectionHeader}>
<Text style={styles.sectionText}>
{section.title}
</Text>
</View>;
};
render() {
const { faFetched, data } = this.props;
const { items } = this.state;
return (
<View style={styles.container}>
<ActionButtons
label={this.props.label}
/>
<KeyboardAvoidingView keyboardVerticalOffset={0} behavior='padding'>
<ScrollView
keyboardShouldPersistTaps="always"
>
<View style={styles.formContainer}>
<Row zIndex={5}>
<InputFieldWrapper>
<Field
input=""
name={this.props.fieldName}
placeholder="Search contact"
update={this.update}
readonly={false}
component={InputTextWithSearchField}
/>
</InputFieldWrapper>
</Row>
</View>
<SectionList
sections={this.itemSection(items && items)}
renderItem={({ item, section }) => {
if(item)return <ListItem
item={item}
section={section} />;
}}
renderSectionHeader={items && this.renderHeader}
keyExtractor={item => item._id}
/>
</ScrollView>
</KeyboardAvoidingView>
</View>
);
}
}
class ListItem extends React.Component {
render() {
return (
<View style={styles.sectionItemWrapper}>
<TouchableOpacity onPress={() => null;}>
<Text style={styles.sectionItem}>
{this.props.item.personal.full_name}
</Text>
</TouchableOpacity>
</View>
);
}
}
It should be following
when user clicks on this input field, he/she will move to next step
next step is this and when user selects the name of user from the list he/she will be redirected back to the form page where that username should be filled in that field
Can anyone give me an idea, please? Right now I could only redirect the user to the contact list but I have no idea how can i route back to the same form page after user touches the contact list and fill the field with that value
If you are using react-navigation you can navigate back to the form page and send parameters along with.
this.props.navigation.navigate("form", {
userID:id,
userName: Name,
})
and then in componentdidmount method set value of text field to the one passed in parameters.
If you are using react-native-router-flux use
Actions.YOURSCENE({userID:id, userName: Name});
or use
Actions.pop({refresh: {userID:id, userName: Name}});
you may find the passed data in this.props
Related
In my Todo App i have sucessfully implemented the add and delete functions but the update function is having trouble. What i need it to do is when i click the touchable opacity of a Todo, it should appear in my inputbox and if any change is made then that todo should be updated e.g clicking on abcd must make it appear in input box and changes made to it should be updated. Picture is also added below
export default function Todo() {
const [getText, setText] = useState('');
const [getList, setList] = useState([]);
const addItem = () => {
setList([...getList, {key: Math.random().toString(), data: getText}]);
setText('');
}
const removeItem = (itemKey) => {
setList(() => getList.filter(item => item.key != itemKey));
}
const updateFieldChanged = (index) => e => {
let newArr = [...getList]; // copying the old datas array
newArr[index] = e.target.value; // replace e.target.value with whatever you want to change it to
setList(newArr);
}
return (
<View style={styles.container}>
<Text style={styles.title}>todo</Text>
<View style={styles.inputContainer}>
<TextInput
style={styles.textInput}
placeholder="Enter Item"
onChangeText={text => setText(text)}
value={getText}
/>
<CustomButton
text = 'add'
color='red'
title= 'add'
textSize={20}
textColor="white"
onPressEvent={addItem}
/>
</View>
<ScrollView style={styles.scrollview}>
{getList.map((item, id) =>
<TouchableOpacity
key={item.key}
activeOpacity={0.7}
onPress= {() => updateFieldChanged(id)}
>
<View style={styles.scrollviewItem}>
<Text style={styles.scrollviewText}>{id}) {item.data}</Text>
<TouchableOpacity
onPress={() => removeItem(item.key)}
>
<View style={styles.crosstextcontainer}>
<Text style={styles.crosstext}>X</Text>
</View>
</TouchableOpacity>
</View>
</TouchableOpacity>
)}
</ScrollView>
</View>
);
}
Change
<TouchableOpacity
key={item.key}
activeOpacity={0.7}
onPress= {() => updateFieldChanged(id)}
>
to
<TouchableOpacity
key={item.key}
activeOpacity={0.7}
onPress= {() => updateFieldChanged(id,getText)}
>
Here iam passing the text that you need to enter to update a particular field
change your updateFieldChanged like this:
const updateFieldChanged = (index, text) => {
let newArr = [...getList]; // copying the old datas array
newArr[index].data = text; // replace e.target.value with whatever you want to change it to
setList(newArr);
setText('');
}
Here iam assigning the text you entered in the TextInput to the data object, which will update the array.
Hope this helps!
Now I am trying to let a screen containing some lists know other screen's state.
The main screen contains some Form Components which user can input text to.
Other screens, Form Components contain some TextInput forms.
If a user inputs some texts into some form and then if this user puts a back button or a save-button, I want to change the main screen's state of these form components to be like "Editing", "Not Edit" or "Complete".
How to change the state of each form component's state on the Main screen?
This picture is the main screen. Please focus on Red characters. There will be changed if a user will input some text into a form on other screens.
This is a input-screen
handleOnpress() {
const db = firebase.firestore();
const { currentUser } = firebase.auth();
db.collection(`users/${currentUser.uid}/form1`).add({
form1 : [
{ fullname: this.state.fullname },
{ middleName: this.state.middleName },
{ reason: this.state.reason },
{ birthPlaceCity: this.state.birthPlaceCity },
{ birthPlaceCountry: this.state.birthPlaceCountry },
{ Citizinchip: this.state.Citizinchip },
{ aboutMaridge: this.state.aboutMaridge },
{ fromTermOfMaridge: this.state.fromTermOfMaridge },
{ ToTermOfMaridge: this.state.ToTermOfMaridge },
{ nameOfSpouse: this.state.nameOfSpouse },
{ birthdateOfSpouse: this.state.birthdateOfSpouse },
{ fromTermOfExMaridge: this.state.fromTermOfExMaridge },
{ ToTermOfExMaridge: this.state.ToTermOfExMaridge },
{ nameOfExSpouse: this.state.nameOfExSpouse },
{ birthdateOfExSpouse: this.state.birthdateOfExSpouse }]
})
.then(() => {
this.props.navigation.goBack();
})
.catch((error) => {
console.log(error);
});
}
render() {
return (
<ScrollView style={styles.container}>
<InfoHeader navigation={this.props.navigation}>申請者情報1
</InfoHeader>
<Notes />
<QuestionTextSet onChangeText={(text) => { this.setState({
fullname: text }); }} placeholder={'例:留学太郎'}>姓名(漢字表記)
</QuestionTextSet>
<QuestionTextSet onChangeText={(text) => { this.setState({
middleName: text }); }}>本名以外に旧姓・通称名(通名)・別名など他の名前が
あればローマ字で記入</QuestionTextSet>
<QuestionTextSet onChangeText={(text) => { this.setState({
reason: text }); }} placeholder={'例:結婚・離婚/ご両親の離婚のためな
ど'}>別名がある方はその理由</QuestionTextSet>
<SubmitButton style={styles.saveButton} onPress=
{this.handleOnpress.bind(this)}>保存</SubmitButton>
<Copyrights />
</ScrollView>
);
This is the main screen.
class WHApply extends React.Component {
render() {
return (
<ScrollView style={styles.container}>
<WHApplyBar navigation={this.props.navigation} />
<WHApplyIndexBar />
<HWApplyMailBar />
<HWApplyList navigation={this.props.navigation} />
<Agreement />
<SubmitButton>同意して送信</SubmitButton>
<Logout />
<Copyrights />
</ScrollView>
);
}
}
And this is a code of HWApplyList.
This component is import to the main screen.
class HWApplyList extends React.Component {
state = {
fontLoaded: false,
}
async componentWillMount() {
await Font.loadAsync({
FontAwesome: fontAwesome,
});
this.setState({ fontLoaded: true });
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={() => {
this.props.navigation.navigate('PersonalInfo1'); }} >
<View style={styles.listBox}>
<Text style={styles.listBoxText}>
申請者情報1
</Text>
<View style={styles.inputBotton}>
<Text style={styles.inputBottonText}>未入力</Text>
</View>
<View style={{ flex: 1, justifyContent: 'center' }}>
{
this.state.fontLoaded ? (
<View style={styles.navigationButton}>
<Text style={styles.navigationButtonIcon}>{'\uf0da'}
</Text>
</View>
) : null
}
</View>
</View>
</TouchableOpacity>
In addition to the previous answer, you will also need to pass a handler function to the screen child. This handle function will allow your child screen to modify the parent's state.
Something like
onChange(value) {
this.setState({value});
}
render() {
return (
<Screen1 value={this.state.value} onChange={this.onChange}/>
<Screen2 value={this.state.value}/>
)
}
When you start to make many components that uses each other's state, Using a tool like "redux" makes it much easier.
Instead of putting your data ( that's you want it to be shared with the other components ) in a particular component state. you can create a common state for the whole app and you can access this state from any component.
here's a good article:
Understanding Redux: The World’s Easiest Guide to Beginning Redux
I've been searching around how to make a single select in Flatlist but I can't find any, here in my code I'am trying to make a single select on every cells that is inside my Flatlist.
Example: I select cell no.1, then no.1 will be selected. And if I need to select no.2, both no.1 and no.2 will be selected.
What is happening in my code is when I select no.1, it would select all cells.
export default class Dishes extends Component {
constructor(props) {
super (props)
this.state = {
data: [],
id: [],
price: [],
count: 0,
SplOrder: '',
tbl: this.props.navigation.state.params.tbl,
orderDet: this.props.navigation.state.params.orderDet,
DineIn: this.props.navigation.state.params.DineIn,
TakeOut: this.props.navigation.state.params.TakeOut,
}
}
/********************EDIT*************************
_incrementCount() {
this.setState({ count: this.state.count + 1 });
}
_decreaseCount() {
this.setState({ count: this.state.count - 1 });
}
changeTextHandler() {
this.setState({ ['count'+index]: text });
};
*/
_renderItem = ({ item, index }) => {
return (
<View>
<View>
<View>
<Text>Name: { item.menu_desc }</Text>
<View}>
<Text>Price: ₱{ item.menu_price }</Text>
<Text>Status: { item.menu_status }</Text>
</View>
<TextInput
placeholder = "Insert Special Request"
onChangeText = { (text) => this.setState({ SplOrder: text }) }
value = { this.state.SplOrder }
/>
</View>
<View>
<TouchableOpacity
onPress = {() => this._incrementCount()}>
<Text> + </Text>
</TouchableOpacity>
<TextInput
onChangeText={this.changeTextHandler}
value={this.state['count'+index].toString()} // Not working
placeholder="0"/>
<TouchableOpacity
onPress = {() => this._decreaseCount()}>
<Text> - </Text>
</TouchableOpacity>
</View>
</View>
</View>
)
}
render() {
return (
<View>
<View>
<Text>Table No: { this.state.tbl }</Text>
<Text>Order No: { this.state.orderDet }</Text>
<Text>{ this.state.DineIn }{ this.state.TakeOut }</Text>
</View>
<FlatList
data = {this.state.data}
keyExtractor={(item, index) => index.toString()}
extraData={this.state}
renderItem = {this._renderItem}
/>
<View>
<TouchableOpacity
onPress = {() => this.submit()}>
<Text>Send Order</Text>
</TouchableOpacity>
</View>
</View>
)
}
}
The TextInputs are targeting the same state SplOrder so, if you change it in any TextInput the others will display the same. The solution I see is to put an state for each item you create.
You should do this:
<TextInput
placeholder = "Insert Special Request"
onChangeText = { (text) => this.setState({ ['SplOrder'+index]: text }) }
value = { this.state['SplOrder'+index] }
/>
The second problem we have discussed in the comments should be fixed by passing index parameter to incrementCount function.
Hi, now in the method _incrementCount() you will have to pass the index and increment each count with it index as you have in the value of. So you could do
<TouchableOpacity
onPress = {() => this._incrementCount(index)}>
<Text> + </Text>
</TouchableOpacity>
And then change your _incrementCount method adding a parameter and doing like this:
_incrementCount(index) {
this.setState({ ['count'+index]: this.state['count'+index] + 1 });
}
I have the following react-native code where I am trying to build a custom form to gather user input. The form renders correctly with 3 input boxes and a Save button.
In the code below, the issue is that as soon as I start typing on the first TextInput field, the this.saveFormData() which is called only inside the TouchableHighlight button gets fired!
Why are the TextInput events conflicting with the TouchableHighlight ones? How do I fix the issue?
class NewScreen extends React.Component {
constructor(props) {
super(props);
this.state = { songTitle: null, chord: null, strumPattern: null };
}
saveFormData = () => {
console.log(this.state.songTitle);
() => navigate("Home");
};
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.row_cell_chord_songTitle}>
<Text style={styles.new_input_label}> Song Title </Text>
<TextInput
style={styles.new_input_field}
onChangeText={text => this.setState({ songTitle: text })}
value={this.state.songTitle}
/>
<Text style={styles.new_input_label}> Chords </Text>
<TextInput
style={styles.new_input_field}
onChangeText={text => this.setState({ chord: text })}
value={this.state.chord}
/>
<Text style={styles.new_input_label}> Strumming Pattern </Text>
<TextInput
style={styles.new_input_field}
onChangeText={text => this.setState({ strumPattern: text })}
value={this.state.strumPattern}
/>
</View>
<TouchableHighlight
style={styles.saveButton}
onPress={this.saveFormData()} // <-- typing on above Inputbox fires this function.
>
<Text style={styles.buttonText}>
<FontAwesome>{Icons.heart}</FontAwesome> Save
</Text>
</TouchableHighlight> */
</View>
</View>
</View>
);
}
}
You need to pass a function to onPress, currently you're invoking the function and passing whatever it returns. You just need to change it to:
onPress={this.saveFormData}
I'm using react-native-autocomplete-input and I'd like disable the <Autocomplete /> input. I tried adding disabled={this.state.loading} (disabling it while the data loads...right now the user can start typing before the autocomplete is available).
I'm confident there's a way to do so but I haven't been able to figure it out. Code below:
<Autocomplete
data={data}
defaultValue={query}
listStyle={styles.autoCompleteItems}
onChangeText={(text) => this.setState({query: text})}
renderItem={(data) => (
<TouchableOpacity onPress={() =>
this.setState({query: data.name, schoolId: data.id, social: data.social})
}
>
<Text>{data.name}</Text>
</TouchableOpacity>
)}
/>
react-native-autocomplete-input itself does not provide functionality to disable the input field. So passing disabled={this.state.loading} will have no effect.
You can edit the the package by going into your node_modules/react-native-autocomplete-input folder and editing index.js file.
change the render function in index.js to following. Now its accepting isEditable prop and passing it to TextInput
render() {
const { showResults } = this.state;
const { containerStyle, inputContainerStyle, onEndEditing, isEditable, style, ...props } = this.props;
return (
<View style={[styles.container, containerStyle]}>
<View style={[styles.inputContainer, inputContainerStyle]}>
<TextInput
editable={isEditable}
style={[styles.input, style]}
ref="textInput"
onEndEditing={e =>
this._showResults(false) || (onEndEditing && onEndEditing(e))
}
{...props}
/>
</View>
{showResults && this._renderItems()}
</View>
);
}
Now you can pass isEditable={this.loading} as a prop to <Autocomplete />