Pergunta

Eu tenho um conjunto de imagens que possuem popovers usando o componente bootstrap popover ui no atributo/parâmetro de conteúdo. Gostaria de adicionar o componente ReactJS MusicList, mas não consegui descobrir a sintaxe ou se é possível ou não.

var MusicList = React.createClass({
    render : function(){
        return(<ul><li>Here</li></ul>);
    }
});

var PopoverImage = React.createClass({
    componentDidMount:function(){

        $("#"+this.getDOMNode().id).attr('data-component','<span>here</span>');
        $("#"+this.getDOMNode().id).popover({
            html:true,
            content: 
            });
    },

    render:function(){
        return(
            <img href="#" id={this.props.friend.uid+'_popover'} data-html={true} className="smallImage" src={this.props.friend.pic_small} rel="popover" data-original-title={this.props.friend.name} />

                );
    }
});
Foi útil?

Solução

O Bootstrap não facilita a renderização de um componente dinâmico dentro de um popover.Se o popover que você deseja apresentar for estático, você pode simplesmente usar o React's renderComponentToString que pega um componente e retorna uma string de HTML através de um retorno de chamada:

var html = React.renderComponentToString(<MusicList />);
$(this.getDOMNode()).popover({
    html: true,
    content: html
});

No entanto, se o seu componente tiver alguma interatividade, essa estratégia não funcionará porque o React nunca terá a chance de anexar manipuladores de eventos (ou executar qualquer um dos seus métodos de ciclo de vida personalizados).Na verdade, o Bootstrap não fornece os ganchos adequados para tornar o conteúdo popover dinâmico.


Dito isto, é possível fazer isso funcionar corrigindo o Bootstrap.Criei uma demonstração ao vivo com conteúdo popover dinâmico:

popover demo screenshot
http://jsfiddle.net/spicyj/q6hj7/

Observe que a hora atual é renderizada no popover por um componente React que é atualizado a cada segundo.


Como esse popover foi criado?

Eu remendei Popovers de bootstrap setContent método para usar um componente React além de um HTML ou string de texto.Em vez de usar jQuery html ou text métodos, eu uso React.renderComponent:

// Patch Bootstrap popover to take a React component instead of a
// plain HTML string
$.extend($.fn.popover.Constructor.DEFAULTS, {react: false});
var oldSetContent = $.fn.popover.Constructor.prototype.setContent;
$.fn.popover.Constructor.prototype.setContent = function() {
    if (!this.options.react) {
        return oldSetContent.call(this);
    }

    var $tip = this.tip();
    var title = this.getTitle();
    var content = this.getContent();

    $tip.removeClass('fade top bottom left right in');

    // If we've already rendered, there's no need to render again
    if (!$tip.find('.popover-content').html()) {
        // Render title, if any
        var $title = $tip.find('.popover-title');
        if (title) {
            React.renderComponent(title, $title[0]);
        } else {
            $title.hide();
        }

        React.renderComponent(content,  $tip.find('.popover-content')[0]);
    }
};

Agora é possível você escrever

$(this.getDOMNode()).popover({
    react: true,
    content: <MusicList />
});

na tua componentDidMount método e faça com que ele seja renderizado corretamente.Se você olhar no JSFiddle vinculado, verá um aplicativo de uso geral <BsPopover /> wrapper que fiz e que cuida de todas as chamadas do Bootstrap para você, incluindo a limpeza adequada dos componentes popover assim que o componente wrapper for removido do DOM.

Outras dicas

Existe uma nova biblioteca chamada React-Bootstrap que está em rápido desenvolvimento.

https://react-bootstrap.github.io/components.html#popovers

Se você incluir este módulo, terá a capacidade de tornar o popover seu próprio componente que pode ser salvo em uma variável e usado em sua função de renderização.

O exemplo deles:

const positionerInstance = ( <ButtonToolbar> <OverlayTrigger trigger="click" placement="bottom" overlay={<Popover title="Popover bottom"><strong>Holy guacamole!</strong> Check this info.</Popover>}> <Button bsStyle="default">Click</Button> </OverlayTrigger> <OverlayTrigger trigger="hover" placement="bottom" overlay={<Popover title="Popover bottom"><strong>Holy guacamole!</strong> Check this info.</Popover>}> <Button bsStyle="default">Hover</Button> </OverlayTrigger> <OverlayTrigger trigger="focus" placement="bottom" overlay={<Popover title="Popover bottom"><strong>Holy guacamole!</strong> Check this info.</Popover>}> <Button bsStyle="default">Focus</Button> </OverlayTrigger> <OverlayTrigger trigger="click" rootClose placement="bottom" overlay={<Popover title="Popover bottom"><strong>Holy guacamole!</strong> Check this info.</Popover>}> <Button bsStyle="default">Click + rootClose</Button> </OverlayTrigger> </ButtonToolbar> );

React.render(posicionadorInstance, mountNode);

meu código:

mostrarMaisDetalhes:função(obj, colunas){

    var popOver = (
        <Popover>
            <table>
                {
                    columns.map(col =>
                            <tr>
                                <td style={{textAlign:'right', padding:5}}>
                                    {col.label}:&nbsp;
                                </td>
                                <td style={{padding:5}}>
                                    {obj[col.key]}
                                </td>
                            </tr>
                    )
                }
            </table>
        </Popover>
    );

    return(
        <OverlayTrigger trigger='click' rootClose placement='left' overlay={popOver}>
            <div className="popover-more">more...</div>
        </OverlayTrigger>
    );

},

Depois de postar esta resposta e testar e trabalhar um pouco com essa solução alternativa, percebo que ela não é a ideal.

Os menus suspensos do Bootstrap fecham assim que o usuário interage com eles.Este pode não ser o comportamento desejado (no meu caso, estou inserindo um datepicker e o usuário não pode alterar o mês sem precisar reabrir o menu para escolher a nova data).


Eu tive o mesmo problema e encontrei uma solução fácil e alternativa.

Eu não queria usar o react-bootstrap (outras partes do meu aplicativo não são reativadas e usam o bootstrap, então não quero ter duas bibliotecas fazendo a mesma coisa).

O componente suspenso fornecido imediatamente pelo Bootstrap fornece quase as mesmas funcionalidades do popover, exceto que é muito mais flexível.Este é o menu suspenso padrão do Bootstrap:

<div class="dropdown">
  <button id="dLabel" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
    Dropdown trigger
    <span class="caret"></span>
  </button>
  <ul class="dropdown-menu" aria-labelledby="dLabel">
    ...
  </ul>
</div>

Aqui está o mínimo que você precisa para fazê-lo funcionar sem quebrá-lo e você pode incluir qualquer elemento React dentro dele:

<div className="dropdown">
  <button data-toggle="dropdown">
    Dropdown trigger
  </button>
  <div className="dropdown-menu">
    <myGreatReactIntervactiveComponent 
      value={this.props.value}
      onChange={this.handleChange}
      onClick={this.handleClick}
      children={this.greatChildrenForMyGreatREactInteractiveComponent}
    />
  </div>
</div>

Tudo que você precisa manter é (i) a classe "dropdown" no wrapper div, (ii) o atributo de alternância de dados "dropdown" no gatilho (você pode alterar seu gatilho para qualquer elemento html que desejar) e (iii) a classe "menu suspenso" no menu suspenso (você também pode alterá-la para qualquer elemento html que desejar e não precisa colar o elemento "ul" proposto pelo Bootstrap).

Você perde alguns recursos em comparação com o popover (você não pode definir suas próprias transições, não pode exibi-las na parte superior, esquerda ou direita, mas apenas abaixo - é um menu suspenso), mas você ganha controle total sobre o conteúdo do seu menu suspenso /dar um pulo.

Outra maneira de resolver isso é incluir o componente react que você deseja que seja o conteúdo do popover na função de renderização do componente que contém o popover (ou seja,'a página'), mas coloque-a dentro de uma div com estilo "display:none;" para que não seja exibido e não ocupe espaço, forneça também um ID, por exemplo.'popOverContent'.Então, quando você inicializar o conteúdo do conjunto popover:document.getElementById("popOverContent").Pelo menos no bootstrap 4, é necessário um elemento como conteúdo.

Você não precisa modificar o código de bootstrap dessa forma, facilitando a manutenção/atualizações.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top