This is my code for redux form. I have also set enableReinitialize to true and followed the react-form documentation.
I have hard coded the initialValues object just for testing purposes. But still my form is not getting initialized.
import React, { Component } from 'react';
import { Container, Header, Body, Content, Title, Button, Text, Left, Icon, Right } from 'native-base';
import { Field, reduxForm } from 'redux-form';
import { connect } from 'react-redux';
import MyTextInput from './TextInput';
import { fetchProfileData } from '../../actions';
const validate = values => {
const error = {};
error.email = '';
error.name = '';
error.mobile = '';
let ema = values.email;
let nm = values.name;
let mob = values.mobile;
if (values.email === undefined) {
ema = '';
}
if (values.name === undefined) {
nm = '';
}
if (values.mobile === undefined) {
mob = '';
}
if (ema.length < 8 && ema !== '') {
error.email = 'too short';
}
if (!ema.includes('#') && ema !== '') {
error.email = '# not included';
}
if (nm.length > 8) {
error.name = 'max 8 characters';
}
if (mob.length < 10 && mob !== '') {
error.mobile = 'min 10 digits';
}
return error;
};
class SimpleForm extends Component {
componentWillMount() {
this.props.fetchProfileData();
}
render() {
const { handleSubmit } = this.props;
console.log(this.props.initialValues);
return (
<Container>
<Header>
<Left>
<Button
transparent
onPress={() => this.props.navigation.navigate('DrawerOpen')}
>
<Icon name="menu" />
</Button>
</Left>
<Body>
<Title>Profile</Title>
</Body>
<Right />
</Header>
<Content padder>
<Field name='name' component={MyTextInput} label='Vendor Name' />
<Field name='company_name' component={MyTextInput} label='Company Name' />
<Field name='office_address' component={MyTextInput} label='Office Address' />
<Field name='email' component={MyTextInput} label='Email' />
<Field name='mobile' component={MyTextInput} label='Contact' />
<Button block primary onPress={handleSubmit((values) => console.log(values))} style={{ marginTop: 20 }}>
<Text>Save</Text>
</Button>
</Content>
</Container>
);
}
}
const mapStateToProps = state => {
return {
initialValues: { name: 'abcde#gmail.com' }
};
};
SimpleForm = connect(mapStateToProps, { fetchProfileData }
)(SimpleForm);
export default reduxForm({
form: 'test',
validate,
enableReinitialize: true
})(SimpleForm);
I've been struggling with this for some time. I've never been able to get anything with props to work. But I just need to some initial state stuff, so this works for me. Hope it works for you as well.
----- This works if you only want to set the initial values once.
export default reduxForm({
form: 'test',
validate,
initialValues: { name: 'abcde#gmail.com' }
})(SimpleForm);
Edit: It seemed I needed to pass variables in. This has been able to work for me for variables set in mapStateToProps. I think your setup didn't work because it is mapping state and props to the form, then adding reduxForm. It looks like it needs to be the other way around.
const mapStateToProps = (state) => {
return {
initialValues: {
name: 'foobar',
}
}
}
export default (connect(mapStateToProps, mapDispatchToProps)(reduxForm({
form: 'groupForm',
enableReinitialize: true
})(SimpleForm)))
Related
I'm new to react native.
I've created a react native app and my first screen is a login screen. I'm using onChangeText to update state vars with username and password and this works great initially.
However on "logout" when I pop back to the login screen. The inputs still have my username and password in. However the state vars are now back to null.
I've tried setting value to {this.state.username} for the input but this just causes a depth error on state after 2 input presses so doesn't work.
Am I missing something?
import React, { Component } from 'react';
import { View, Text, StyleSheet, Image, Alert, AsyncStorage, Linking } from 'react-native';
import { Input, Left, Spinner, Container, Item, Form, Header, Content, Label, Button } from 'native-base'
export default class Login extends Component {
state = { username: "", password: "", isLoaded: true }
static navigationOptions = {
header: null
}
constructor(props) {
super()
this.state.isLoaded = false
AsyncStorage.getItem("loggedIn").then(res => {
if (res === "true") {
this.props.navigation.navigate('List')
}
else {
this.setState({isLoaded: true})
}
})
}
checkLogin() {
if ((!this.state.username) || (!this.state.password)) {
Alert.alert('Error', 'Username/Password combination unknown', [{
text: 'Okay'
}])
return
}
....... snip ......
if (response === false) {
Alert.alert('Error', 'Username/Password combination unknown', [{
text: 'Okay'
}])
}
else {
AsyncStorage.setItem('user', JSON.stringify(response));
AsyncStorage.setItem('loggedIn', "true");
this.setState({username: null, password: null})
this.props.navigation.navigate('List')
}
}
}
render()
{
if (this.state.isLoaded == false) {
return (
<Container>
<Spinner />
</Container>
)
}
return (
<Container>
<Content>
<Image source={require('../../assets/logo.jpg')}/>
<Form>
<Item floatingLabel>
<Label>Username</Label>
<Input
autoCapitalize='none'
clearButtonMode='always'
onChangeText={text => this.setState({username:text})} />
</Item>
<Item floatingLabel>
<Label>Password</Label>
<Input
secureTextEntry={true}
clearButtonMode='always'
onChangeText={text => this.setState({password: text})} />
</Item>
<Button primary onPress={_ => this.checkLogin()}>
<Text style={styles.loginButtonText}>Login</Text>
</Button>
</Form>
</Content>
</Container>
);
}
}
You can use direct manipulation method.
Try passing ref to Input like ref={ (c) => this._input = c } and then calling the setNativeProps function this._input.setNativeProps({text:''})
I am also using react navigation and face similar issue.
I fixed as below :
import { NavigationEvents } from "react-navigation";
class ... {
onStartScreenFocus = ()>={
this.setState({
username: "", password: ""
})
}
render(){
return(
<View>
<NavigationEvents
onWillFocus={() => this.onStartScreenFocus()}
onDidBlur={() => this.onDidScreenBlur()} />
<View>
)
}
}
Is there a way to limit the textinput between a minimum length and maximum length. Suppose I want to limit the textinput length between 5 and 15, how do I do that ?
Consider adding the following code in your component:
<TextInput onTextChange={this.onTextChange} maxLength={15} ... />
<Button onPress={this.onPress} ... >Submit</Button>
onTextChange = text => {
this.setState({text : text});
}
onPress = () => {
const {text} = this.state;
if(text.length < 5) {
console.log('Your text is less than what is required.');
}
}
You can do it using redux-form, following below steps
we.js
module.exports = {
reqMsg: 'Required',
maxLength: max => value => value && value.length > max ? `Must be ${max} characters or less` : undefined,
minValue: min => value => value && value.length < min ? `Must be at least ${min} characters` : undefined,
};
validations.js
import { reqMsg, maxLength, minValue } from './we';
module.exports = {
//Validation
required: value => value ? undefined : reqMsg,
maxLength15: maxLength(15),
minValue5: minValue(5)
};
UserCreateForm.js
import React, { Component } from 'react';
import { Field, reduxForm } from 'redux-form';
import { Item, Input, CheckBox, ListItem, Spinner, Icon } from 'native-base';
import { required, minValue5, maxLength15} from './validations';
const renderField = ({ secureTextEntry, iconType, iconName, keyboardType, placeholder, meta: { touched, error, warning }, input: { onChange, ...restInput } }) => {
return (
<View>
<Item error={touched && !!error} rounded>
<Icon type={iconType} name={iconName} />
<Input secureTpickerStyleextEntry={JSON.parse(secureTextEntry)} keyboardType={keyboardType}
onChangeText={onChange} {...restInput} placeholder={placeholder} autoCapitalize='none'>
</Input>
{touched && !!error && <Icon name='close-circle' />}
</Item>
{touched && (!!error && <Text>{error}</Text>)}
</View>
);
};
class UserComponent extends Component {
render() {
return (
<Field name="Name" iconType="SimpleLineIcons" iconName="user" secureTextEntry="false" keyboardType="default" placeholder="FirstName LastName NikeName" component={renderField}
validate={[required, minValue5, maxLength15]}
/>
);
}
}
const UserCreateForm = reduxForm({
form: USER_CREATE_FORM // a unique identifier for this form
})(UserComponent);
export default UserCreateForm;
Previous comment is also Good, but it have more time and space complexity. For this overcome use this code .
<TextInput onTextChange={this.onTextChange} maxLength={15} ... />
onTextChange=()=>{
if (value ==^[a-zA-Z0-9]{5,15}$) {
alert( "Input is valid\n");
} else {
alert( "Input is invalid\n");
}
}
this code help me use this code, you can also reset the limit length, change the value
here 5 :- minimum
15:- maximum value.
I'm using DatePicker with ReduxForm. However, when I click submit button, the input value from Date Picker not pass to Redux Form.
I've search around and come across the answer from this (my code of renderDatePicker comes from there) but it still doesn't work for me.
My demo of the form on my Simulator:
Here's my code:
import React, { Component } from 'react';
import {
View, Text, Button, Icon, Container, Item,
Input, Label, Content, Form, Picker, Footer, DatePicker
} from 'native-base';
import { Field, reduxForm } from 'redux-form';
import { addTransactionItem } from '../redux/ActionCreators';
import moment from 'moment';
import { connect } from 'react-redux';
const mapDispatchToProps = dispatch => ({
addTransactionItem: (transactionItem) => dispatch(addTransactionItem(transactionItem))
})
class AddTransaction extends Component {
constructor(props) {
super(props);
this.renderField = this.renderField.bind(this);
this.submit = this.submit.bind(this);
this.renderDatePicker = this.renderDatePicker.bind(this);
}
renderDatePicker = ({ input, placeholder, defaultValue, meta: { touched, error }, label ,...custom }) => (
<Item>
<Label>{label}</Label>
<DatePicker {...input} {...custom} dateForm="MM/DD/YYYY"
onChange={(value) => input.onChange(value)}
autoOk={true}
selected={input.value ? moment(input.value) : null} />
{touched && error && <span>{error}</span>}
</Item>
);
submit = values => {
alert(`The values are ${JSON.stringify(values)}`)
const transactionItem = JSON.parse(JSON.stringify(values))
this.props.addTransactionItem(transactionItem);
const { navigate } = this.props.navigation;
navigate('Home');
}
render() {
const { handleSubmit } = this.props
return (
<>
<Form>
<Field keyboardType='default' label='Date' component={this.renderDatePicker} name="date" />
</Form>
<Button full light onPress={handleSubmit(this.submit)}>
<Text>Submit</Text>
</Button>
</>
);
}
}
AddTransaction = connect(null, mapDispatchToProps)(AddTransaction);
export default reduxForm({
form: 'addTransaction',
})(AddTransaction);
I think this is because you do not have "change" attribute in the Field component.
Try to add change function as shown below:
renderDatePicker = (
{
input,
placeholder,
defaultValue,
meta: { touched, error },
label ,
...custom,
change
}
) => (
<Item>
<Label>{label}</Label>
<DatePicker {...input} {...custom} dateForm="MM/DD/YYYY"
onDateChange={change}
autoOk={true}
selected={input.value ? moment(input.value) : null} />
{touched && error && <span>{error}</span>}
</Item>
);
render() {
const { handleSubmit, change } = this.props
return (
<>
<Form>
<Field
keyboardType='default'
label='Date'
component={this.renderDatePicker}
name="date"
change={change}
/>
</Form>
<Button full light onPress={handleSubmit(this.submit)}>
<Text>Submit</Text>
</Button>
</>
);
}
Hope it will work for you.
I see that there is no onChange listener for DatePicker. May be you should use onDateChange. http://docs.nativebase.io/Components.html#picker-input-headref
I have form with only one TextInput which is made using redux-form. I am checking (!meta.active) to show validation message, since focus is not changing even on button click from TextInput, meta.active is always true and validation message does not shows up.
export default function MTTextInput(props) {
const { input, label, meta, ...inputProps } = props;
var hasError = false;
if (meta.error !== undefined && meta.touched && !meta.active) {
hasError = true;
}
return (
<Item fixedLabel error={hasError} ><Label>{label}</Label>
<Input
{...inputProps}
onChangeText={input.onChange}
onBlur={input.onBlur}
onFocus={input.onFocus}
value={input.value}
/>
{hasError ? <Text>{meta.error}</Text> : <Text />}
</Item>
);
}
MTTextInput.propTypes = {
input: PropTypes.shape({
onBlur: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
onFocus: PropTypes.func.isRequired,
value: PropTypes.any.isRequired
}).isRequired,
meta: PropTypes.shape({
active: PropTypes.bool.isRequired,
error: PropTypes.string,
invalid: PropTypes.bool.isRequired,
pristine: PropTypes.bool.isRequired,
visited: PropTypes.bool.isRequired
}).isRequired
};
Perhaps you may want to switch from an <Input/> component to a <TextInput/> component. Here is a generic example that you can find here:
import React from 'react';
import { TextInput, View, Text } from 'react-native';
/**
* to be wrapped with redux-form Field component
*/
export default function MyTextInput(props) {
const { input, meta, ...inputProps } = props;
const formStates = ['active', 'autofilled', 'asyncValidating', 'dirty', 'invalid', 'pristine',
'submitting', 'touched', 'valid', 'visited'];
return (
<View>
<TextInput
{...inputProps}
onChangeText={input.onChange}
onBlur={input.onBlur}
onFocus={input.onFocus}
value={input.value}
/>
<Text>The { input.name} input is:</Text>
{
formStates.filter((state) => meta[state]).map((state) => {
return <Text key={state}> - { state }</Text>;
})
}
</View>
);
}
I am using native-base version 2.0.2, react-native version 0.40.0.
I am following a tutorial to make a GithHub Repo Search using native-base & integrate it with my functionalities to make something different, but all of the components are not properly loaded.
The Header & Footer example from the docs worked fine, but when I add things like searchbar rounded property or the icon classes, it does not get reflected.
When I add the button component I get the following error.
The Code in question is
var constants = require("../constants")
var React = require('react');
var ReactNative = require('react-native');
var t = require('tcomb-form-native');
var authenticate = require("../services/authenticate")
import { Container, Header, Title, Content, Footer, FooterTab, Button, Left, Right, Body,Picker,InputGroup,Icon,Input,Item } from 'native-base';
var {
AppRegistry,
AsyncStorage,
StyleSheet,
Text,
View,
TouchableHighlight,
Alert,
ListView,
Image,
} = ReactNative;
var Form = t.form.Form;
var getFeatured = require("../services/get_featured");
var getCategory = require("../services/get_categories");
var search = require("../services/search");
var Query;
const options = {
fields: {
category: {
order: 'asc',
nullOption: {value: '', text: 'Anything'}
}
}
}
class SplashPage extends React.Component{
constructor() {
super();
this.set_initial_state()
//this.set_categories();
//this.get_featured();
}
set_initial_state(){
this.state ={
hasResult: false,
hasCategory:false,
noResult: false,
isLoading: true,
isLoadingCat:true,
searchResult:false,
categories : [],
searchText:"",
searchCat:"",
filterCat:"",
articles:[],
}
}
set_categories() {
var par = this;
getCategory().then(function(catData){
par.setState({
isLoadingCat:false,
hasCategory:true,
categories:catData,
});
console.error("till here");
});
}
get_categories(){
const cats = this.state.categories;
const CatItems = cats.map((cat,i)=>{
return (
<Picker.item key={i} label={cat} value={cat} />
);
});
return CatItems;
}
openRecipe(data){
this.props.navigator.push({
id: 'RecipePage',
name: 'Recipe',
recipe_id:data.id,
});
}
get_featured(){
var par = this;
getFeatured().then(function(articles){
par.setState(
{
articles:articles,
hasResult: true,
isLoading:false,
searchResult:false,
}
)
}).catch(function(error) {
console.error(error);
});
}
perform_search(){
var value = this.state.searchText;
var par = this;
if(value){
par.setState(
{
hasResult: false,
isLoading:true,
}
)
var category = value.category;
var ingredient = value.ingredient.toString().split(',').join(' ');
search(ingredient,category).then((articles) => {
par.setState(
{
articles:articles,
hasResult: true,
isLoading:false,
searchResult:true
}
)
}).catch(function(error) {
console.error(error);
});
}
}
render() {
return (
<Header searchBar rounded>
<InputGroup>
<Icon name="ios-search" />
<Input placeholder="Search" value={this.state.searchText} onChangeText={(text) => this.setState({searchText:text})} onSubmitEditing={()=>this.search()}/>
<Picker
iosHeader="Select one"
mode="dropdown"
selectedValue={this.state.searchCat}
onValueChange={(cat) => this.setState({searchCat:cat})}>
<Item label="Cats" value="key0" />
<Item label="Cats2" value="key02" />
</Picker>
</InputGroup>
<Button transparent onPress={()=>this.search()}>Go</Button>
</Header>
);
}
}
module.exports = SplashPage;
I checked the dependencies and everything is installed.
I think you should wrap your code in
<Container>
<Content>
// your code
<Button>
<Text>Click Me! </Text>
</Button>
</Content>
</Container>
there's something wrong i think in your Button on onPress.
your code is onPress={()=>this.search()}
but i don't see search() method, i just find perform_search() method
if your problem came after you add <Button> tag, you can change this one :
<Button transparent onPress={()=>this.search()}>Go</Button>
to this one :
<Button transparent onPress={()=>this.perform_search()}><Text>Go</Text></Button>
and also this one : onSubmitEditing={()=>this.search()}
to this one : onSubmitEditing={()=>this.perform_search()}
and don't forget to import Text in native-base, hope can solve your problem :)