How do I initialize the Bootstrap 4 popover in a React application?

后端 未结 2 1717
眼角桃花
眼角桃花 2021-01-24 20:18

I can\'t figure out how to make popovers work, as per: https://getbootstrap.com/docs/4.0/components/popovers/.

The documentation talks about the popover support being a

相关标签:
2条回答
  • 2021-01-24 20:21

    What the documentation is trying to say that simply having an element with data-toggle="popover" will not create an instance of a popover. You need to explicitly initialise it with a javascript call.

    In a non-react environment, you could add it to the document ready function, for example like this

    $(document).ready(function () {
        $('.myPopoverItem').popover({
            html: true
            , trigger: 'focus'
            , content: $.proxy(this.getContent, this)
        });
    }
    

    In React though, you would need to add it to the constructor code of your object, such that it is called after render() (The elements have to be on the page).

    I found this potential answer: React "after render" code? Where it recommends the componentDidMount function in which you can call the popover initialisation.

    So in your React object, you would have a function

    componentDidMount() {
        $('.myPopoverItem').popover({
            html: true
            , trigger: 'focus'
            , content: $.proxy(this.getContent, this)
        });
    }
    
    0 讨论(0)
  • 2021-01-24 20:41

    I had (still have, undoubtedly) a lot of missing contextual understanding when I was initially trying to get Bootstrap popovers working.

    First thing is: the Bootstrap "Popover" plugin is really a JQuery plugin. I assume that's how all the Bootstrap plugins work, but I couldn't find any Bootstrap introductory documentation about this. So that explains the popover() method and where it comes from.

    Below, I've outlined what is needed to make the popovers work in the context of a React / Typescript / Webpack stack.

    In the following, I'm assuming you've configured Webpack as per the Bootstrap doco.

    You don't need the "Popover" and "Tooltip" lines from the original question, assuming you're webpack.config.js is as per the Bootstrap doco and you have import 'bootstrap'; somewhere in your codebase.


    You need to add the JQuery typings, if not already present, so that you can import $ and have the right types:

    "devDependencies": {
       "@types/jquery": "3.2.15",
       ...
    }
    
    "dependencies": {
      "bootstrap": "4.0.0-beta",
      "jquery": "3.2.1",
      "popper.js": "1.11.0",
      ...
    }
    

    You have to extend the type definition of JQuery so that it knows about the Popover plugin, as per this blog article by Netanel Basal. In typings.d.ts (or wherever makes sense in your project), add the following:

    // support for JQuery popover plugin from Bootstrap 4
    interface JQuery {
      popover() : any;
    }
    

    Note that definition is the bare minimum you need to get popovers working from your code in a statically typed way. It needs to be extended to support passing parameters so that you can customise the popover behaviour. Or you could use the data attributes to pass these parameters, as per the Live example in the doco.

    In the React component itself, the JSX to declare the popover from the question seems to work fine.

    To "initialize" the popover, as per the question, you need to import the JQuery identifier and then call the popover method:

    ...
    const $ = require('jquery'); 
    ...
    componentDidMount(): void{
      $('[data-toggle="popover"]').popover();
    }
    ...
    

    The "import form" didn't work for me, so I had to require() it.

    That code searches the entire HTML page for elements with data-toggle="popover", and returns a JQuery object that has the popover() method you can call (that's the whole JQuery plugin part).

    Once popover() has been called on the element with the popover attributes, popovers will be automatically displayed when the element is clicked (there's no need to manage popover-specific React state).


    EDIT

    It's not a good idea to search the entire HTML page for all popovers as shown above. In a complicated page with multiple popovers in multiple React components, each component would end up overwriting each other's popover() options.

    Here's my current solution for a re-usable React bootstrap Popover component.

    Extend the Typescript typings to understand more popover options:

    // support for JQuery popover plugin from Bootstrap 4
    interface JQuery {
      popover(options?: PopoverOptions) : any;
    }
    
    interface PopoverOptions {
      container?: string | Element | boolean;
      content?: string | Element | Function;
      placement?: "auto" | "top" | "bottom" | "left" | "right" | Function;
      title?: string | Element | Function;
      ...
    }
    

    Create Popover.tsx like:

    export interface PopoverProps {
      popoverTitle: string | Element | Function;
      popoverContent: string | Element | Function;
    }
    
    export class Popover
    extends PureComponent<PopoverProps, object> {
    
      selfRef: HTMLSpanElement;
    
      componentDidMount(): void{
        $(this.selfRef).popover({
          container: this.selfRef,
          placement: "auto",
          title: this.props.popoverTitle,
          content: this.props.popoverContent,
        });
      }
    
      render(){
        return <span
          ref={(ref)=>{if(ref) this.selfRef = ref}} 
          data-toggle="popover"
        >
          {this.props.children}
        </span>;
    
      }
    }
    

    Then use the popover like:

    <Popover 
      popoverTitle="The popover title"
      popoverContent="The popover content"
    >
      <span>
        Click this to show popover.
      </span>
    </Popover>
    

    Beware issues related to Popover positioning with dynamic content: Bootstrap 4 - how does automatic Popover re-positioning work?

    0 讨论(0)
提交回复
热议问题