2

React/Redux newbie here.

I have implemented a management portal using Admin On Rest. In a Create component I have a Tabbed Form with TextInput components for various form fields. Included in those are firstName, lastName and userName. I need to compose the username from the first 4 characters of the firstName and the lastName as the user enters the name. In order to access the field values for firstName and lastName I have tried to decorate the Create component with a redux-form, but to no avail. I clearly don't understand how redux-form works. How can I accomplish the above within Admin On Rest? Here's one of my Create components:

export const HPCreate = (props, state) => (
  <Create {...props}>
    <TabbedForm validate={validateUserCreation}>
      <FormTab label="Personal Details">
        <TextInput source="userName" validate={[required, noSpace]} options={opts} autoComplete='off'/>
        <TextInput validate={[required]} source="password" autoComplete='off' options={opts}/>
        <TextInput label="First Name" validate={[required]} source="firstName" options={opts}/>
        <TextInput label="Last Name" validate={[required]} source="lastName" options={opts}/>
        <TextInput source="phone" validate={[required]} options={opts}/>
        <TextInput source="email" validate={[required, email]} options={opts}/>
        <TextInput source="address" options={opts}/>
        <TextInput source="city" options={opts}/>
        <TextInput source="state" options={opts}/>
        <TextInput source="zip" validate={[required]} options={opts}/>
      </FormTab>
      <FormTab label="Account Details">
        <ReferenceInput label="Job Title" source="jobTitle" reference="jobtitles" allowEmpty={true}
                        validation={{required: false}}>
          <AutocompleteInput optionText="name" optionValue="name" options={autocompleteOptions}/>
        </ReferenceInput>
        <ReferenceInput label="Designation" source="designation" reference="designations" allowEmpty={true}
                        validation={{required: false}}>
          <AutocompleteInput optionText="name" optionValue="name" options={autocompleteOptions}/>
        </ReferenceInput>
        <TextInput label="Employee ID" source="employeeId" options={opts}/>
        <ReferenceInput label="Practice Type" source="practiceType" reference="practicetypes" allowEmpty={true}
                        validation={{required: false}}>
          <AutocompleteInput optionText="name" optionValue="name" options={autocompleteOptions}/>
        </ReferenceInput>
        <ReferenceInput label="Primary Network *" source="primaryNetwork" reference="facilities"
                        allowEmpty={true} validate={[required]}>
          <AutocompleteInput optionText="name" optionValue="name" options={autocompleteOptions} validate={[required]}/>
        </ReferenceInput>
        <ReferenceArrayInput label="Secondary Networks" source="secondaryNetwork" reference="facilities"
                             allowEmpty={true}>
          <SelectArrayInput optionText="name" optionValue="name" options={opts}/>
        </ReferenceArrayInput>
        <SelectInput label="User Type" source="userType"
                     choices={[
                       {id: 'PATIENT', name: 'PATIENT'},
                       {id: 'PHYSICIAN', name: 'PHYSICIAN'},
                       {id: 'STAFF', name: 'STAFF'},
                       {id: 'FRONT DESK ADMIN', name: 'FRONT DESK ADMIN'},
                       {id: 'HOSPITAL ADMIN', name: 'HOSPITAL ADMIN'},
                       {id: 'HOSPITAL SUPERADMIN', name: 'HOSPITAL SUPERADMIN'},
                       {id: 'SALES TEAM', name: 'SALES TEAM'}
                     ]}
                     options={opts}
                     validate={[required]}
        />
        <DependentInput dependsOn="neverExpire" value={false}>
          <DateInput source="expirationDate" options={opts}/>
        </DependentInput>
        <BooleanInput label="Never expire?" source="neverExpire" defaultValue={true}/>
      </FormTab>

    </TabbedForm>
  </Create>

2 Answers2

0

Create a connected component using mapStateToProps. The form data is sitting in state and you can use that to write other fields as well.

class ConnectedUserNameInput extends Component {
  constructor() {
    // set your state as userName prop
  }
    componentWillRecieveProps = (nextProps) {
    this.props.input.value = nextProps.userName
   }
  render() {
    <span>{userName}</span>

  }
}

function mapStateToProps(state, props) {
   const userName = `${state.admin.form.firstName.slice(0,5)}${state.admin.form.lastName.slice(0,5)}`
   return userName
}

^^ will not work as value of the state needs the formName as part of the key something like state.admin.form{formName} . Console.log the state value to see what the name of your form is. AOR is using the Field component of Redux-Form to render every component. Looking at the docs for that will give you great clarity on whats happening under the hood.

Above is patchy code put together in a hurry to give you an idea of an approach I think will work. Feel free to ask questions as you face them.

kunal pareek
  • 1,285
  • 10
  • 21
0

Ok, thank you to kunal for your answer, but I found my solution before I ready yours and didn't have a chance to try your suggestion. I was able to solve my problem this way. First I decorate the Create component like so:

// Decorate with redux-form
HPCreate = reduxForm({
  form: 'record-form'  // a unique identifier for this form
})(HPCreate);

// Decorate with connect to read form values
const selector = formValueSelector('record-form'); // <-- same as form name
HPCreate = connect(
  state => {
    let {firstName, lastName} = selector(state, 'firstName', 'lastName');
    if (firstName) {
      firstName = firstName.substr(0, 4);
    }
    if (lastName) {
      lastName = lastName.substr(0, 4);
    }
    return {
      firstName,
      lastName,
      state
    };
  }
)(HPCreate);

Then I initialized the new connected props in my component:

const {
    firstName, lastName, change
  } = props;

Finally, I modified the firstName and lastName TextInput components (from above) like so using the redux-form method "change" to modify the form field value for userName:

<TextInput label="First Name" validate={[required]} source="firstName" options={opts}
                     onChange={(event, newValue, previousValue) => {
                       change('userName', `${newValue.substr(0,4).toLowerCase() || ''}${lastName ? lastName.substr(0,4).toLowerCase() : ''}`);
                     }}
          />

<TextInput label="Last Name" validate={[required]} source="lastName" options={opts}
                     onChange={(event, newValue, previousValue) => {
                       change('userName', `${firstName ? firstName.substr(0,4).toLowerCase() : ''}${newValue.substr(0,4).toLowerCase() || ''}`);
                     }}
          />

This modifies the form state for the userName field so that it will submit with the proper value.

If anyone has any improvements or corrections, please let me know how I could do better.

Thank you.