Monday 25 January 2016

Auto complete field with Rails and React.js

For the impatience, all the code is here.

Background: I have more than 2500 customers in the app that I'm developing, so I want the ajax-auto-complete functionality in the field "customer name" when I want to create a new appointment, this way the final user can find the user easily. I coded the next React component:

// file: app/assets/javascripts/components/appointment_form.jsx

var MyList = React.createClass({
  getInitialState: function() {
    return {
       childSelectValue: undefined,
       getOptions: [],
       url: '/appointments/get_data',  // add to your routes.rb 
       options: []
      }
    },
    changeHandler: function(e) {
        console.log('In changeHandler method');
        var tmp = this.getData(e);
        this.forceUpdate();
    },
    getData: function(e) {
      e.preventDefault();
      ovalue = e.target.value // first character typed for the user 
      console.log(ovalue);
      link = {url: this.state.url, ovalue: ovalue};
      $.ajax({
        type: 'POST',
        data: link,
        url: this.state.url,
        headers: {'X-CSRFToken': Cookies.get('csrf-token')}, // rails asks for this
        cache: false,
        dataType: 'json',
        success: function(data) {
          if (data != undefined) {
            console.log( ">>>>>> Line 108 data >>>>>>>"+JSON.stringify(data));
            this.setOptions(data);
          }
        }.bind(this),
        error: function(xhr, status, err) {
          console.error(this.state.url, status, err.toString());
        }.bind(this)
      });
    },
    setOptions: function(data) {
      var tempo = [];
      for (var i = 0; i < data.length; i++) {
        var option = data[i];
        var tmp = ;
        tempo.push(tmp); // add the option
     }
     console.log( ">>>>>> Line 127 data >>>>>>>"+JSON.stringify(tempo));
     this.setState({options: tempo});
    },
    render: function() {
        return (
          <span>
            <input type="text" className="form-control" onChange={this.changeHandler} placeholder="Owner" list="slist" name="owner" />
            <datalist id="slist">{this.state.options}</datalist>
          </span>
        )
    }
});

Now include your MyList component inside the form tag:

// file:  app/assets/javascripts/components/appointment_form.jsx (continuation)

render: function() {
    return React.DOM.form({
      className: 'form-inline',
      onSubmit: this.handleSubmit
    },
    ,
    React.DOM.button({
        type: 'submit',
        className: 'button-primary',
    }, 'Create appointment'));
  });
  

In Appointments controller:

  # POST /appointments/get_data
  def get_data
    owner = params[:ovalue]  # ovalue cames from react
    results = User.where("lname ~ '#{owner}' AND group_id=2").select(:id, :fname, :lname)
    logger.debug "### get_data in appointments #####################>>>> #{params.to_json} "
    users = results.map do |r|
      {value: r.id, name: "#{r.lname} #{r.fname}" }
    end
    return render json: users.to_json  # send this back to react
  end

Results:

No comments: