2016-06-24 13 views
6

Sto provando a creare un modulo di registrazione a più fasi utilizzando React e Redux.Immissione incontrollata di testo di tipo da controllare avviso

Il componente principale è il seguente:

import React, {PropTypes} from 'react'; 
import {connect} from 'react-redux'; 
import {bindActionCreators} from 'redux'; 
import * as actionCreators from '../../actions/actionCreators'; 
import countries from '../../data/countries'; 

import RegistrationFormStepOne from './registrationFormStepOne'; 
import RegistrationFormStepTwo from './registrationFormStepTwo'; 
import RegistrationFormStepThree from './registrationFormStepThree'; 
import RegistrationFormStepFour from './registrationFormStepFour'; 

class RegistrationPage extends React.Component { 
    constructor(props) { 
     super(props); 

     this.state = { 
      user: Object.assign({}, this.props.userData), 
      fileNames: {}, 
      selectedFile: {}, 
      icons: { 
       idCard: 'upload', 
       statuten: 'upload', 
       blankLetterhead: 'upload', 
       companyPhoto: 'upload' 
      }, 
      step: 1, 
      errors: {} 
     }; 

     this.setUser = this.setUser.bind(this); 
     this.onButtonClick = this.onButtonClick.bind(this); 
     this.onButtonPreviousClick = this.onButtonPreviousClick.bind(this); 
     this.changeCheckboxState = this.changeCheckboxState.bind(this); 
     this.onFileChange = this.onFileChange.bind(this); 
     this.routerWillLeave = this.routerWillLeave.bind(this); 
    } 

    componentDidMount() { 
     this.context.router.setRouteLeaveHook(this.props.route, this.routerWillLeave); 
    } 

    routerWillLeave(nextLocation) { 
     if (this.state.step > 1) { 
      this.setState({step: this.state.step - 1}); 
      return false; 
     } 
    } 

    getCountries(){ 
     return countries; 
    } 


    setUser(event) { 
     const field = event.target.name; 
     const value = event.target.value; 

     let user = this.state.user; 
     user[field] = value; 
     this.setState({user: user}); 

    } 

    validation(){ 
     const user = this.state.user; 
     const languageReg = this.props.currentLanguage.default.registrationPage; 
     let formIsValid = true; 
     let errors = {}; 

     if(!user.companyName){ 
      formIsValid = false; 
      errors.companyName = languageReg.companyNameEmpty; 
     } 

     if(!user.btwNumber){ 
      formIsValid = false; 
      errors.btwNumber = languageReg.btwNumberEmpty; 
     } 

     if(!user.address){ 
      formIsValid = false; 
      errors.address = languageReg.addressEmpty; 
     } 

     if(!user.country){ 
      formIsValid = false; 
      errors.country = languageReg.countryEmpty; 
     } 

     if(!user.zipcode){ 
      formIsValid = false; 
      errors.zipcode = languageReg.zipcodeEmpty; 
     } 

     if(!user.place){ 
      formIsValid = false; 
      errors.place = languageReg.placeEmpty; 
     } 


     if(!user.firstName){ 
      formIsValid = false; 
      errors.firstName = languageReg.firstnameEmpty; 
     } 



     this.setState({errors: errors}); 
     return formIsValid; 
    } 

    onFileChange(name, event) { 
     event.preventDefault(); 
     let file = event.target.value; 

     let filename = file.split('\\').pop(); //We get only the name of the file 
     let filenameWithoutExtension = filename.replace(/\.[^/.]+$/, ""); //We get the name of the file without extension 

     let user = this.state.user; 
     let fileNames = this.state.fileNames; 
     let selectedFile = this.state.selectedFile; 
     let icons = this.state.icons; 

     switch (name.btnName) { 
      case "idCard" : 
       fileNames[name.btnName] = filenameWithoutExtension; 
       //Check if file is selected 
       if(file){ 
        selectedFile[name.btnName] = "fileSelected"; 
        user["idCardFile"] = true; 
        icons["idCard"] = "check"; 
       }else{ 
        selectedFile[name.btnName] = ""; 
        user["idCardFile"] = false; 
        icons["idCard"] = "upload"; 
       } 
       break; 
      case "statuten" : 
       fileNames[name.btnName] = filenameWithoutExtension; 

       //Check if file is selected 
       if(file){ 
        selectedFile[name.btnName] = "fileSelected"; 
        user["statutenFile"] = true; 
        icons["statuten"] = "check"; 
       }else{ 
        selectedFile[name.btnName] = ""; 
        user["statutenFile"] = false; 
        icons["statuten"] = "upload"; 
       } 
       break; 
      case "blankLetterhead" : 
       fileNames[name.btnName] = filenameWithoutExtension; 

       //Check if file is selected 
       if(file){ 
        selectedFile[name.btnName] = "fileSelected"; 
        user["blankLetterheadFile"] = true; 
        icons["blankLetterhead"] = "check"; 
       }else{ 
        selectedFile[name.btnName] = ""; 
        user["blankLetterheadFile"] = false; 
        icons["blankLetterhead"] = "upload"; 
       } 
       break; 
      default: 
       fileNames[name.btnName] = filenameWithoutExtension; 
       //Check if file is selected 
       if(file){ 
        selectedFile[name.btnName] = "fileSelected"; 
        user["companyPhotoFile"] = true; 
        icons["companyPhoto"] = "check"; 
       }else{ 
        selectedFile[name.btnName] = ""; 
        user["companyPhotoFile"] = false; 
        icons["companyPhoto"] = "upload"; 
       } 
     } 

     this.setState({user: user, fileNames: fileNames, selectedFile: selectedFile, icons: icons}); 
    } 

    changeCheckboxState(event) { 
     let chcName = event.target.name; 
     let user = this.state.user; 

     switch (chcName) { 
      case "chcEmailNotificationsYes": 
       user["emailNotifications"] = event.target.checked; 
       break; 
      case "chcEmailNotificationsNo": 
       user["emailNotifications"] = !event.target.checked; 
       break; 
      case "chcTerms": 
       if(typeof this.state.user.terms === "undefined"){ 
        user["terms"] = false; 
       }else{ 
        user["terms"] = !this.state.user.terms; 
       } 

       break; 
      case "chcSmsYes": 
       user["smsNotifications"] = event.target.checked; 
       break; 
      default: 
       user["smsNotifications"] = !event.target.checked; 
     } 
     this.setState({user: user}); 
     this.props.actions.userRegistration(this.state.user); 
    } 

    onButtonClick(name, event) { 
     event.preventDefault(); 
     this.props.actions.userRegistration(this.state.user); 
     switch (name) { 
      case "stepFourConfirmation": 
       this.setState({step: 1}); 
       break; 
      case "stepTwoNext": 
       this.setState({step: 3}); 
       break; 
      case "stepThreeFinish": 
       this.setState({step: 4}); 
       break; 
      default: 
       if(this.validation()) { 
        this.setState({step: 2}); 
       } 
     } 
    } 


    onButtonPreviousClick(){ 
     this.setState({step: this.state.step - 1}); 
    } 

    render() { 
     const languageReg = this.props.currentLanguage.default.registrationPage; 

     console.log(this.state.user); 
     let formStep = ''; 
     let step = this.state.step; 
     switch (step) { 
      case 1: 
       formStep = (<RegistrationFormStepOne user={this.props.userData} 
                onChange={this.setUser} 
                onButtonClick={this.onButtonClick} 
                countries={this.getCountries(countries)} 
                errors={this.state.errors} 
                step={step}/>); 
       break; 
      case 2: 
       formStep = (<RegistrationFormStepTwo user={this.props.userData} 
                onChange={this.setUser} 
                onButtonClick={this.onButtonClick} 
                onButtonPreviousClick={this.onButtonPreviousClick} 
                errors={this.state.errors}/>); 
       break; 
      case 3: 
       formStep = (<RegistrationFormStepThree user={this.props.userData} 
                 onFileChange={this.onFileChange} 
                 onButtonClick={this.onButtonClick} 
                 onButtonPreviousClick={this.onButtonPreviousClick} 
                 errors={this.state.errors} 
                 fileNames={this.state.fileNames} 
                 icons={this.state.icons} 
                 fileChosen={this.state.selectedFile}/>); 
       break; 

      default: 
       formStep = (<RegistrationFormStepFour user={this.props.userData} 
                 onChange={this.setUser} 
                 onChangeCheckboxState={this.changeCheckboxState} 
                 onButtonClick={this.onButtonClick} 
                 onButtonPreviousClick={this.onButtonPreviousClick} 
                 errors={this.state.errors}/>); 
     } 

     return (
      <div className="sidebar-menu-container" id="sidebar-menu-container"> 

       <div className="sidebar-menu-push"> 

        <div className="sidebar-menu-overlay"></div> 

        <div className="sidebar-menu-inner"> 
         <div className="contact-form"> 
          <div className="container"> 
           <div className="row"> 
            <div className="col-md-10 col-md-offset-1 col-md-offset-right-1"> 
             {React.cloneElement(formStep, {currentLanguage: languageReg})} 
            </div> 
           </div> 
          </div> 
         </div> 
        </div> 
       </div> 
      </div> 
     ); 
    } 
} 

RegistrationPage.contextTypes = { 
    router: PropTypes.object 
}; 

function mapStateToProps(state, ownProps) { 
    return { 
     userData: state.userRegistrationReducer 
    }; 
} 

function mapDispatchToProps(dispatch) { 
    return { 
     actions: bindActionCreators(actionCreators, dispatch) 
    }; 
} 

export default connect(mapStateToProps, mapDispatchToProps)(RegistrationPage); 

Il primo componente passo è la seguente

import React from 'react'; 
import Button from '../../common/formElements/button'; 
import RegistrationFormHeader from './registrationFormHeader'; 
import TextInput from '../../common/formElements/textInput'; 
import SelectInput from '../../common/formElements/selectInput'; 

const RegistrationFormStepOne = ({user, onChange, onButtonClick, errors, currentLanguage, countries}) => { 

    const language = currentLanguage; 

    return (
    <div className="contact_form"> 
     <form role="form" action="" method="post" id="contact_form"> 
     <div className="row"> 
      <RegistrationFormHeader activeTab={0} currentLanguage={language}/> 
      <div className="hideOnBigScreens descBox"> 
      <div className="headerTitle">{language.businessInfoConfig}</div> 
      <div className="titleDesc">{language.businessBoxDesc}</div> 
      </div> 
      <div className="col-lg-12"> 
      <h6 className="registrationFormDesc col-lg-10 col-lg-offset-1 col-lg-offset-right-2 col-xs-12"> 
       {language.businessDesc} 
      </h6> 
      <div className="clearfix"></div> 
      <div className="col-sm-6"> 
       <TextInput 
       type="text" 
       name="companyName" 
       label={language.companyNameLabel} 
       labelClass="control-label" 
       placeholder={language.companyNameLabel} 
       className="templateInput" 
       id="company" 
       onChange={onChange} 
       value={user.companyName} 
       errors={errors.companyName} 
       /> 
      </div> 
      <div className="col-sm-6"> 
       <TextInput 
       type="text" 
       name="btwNumber" 
       label={language.vatNumberLabel} 
       placeholder={language.vatNumberLabel} 
       className="templateInput" 
       id="btwNumber" 
       onChange={onChange} 
       value={user.btwNumber} 
       errors={errors.btwNumber} 
       /> 
      </div> 

      <div className="col-sm-12" style={{marginBottom: 25}}> 
       <TextInput 
       type="text" 
       name="address" 
       label={language.addressLabel} 
       placeholder={language.address1Placeholder} 
       className="templateInput" 
       id="address" 
       onChange={onChange} 
       value={user.address} 
       errors={errors.address} 
       /> 
      </div> 

      <div className="col-sm-12" style={{marginBottom: 25}}> 
       <TextInput 
       type="text" 
       name="address1" 
       placeholder={language.address2Placeholder} 
       className="templateInput" 
       id="address" 
       onChange={onChange} 
       value={user.address1} 
       errors="" 
       /> 
      </div> 

      <div className="col-sm-12"> 
       <TextInput 
       type="text" 
       name="address2" 
       placeholder={language.address3Placeholder} 
       className="templateInput" 
       id="address" 
       onChange={onChange} 
       value={user.address2} 
       errors="" 
       /> 
      </div> 

       <div className="col-sm-3"> 
       <SelectInput name="country" 
          label={language.selectCountryLabel} 
          onChange={onChange} 
          options={countries} 
          className="templateInput selectField" 
          defaultOption={language.selectCountry} 
          value={user.country} 
          errors={errors.country} 
          /> 
       </div> 

      <div className="col-sm-3"> 

       <TextInput 
       type="text" 
       name="zipcode" 
       label={language.zipcodeLabel} 
       placeholder={language.zipcodeLabel} 
       className="templateInput" 
       id="zipcode" 
       onChange={onChange} 
       value={user.zipcode} 
       errors={errors.zipcode} 
       /> 
      </div> 
      <div className="col-sm-6"> 
       <TextInput 
       type="text" 
       name="place" 
       label={language.placeLabel} 
       placeholder={language.placeLabel} 
       className="templateInput" 
       id="place" 
       onChange={onChange} 
       value={user.place} 
       errors={errors.place} 
       /> 
      </div> 
      </div> 
      <div className="clearfix"></div> 
      <div className="col-lg-12" style={{marginLeft: 15, marginTop: 30}}> 
      <Button onClick={onButtonClick.bind(this)} 
        name="stepOneNext" 
        value={language.btnNext} 
        icon="arrow-circle-right" 
        style={{margin: '0 auto 60px'}}/> 
      </div> 
     </div> 
     </form> 
    </div> 
); 
}; 

export default RegistrationFormStepOne; 

provo ad aggiungere qualche semplice validazione e ho aggiunto la funzione di validazione nella mia componente principale e poi controllo il clic del pulsante se il valore restituito è vero o falso. Se è vero, allora imposto lo stato del passo su un valore appropriato. E funziona se convalido solo i campi modulo del primo passaggio, ma quando provo a convalidare anche uno o più campi modulo del passaggio successivo (ora sto provando a convalidare anche il primo campo del secondo passaggio)

if(!user.firstName){ 
     formIsValid = false; 
     errors.firstName = languageReg.firstnameEmpty; 
    } 

ottengo di

Attenzione: TextInput sta cambiando un ingresso incontrollato di tipo testo da controllare. Gli elementi di input non devono passare da incontrollati a controllati (o viceversa). Decidere tra l'uso di un elemento di input controllato o non controllato per la durata del componente.

Senza la funzione di convalida funziona tutto perfetto.

Qualche consiglio?

EDIT

import React, {propTypes} from 'react'; 
import _ from 'lodash'; 

const TextInput = ({errors, style, name, labelClass, label, className, placeholder, id, value, onChange, type}) => { 
    let wrapperClass = "form-group"; 

    if (errors) { 
    wrapperClass += " " + "inputHasError"; 
    } 

    return (
    <div className={wrapperClass} style={style}> 
     <label htmlFor={name} className={labelClass}>{label}</label> 
     <input type={type} 
      className={className} 
      placeholder={placeholder} 
      name={name} 
      id={id} 
      value={value} 
      style={{}} 
      onChange={onChange} 
     /> 
     <div className="errorBox">{errors}</div> 
    </div> 
); 
}; 

TextInput.propTypes = { 
    name: React.PropTypes.string.isRequired, 
    label: React.PropTypes.string, 
    onChange: React.PropTypes.func.isRequired, 
    type: React.PropTypes.string.isRequired, 
    id: React.PropTypes.string, 
    style: React.PropTypes.object, 
    placeholder: React.PropTypes.string, 
    className: React.PropTypes.string, 
    labelClass: React.PropTypes.string, 
    value: React.PropTypes.string, 
    errors: React.PropTypes.string 
}; 

export default TextInput; 

Questo è seconda componente passo:

import React from 'react'; 
import Button from '../../common/formElements/button'; 
import RegistrationFormHeader from './registrationFormHeader'; 
import TextInput from '../../common/formElements/textInput'; 


const RegistrationFormStepTwo = ({user, onChange, onButtonClick, onButtonPreviousClick, errors, currentLanguage}) => { 
    const language = currentLanguage; 

    return (
     <div className="contact_form"> 
      <form role="form" action="" method="post" id="contact_form"> 
       <div className="row"> 
        <RegistrationFormHeader activeTab={1} currentLanguage={language}/> 
        <div className="hideOnBigScreens descBox"> 
         <div className="headerTitle">{language.personalInfoConfig}</div> 
         <div className="titleDesc">{language.personalBoxDesc}</div> 
        </div> 
        <div className="col-lg-12"> 
         <h6 className="registrationFormDesc col-lg-10 col-lg-offset-1 col-lg-offset-right-2 col-xs-12"> 
          {language.personalDesc} 
         </h6> 
         <div className="col-lg-6 col-md-6 col-sm-6 col-xs-12"> 
          <TextInput 
           type="text" 
           name="firstName" 
           label={language.firsnameLabel} 
           placeholder={language.firsnameLabel} 
           className="templateInput" 
           id="name" 
           onChange={onChange} 
           value={user.firstName} 
           errors={errors.firstName} 
          /> 
         </div> 
         <div className="col-lg-6 col-md-6 col-sm-6 col-xs-12"> 
          <TextInput 
           type="text" 
           name="lastName" 
           label={language.lastnameLabel} 
           placeholder={language.lastnameLabel} 
           className="templateInput" 
           id="name" 
           onChange={onChange} 
           value={user.lastName} 
           errors={errors.lastName} 
          /> 
         </div> 

         <div className="col-lg-6 col-md-6 col-sm-6 col-xs-12"> 
          <TextInput 
           type="text" 
           name="phone" 
           label={language.phoneLabel} 
           placeholder={language.phoneLabel} 
           className="templateInput" 
           id="phone" 
           onChange={onChange} 
           value={user.phone} 
           errors={errors.phone} 

          /> 
         </div> 

         <div className="col-lg-6 col-md-6 col-sm-6 col-xs-12"> 
          <TextInput 
           type="text" 
           name="mobilePhone" 
           label={language.mobileLabel} 
           placeholder={language.mobileLabel} 
           className="templateInput" 
           id="phone" 
           style={{}} 
           onChange={onChange} 
           value={user.mobilePhone} 
           errors={errors.mobilePhone} 
          /> 
         </div> 
         <div className="clearfix"></div> 

         <div className="col-lg-12 col-md-12 col-sm-12 col-xs-12"> 
          <TextInput 
           type="text" 
           name="email" 
           id="email" 
           label={language.emailLabel} 
           placeholder={language.emailLabel} 
           className="templateInput" 
           style={{}} 
           onChange={onChange} 
           value={user.email} 
           errors={errors.email} 
          /> 
         </div> 

         <div className="col-lg-12 col-md-12 col-sm-12 col-xs-12"> 
          <TextInput 
           type="text" 
           name="userName" 
           label={language.usernameLabel} 
           placeholder={language.usernameLabel} 
           className="templateInput" 
           id="name" 
           onChange={onChange} 
           value={user.userName} 
           errors={errors.userName} 
          /> 
         </div> 

         <div className="col-lg-6 col-md-6 col-sm-6 col-xs-12"> 
          <TextInput 
           type="password" 
           name="password" 
           label={language.passwordLabel} 
           placeholder={language.passwordLabel} 
           className="templateInput" 
           id="password" 
           onChange={onChange} 
           value={user.password} 
           errors={errors.password} 
          /> 
         </div> 
         <div className="col-lg-6 col-md-6 col-sm-6 col-xs-12"> 
          <TextInput 
           type="password" 
           name="confirmPassword" 
           label={language.passwordConfirmLabel} 
           placeholder={language.passwordConfirmLabel} 
           className="templateInput" 
           id="password" 
           onChange={onChange} 
           value={user.confirmPassword} 
           errors={errors.confirmPassword} 
          /> 
         </div> 

        </div> 
        <div className="clearfix"></div> 
        <div className="col-lg-6 col-xs-6" style={{marginTop: 30}}> 
         <Button onClick={onButtonPreviousClick} 
           name="btnPrevious" 
           value={language.btnPrevious} 
           icon="arrow-circle-left" 
           style={{marginRight: 10, float: 'right'}}/> 
        </div> 
        <div className="col-lg-6 col-xs-6" style={{marginTop: 30}}> 
         <Button onClick={onButtonClick} name="stepTwoNext" value={language.btnNext} 
           icon="arrow-circle-right" style={{marginLeft: 10, float: 'left'}}/> 
        </div> 
       </div> 
      </form> 
     </div> 

    ); 
}; 

export default RegistrationFormStepTwo; 
+0

Che cos'è TextInput? –

risposta

15

Questo è il motivo per cui esiste l'avvertimento: Quando il valore è specificato come indefinita, Reagire non ha alcun modo di sapere se inteso a rendere un componente con un valore vuoto o se si intendeva che il componente non fosse controllato. È una fonte di bug.

È possibile eseguire un controllo nullo/non definito prima di passare il valore all'ingresso.

a source

+0

Ma perché non ricevo questo avviso senza la funzione di convalida? La funzione di validazione non fa nulla con i valori del campo. – Boky

+0

@Boky puoi fornire un repo? hai scritto sul "secondo passo", ma non ho visto quel componente –

+0

È molto simile al primo passo. Ho aggiornato la mia domanda. Se aggiungo qualcosa come 'if (value == null || typeof value ==" undefined ") { fieldValue =" "; } else { fieldValue = value; } 'Non ricevo alcun avvertimento ma non si passa al secondo passaggio. Se rimuovo la funzione di convalida funziona perfettamente. – Boky

1

@Kokovin Vladislav è giusto. Per mettere questo in codice, è possibile farlo in tutti i vostri input value s:

<TextInput 
    // your other code 
    value={user.firstName || ''} 
/> 

Cioè, se non trovate il valore del nome di battesimo, poi dare un valore vuoto.