xkeshav
xkeshav

Reputation: 54052

Adding a jQuery plugin is not working in a React app; "TypeError: this.$el.chosen is not a function"

I am learning React and am following integrating other Libraries chapter. I tried the same they have suggested, but I am getting the below error:

TypeError: this.$el.chosen is not a function
Chosen.componentDidMount
src/App.js:18

  componentDidMount() {
    this.$el = $(this.el);
>   this.$el.chosen();
  }

The React website provides an example CodePen where they have added the jQuery and chosen plugin .js files in dependencies. I have added jQuery and chosen the library .js file in index.html and also added jQuery using npm install jquery --save, so that it can be imported in App.js.

File index.html

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta name="theme-color" content="#000000">
    <link rel="manifest" href="%PUBLIC_URL%/manifest.json">
    <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/chosen/1.6.2/chosen.jquery.min.js"></script>
    <title>React App</title>
  </head>
  <body>
    <noscript>
      You need to enable JavaScript to run this app.
    </noscript>
    <div id="root"></div>
  </body>
</html>

File App.js

import React, { Component } from 'react';

import $ from 'jquery';

class Chosen extends Component {

  componentDidMount() {
    this.$el = $(this.el);
    this.$el.chosen();
  }

  componentWillUnmount() {
    this.$el.chosen('destroy');
  }

  render() {
    return (
      <div >
        <select className="Chosen-select" ref={el => this.el = el}>
          {this.props.children}
        </select>
      </div>
    );
  }
}

function Example() {
  return (
    <Chosen >
      <option >vanila</option>
      <option >strawberry</option>
      <option >chocolate</option>
    </Chosen>
    );
}


class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <section>
          <Example/>
        </section>
      </div>
    );
  }
}

export default App;

File index.js


import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

Why am I getting this error, and how do I fix it?

Upvotes: 4

Views: 5212

Answers (4)

Sachin Kumar
Sachin Kumar

Reputation: 3240

I have also faced the same issue while reading the documentation. But instead of updating the "node_modules/chosen-js/chosen.jquery.js" file, I prefer to Use the ProvidePlugin to inject implicit globals in webpack.config.js.

But when we created an application using Create React App, we didn't find the webpack.config.js file. You will need to eject the React application. But you should first read from the following links before ejecting the application (if you’re a power user and you aren’t happy with the default configuration).

References:

You will need to run the following command to eject the React application as this command will remove the single build dependency from your project and also copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc.) into your project as dependencies in file package.json.

npm run eject

Install the dependencies

npm install jquery chosen-js --save

Now edit your webpack.config.js file and update the configuration object as follows:

return {
    ...
    module: {
        ...
    },
    plugins: [
        ...
        new webpack.ProvidePlugin({
            $: "jquery",
            jQuery: "jquery"
          }),
    ]
    ...
}

Chosen.js

import React from 'react';
import $ from "jquery";
import "chosen-js/chosen.css";
import "chosen-js/chosen.jquery.js";

class Chosen extends React.Component {
  componentDidMount() {
    this.$el = $(this.el);
    this.$el.chosen();

    this.handleChange = this.handleChange.bind(this);
    this.$el.on("change", this.handleChange);
  }

  componentDidUpdate(prevProps) {
    if (prevProps.children !== this.props.children) {
      this.$el.trigger("chosen:updated");
    }
  }

  componentWillUnmount() {
    this.$el.off("change", this.handleChange);
    this.$el.chosen("destroy");
  }

  handleChange(e) {
    this.props.onChange(e.target.value);
  }

  render() {
    return (
      <div>
        <select className="Chosen-select" ref={(el) => (this.el = el)}>
          {this.props.children}
        </select>
      </div>
    );
  }
}

Upvotes: 1

appsmatics
appsmatics

Reputation: 709

I got it to work by following these steps (after creating a project using Create React App (executable create-react-app)):

npm install jquery --save
npm install chosen-js --save

Add this in line #1 of file node_modules/chosen-js/chosen.jquery.js

import jQuery from 'jquery'

As per this answer

import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';

import $ from 'jquery'
import "chosen-js/chosen.css";
import "chosen-js/chosen.jquery.js";

class Chosen extends React.Component {


  componentDidMount() {
    this.$el = $(this.el);
    this.$el.chosen();

    this.handleChange = this.handleChange.bind(this);
    this.$el.on('change', this.handleChange);
  }

  componentDidUnmount() {
    this.$el.off('change', this.handleChange);
    this.$el.chosen('destroy');
  }

  handleChange(e) {
    this.props.onChange(e.target.value);
  }

  render() {
    return (
      <div>
        <select className="Chosen-select" style={{width: "200px"}} ref={el => this.el = el}>
          {this.props.children}
        </select>
      </div>
    );
  }
}

function Example() {
  return (
    <Chosen className="chosen-container chosen-container-single" onChange={value => console.log(value)}>
      <option>vanilla</option>
      <option>chocolate</option>
      <option>strawberry</option>
    </Chosen>
  );
}


class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
          <Example/>
        </p>
      </div>
    );
  }
}

export default App;

Upvotes: 3

fung
fung

Reputation: 639

It seems like an issue related with a dependency.

I notice that you include jQuery and its chosen plugin with a CDN which means it is declared globally. But in the third line of App.js, you import $ from 'jquery'; which may introduce jQuery locally. In my experience, React will refer $ to the local jQuery instance which is not with the plugin.

I suggest that you could try comment out import $ from 'jquery' and try again.

Upvotes: 0

Agniswar Chakraborty
Agniswar Chakraborty

Reputation: 287

Use

window.$("#infomodal").modal("hide");

Upvotes: 0

Related Questions