0

I am trying to render a custom input field, and not use the default one, as I need some extra elements surrounding my input

This is my component, PetalkInvitationModal. The other 2 are examples of components that I'm trying to hack together for rendering the actual input field. I've initially tried to use RenderInputField, but then I started building RenderInputModalField, so to be able to control the props manually

import React from 'react'
import {GenericActionOrCancelModal} from "../GenericActionOrCancelModal";
import {reduxForm, Field} from "redux-form";
import Datetime from 'react-datetime';


import WarningAlert from "./components/alerts";


export class PetalkInvitationModal extends GenericActionOrCancelModal {

    this.renderDateInputOutsideForm = this.renderDateInputOutsideForm.bind(this);
    this.renderDateInputField = this.renderDateInputField.bind(this);
    this.renderDateInputAsFormField = this.renderDateInputAsFormField.bind(this);
  }

  renderDateInputOutsideForm(options) {
    return <Datetime
      closeOnSelect={true}
      renderInput={this.renderDateInputField(options)}/>;
  }

  /**
   * @param {{id}, {label}, {name}, {required}} options
   */
  renderDateInputField(options) {
    return (props, openCalendar, closeCalendar)=> {
      return (
        <div className="form-group">
          <div className="form-label-group">
            <input
              className="form-control"
              {...props}/>
            <label htmlFor={options.id} onClick={openCalendar}>{options.label}</label>
          </div>
        </div>
      )
    }
  }

  renderDateInputAsFormField(props) {
    const {input, inputProps, meta: {touched, error}} = props;

    // I'm trying to pass all the callbacks that I get, down to my component
    // I tried calling the callbacks from props2, and from olderInput
    const RenderInputModalWrapper = (
      (props2) => <RenderInputModalField olderInput={input} {...props2}/>
    );

    return <Datetime {...input} {...inputProps} renderInput={RenderInputModalWrapper}/>
  }

  renderFields() {
    return (
      <div>

        {/*this doesn't work, sadly :( */}
        <Field
          name="option1"
          type="text"
          component={this.renderDateInputAsFormField}
          inputProps={{
            closeOnSelect: true
          }}
        />


        {/*this works...but it's not controlled by redux-form */}
        {this.renderDateInputOutsideForm({
          label: 'Erste Option (erforderlich)',
          name: 'option1',
        })}

      </div>
    )
  }
}

function validate(values) {
  //...
}


export function RenderInputField(field) {
  const {input, meta: {touched, error, valid}} = field;
  const error_message = touched && !valid ? error : "";

  return (
    <div className="form-group">
      <label htmlFor={field.htmlFor}>{field.label}</label>
      <input {...field.input}
             id={field.htmlFor}
             className={field.className}
             type={field.type ? field.type : "text"}
             autoFocus={field.autoFocus}
             placeholder={field.placeholder}
             readOnly={field.readOnly ? field.readOnly : false}
      />
    </div>
  )
}

export function RenderInputModalField(props) {    
  let extras = {};
  let {onChange, onBlur, onFocus, onDragStart, onDrop} = props;

  if(props.olderInput){
    // this is not good at all field doesn't respond to clicks now
    // onChange = (evt) => (props.olderInput.onChange(evt), onChange(evt))
    // onBlur = (evt) => (props.olderInput.onBlur(evt), onBlur(evt))
    // onFocus = (evt) => (props.olderInput.onFocus(evt), onFocus(evt))
    // onDragStart = (evt) => (props.olderInput.onDragStart(evt), onDragStart(evt))
    // onDrop = (evt) => (props.olderInput.onDrop(evt), onDrop(evt))

    // this is not good; does something on the second click. only changes the
    // field value the first time
    // onChange = (evt) => (onChange(evt), props.olderInput.onChange(evt))
    // onBlur = (evt) => (onBlur(evt), props.olderInput.onBlur(evt))
    // onFocus = (evt) => (onFocus(evt), props.olderInput.onFocus(evt))
    // onDragStart = (evt) => (onDragStart(evt), props.olderInput.onDragStart(evt))
    // onDrop = (evt) => (onDrop(evt), props.olderInput.onDrop(evt))


    // this also responds to open only on the second click.
    // it also updates the value only the first time
    // onChange = (evt) => onChange(evt)
    // onBlur = (evt) => (onBlur(evt))
    // onFocus = (evt) => (onFocus(evt))
    // onDragStart = (evt) => (onDragStart(evt))
    // onDrop = (evt) => (onDrop(evt))

    // this doesn't respond to the first click, and doesn't update anything
    // onChange = (evt) => ( props.olderInput.onChange(evt))
    // onBlur = (evt) => (props.olderInput.onBlur(evt))
    // onFocus = (evt) => (props.olderInput.onFocus(evt))
    // onDragStart = (evt) => (props.olderInput.onDragStart(evt))
    // onDrop = (evt) => (props.olderInput.onDrop(evt))
  }

  extras = {onChange, onBlur, onFocus, onDragStart, onDrop};




  return (
    <div className="form-group">
      <label htmlFor={props.htmlFor}>{props.label}</label>
      <input {...props}
             {...extras}
             id={props.htmlFor}
             className={props.className}
             type={props.type ? props.type : "text"}
             autoFocus={props.autoFocus}
             placeholder={props.placeholder}
             readOnly={!!props.readOnly}
      />
    </div>
  )
}


export default reduxForm({
  validate,
  form: 'PetalkInvitationModalForm'
})(PetalkInvitationModal)

So as you can see, I tried calling and passing all the callbacks I could, but obviously I'm missing something, and I spent a lot of time on this already.

Any ideas are welcome

[EDIT] Also, I need to mention that I did find this post https://github.com/YouCanBookMe/react-datetime/issues/552#issuecomment-392226610 so I know how to render a Datetime component inside a Field.

<Field
    name="arrivalDate"
    component={CustomDatetimePicker}
    inputProps={{
      timeFormat: false,
      closeOnSelect: true,
      dateFormat: 'DD/MM/YYYY',
    }}
/>


const CustomDatetimePicker = props => {
  const {
    input,
    inputProps,
    meta: { touched, error }
  } = props;
  return (
     <Datetime {...input} {...inputProps} />
  );
};

I have also read the documentation of react-datetime where I'm shown how to render a customized input field inside a Datetime component: https://github.com/YouCanBookMe/react-datetime#customize-the-input-appearance

var MyDTPicker = React.createClass({
    render: function(){
        return <Datetime renderInput={ this.renderInput } />;
    },
    renderInput: function( props, openCalendar, closeCalendar ){
        function clear(){
            props.onChange({target: {value: ''}});
        }
        return (
            <div>
                <input {...props} />
                <button onClick={openCalendar}>open calendar</button>
                <button onClick={closeCalendar}>close calendar</button>
                <button onClick={clear}>clear</button>
            </div>
        );
    },
});

I'm just too noob at react to be able to put those 2 together

vlad-ardelean
  • 7,480
  • 15
  • 80
  • 124
  • Do you have to use react-datetime or are you free to choose something else? Like https://github.com/Hacker0x01/react-datepicker? – Mrchief Oct 13 '18 at 18:51
  • I'm free to choose anything. I also tried that one, but it looks uglier, and I'm a worse designer than I'm a coder :P I found a workaround btw, which was to take the datetime field out of the form, and manage its validation myself. It's bad, but it worked. I am still waiting for a proper solution though... I'm sure there is someone there who understands react better than me. Unfortunately, I'm pressed by a deadline, so I had to move on, otherwise I'd have tried to get to the bottom of it myself. – vlad-ardelean Oct 14 '18 at 06:47
  • Working with redux-form, I often find this to be a barrier of entry - not only you need to figure out how to use a 3rd party control, you also need to figure out how to make it work with redux-form. I don't know anything about react-datetime and unfortunately, I don't have enough time to understand it. I simply asked since I've used react-datepicker with redux-form, so I can offer more ready assistance with that one. Anyway, at least you have a workaround. Good luck! – Mrchief Oct 15 '18 at 01:11

0 Answers0