Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chip - Javascript Plugin - autocomplete : how to update state variable #1117

Closed
Louvivien opened this issue Apr 30, 2020 · 10 comments
Closed

Comments

@Louvivien
Copy link

Louvivien commented Apr 30, 2020

Hi,
I would like to update a state variable array but I can't figure out how to update on change.
There is not event linked to the Chip.
I have want to change the array "countries", but when I try to link it with the React-materialize Chip, it does not work.

How can I get the event from the chip ? Can you help ?
Thank you

Below is my code also available in CodeSandbox

import React from "react";
import ReactDOM from "react-dom";
import { Icon, Chip} from 'react-materialize';
import 'materialize-css';


    class App extends React.Component {
      constructor() {
        super();
        this.state = {
          name: "Venom",
          countries: [{ name: 'France' }, { name: 'Germany' }],
        };
      }
      handleAddCountry = (e) => {
        console.log("Chip :")
        console.log(e.target.name)
        this.setState({ countries: this.state.countries.concat([{ name: e.target.value }]) });
      }
      handleAddFrance = (e) => {
        console.log("Button:")
        console.log(e.target.value)
        this.setState({ countries: this.state.countries.concat([{ name: e.target.value }]) });
      }
      render() {
        const { countries} = this.state
        return (
        <div>
              <div>
                <h1>{this.state.name}</h1>
              </div>
         
            <div>
                <Chip
                        onChange={ this.handleAddCountry } 
                        close={false}
                        closeIcon={<Icon className="close">close</Icon>}
                        options={{
                        placeholder: 'saisir un territoire',
                        secondaryPlaceholder: '+territoire',
                        autocompleteOptions: {
                        data: {
                        '	France métropolitaine	'	:	null,
                        '	DOM - TOM	'	:	null,
                        '	DOM	'	:	null,
                        '	Afghanistan	'	:	null,
                        },
                        limit: Infinity,
                        minLength: 1,
                        onAutocomplete: function noRefCheck(){}
                        }
                        }}
                />
            </div>
            <button type="button" onClick={this.handleAddFrance} value="France" className="small">Add France</button>
                <br></br>    
                {countries.map(country => <div>{country.name}</div>)}
          </div>
        );
      }
    }
    const rootElement = document.getElementById("root");
    ReactDOM.render(
      <React.StrictMode>
        <App />
      </React.StrictMode>,
      rootElement

);
@alextrastero
Copy link
Member

alextrastero commented May 3, 2020

Can you try onAutocomplete prop?
<Chip options={{autocompleteOptions: { onAutocomplete: someFn } }} ...

See what console logs on someFn

@alextrastero
Copy link
Member

or

    <Chip
      options={{
        onChipAdd: someFn,

@alextrastero
Copy link
Member

But yes, Chip needs to be updated with new methods from https://materializecss.com/chips.html and updated proptypes

@Louvivien
Copy link
Author

Hi, Thank you for your reply.

It logs undefined. Nothing is returned for e.target.value

Below is my code and you can run it on Codesandbox :

import React from "react";
import ReactDOM from "react-dom";
import { Icon, Chip } from "react-materialize";
import "materialize-css";

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      countries: [{ name: "France" }, { name: "Germany" }],
      hashTag: []
    };
  }

  //test 1 & 2 function

  handleAddCountry = e => {
    console.log("Chip :");
    var test = console.log(e.target);
    this.setState({
      countries: this.state.countries.concat([{ name: e.target.value }])
    });

    //this.setState({
      //countries: this.state.countries.concat([{ name: e.target }])
    //});
  };

  

  // Button

  handleAddFrance = e => {
    console.log("Button:");
    console.log(e.target.value);
    this.setState({
      countries: this.state.countries.concat([{ name: e.target.value }])
    });
  };

  render() {
    const { countries, test } = this.state;

    return (
      <div>
        <div>
          <p>Chip 1 test - onChipAdd</p>
          {/*  <Chip
      options={{
        onChipAdd: someFn,} */}


          <Chip
            close={false}
            closeIcon={<Icon className="close">close</Icon>}
            options={{
              onChipAdd: this.handleAddCountry,
              placeholder: "saisir un territoire",
              secondaryPlaceholder: "+territoire",
              autocompleteOptions: {
                data: {
                  "	France métropolitaine	": null,
                  "	DOM - TOM	": null,
                  "	DOM	": null,
                  "	Afghanistan	": null
                },
                limit: Infinity,
                minLength: 1,
                onAutocomplete: function noRefCheck() {}
              },
            }}
          />
        </div>


        <p>Consol Log: </p>
        <br />

        
          <div>{test}</div>
        
        
        <hr />

        <p>Chip 2 test - autocompleteOptions</p>
        {/* <Chip options={{autocompleteOptions: { onAutocomplete: someFn } }} */}


        <div>
          <Chip
            countries={this.state.countries}
            onSubmit={value => this.addCountry(value)}
            onRemove={index => this.removeCountry(index)}
            close={false}
            closeIcon={<Icon className="close">close</Icon>}
            options={{
              placeholder: "saisir un territoire",
              secondaryPlaceholder: "+territoire",
              autocompleteOptions: {
                onAutocomplete: this.handleAddCountry,
                data: {
                  "	France métropolitaine	": null,
                  "	DOM - TOM	": null,
                  "	DOM	": null,
                  "	Afghanistan	": null
                },
                limit: Infinity,
                minLength: 1,
                onAutocomplete: function noRefCheck() {}
              }
            }}
          />
        </div>
          <p>Consol Log: </p>
        <br />

        
          <div>{test}</div>
        

        <hr />

        <p>Button test</p>

        <button
          type="button"
          onClick={this.handleAddFrance}
          value="France"
          className="small"
        >
          Add France
        </button>

        <hr />

        <p>Variable result : </p>
        <br />

        {countries.map(country => (
          <div>{country.name}</div>
        ))}
        <br />
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  rootElement
);


@alextrastero
Copy link
Member

alextrastero commented May 4, 2020

Ok, I managed to get to something, but it's incomplete:

foo is an instance of CASH

class App extends React.Component {
  handleAddCountry = (foo) => {
    console.log(foo.text())
  };
  
  render() {
    return (
      <Chip
      close={false}
      options={{
        onChipAdd: this.handleAddCountry,
        autocompleteOptions: {
          data: {
            "	France métropolitaine	": null,
            "	DOM - TOM	": null,
            "	DOM	": null,
            "	Afghanistan	": null
          }
        }
      }}
      />
      )
    }
  }

@alextrastero
Copy link
Member

But yes, ideally Chip would have 3 new props, onChipAdd, onChipSelect and onChipRemove where the argument is just the text value from the event.

@Louvivien
Copy link
Author

Louvivien commented May 4, 2020

Thanks ! it works if I want to add a value to the array but then I can't see the chip anymore and can not delete it

How can I do the same function for onChipRemove? Do I need to write a onChipSelect function to display the chips and then write a onChipRemove function to remove it ?

Here is the code and the Codesandbox

import React from "react";
import ReactDOM from "react-dom";
import { Icon, Chip } from "react-materialize";
import "materialize-css";

class App extends React.Component {
  constructor() {
    super();
    this.state = {
      countries: [{ name: "France" }, { name: "Germany" }],
      hashTag: []
    };
  }

  //test 1 function

  handleAddCountry = foo => {
    console.log("Chip :");
    console.log(foo.text())
    var test = foo.text()
    var ret = foo.text().replace('close','');
    console.log(ret);   
    this.setState({
      countries: this.state.countries.concat([{ name: ret }])
    });
  };



  // Button

  handleAddFrance = e => {
    console.log("Button:");
    console.log(e.target.value);
    this.setState({
      countries: this.state.countries.concat([{ name: e.target.value }])
    });
  };

  render() {
    const { countries, test } = this.state;

    return (
      <div>
        <div>
          <p>Chip test - onChipAdd</p>
          {/*  <Chip
      options={{
        onChipAdd: someFn,} */}


          <Chip
            close={false}
            closeIcon={<Icon className="close">close</Icon>}
            options={{
              onChipAdd: this.handleAddCountry,
              placeholder: "saisir un territoire",
              secondaryPlaceholder: "+territoire",
              autocompleteOptions: {
                data: {
                  "	France métropolitaine	": null,
                  "	DOM - TOM	": null,
                  "	DOM	": null,
                  "	Afghanistan	": null
                },
                limit: Infinity,
                minLength: 1,
                onAutocomplete: function noRefCheck() {}
              },
            }}
          />
        </div>


   
        <hr />

        <p>Button test</p>

        <button
          type="button"
          onClick={this.handleAddFrance}
          value="France"
          className="small"
        >
          Add France
        </button>

        <hr />

        <p>Variable result : </p>

        {countries.map(country => (
          <div>{country.name}</div>
        ))}
        <br />
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  rootElement
);

@alextrastero
Copy link
Member

alextrastero commented May 9, 2020

Your issue is that in the handler you are calling setState which is triggering a re-render of the component which is creating a new Chip component.

What you want is to add a "initial" data to the Chip populated from state. This way when you update the state Chip will be re-rendered with those values.

<Chip
  options={{
    data: [{ tag: 'foo' }] // chip will render with 'foo' as a tag
  }}

@alextrastero
Copy link
Member

Let me know how it goes :)

@alextrastero
Copy link
Member

I'm going to close this as it's not a bug, good luck!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants