Rendering a new partial prevent another one to be displayed

Hi there! :wave:

I’m still a beginner, but I loved the syntax and the way Stimulus work. So I’m using it in one of my Rails projet. I’m facing a little issue, I hope it’s ok to ask here! To be fairly honest, it might be the first time in a while I’m asking on an issue in public - I’m not 100% sure that I’m able to describe my issue clearly.

Here we go:

I have two stimulus controllers, one called “rankings” and one called “userview”. It works this way : several rankings are available. I can click on a ranking name, and that will trigger the rendering of this specific ranking, through a partial :

My view:

<%= link_to ranking_path(group), :remote => true, :role => "button", :title => title, :data => { :target => 'ranking.source', :action => 'click->ranking#get ajax:success->ranking#reveal', :html => "true" }, :class=>" btn btn-outline-third btn-sm mb-2 text-left" %>

Stimulus controller:

  reveal(event) {
  	const [data, status, xhr] = event.detail;
    console.log("REVEAL RANKING!", this.element)
    console.log(xhr.response)
    var el = document.getElementById("rankings-table")
    var newEl = document.createElement('div')
    var att = document.createAttribute("id")
    att.value = "rankings-table"
    newEl.setAttributeNode(att)
    newEl.innerHTML = xhr.response
    el.parentNode.replaceChild(newEl, el)
  }

The partial is rendered through a ruby controller:

  # pages_controller.rb
  def ranking
    if user_signed_in?
      @group = Group.find(params[:id])
      puts @group.id
      respond_to do |format|
        puts "@group.id"
        if request.xhr?
          puts "xhr"
          format.html { render partial: 'rankings', formats: [:html], locals: { groupranking: @group } }
        end
      end
    end      
  end

This part works like a charm! :sparkles:

Then, within this ranking, I have a bootstrap popover linked to each username. This popover is by default empty (data-content="") and displays some info about the profile of the user, through another partial, defined in my pages_controller.rb.

Trigger:
<%= link_to user.username, userview_path(user), :remote => true, :class => "profile", :role => "button", :tabindex => "0", :data => { :target => 'userview.source', :action => 'click->userview#get ajax:success->userview#reveal', :html => "true", :content => "", :toggle => "popover", :delay => "500" } %>

JS Controller:

// userview_controller.js
  reveal(event) {
  	const [data, status, xhr] = event.detail;
    console.log("REVEAL USERVIEW!", this.element)
    this.element.children[0].setAttribute("data-content", xhr.response);
  }

My issue is that when the page loads on the first time, I pick one ranking to be displayed by default: when I click on a username, then it loads the userview and displays the popover correctly.

When I ask for another ranking to be displayed, the ranking partial is correctly rendered. But when I click on a username, nothing is displayed.

Looking at the console, the partial calling and rendering is working fine (no errors and it does change the DOM), but the popover doesn’t display.

I’m not sure where this behaviour might be coming from?

It works well when the ranking is not changed by JS/Stimulus, so I thought that it would make sense to ask here, I hope it’s ok!

Thanks for reading - if anyone has an idea of what could be causing this, I’d love to have insights!

Cheers!

I think your problem is caused by an uninitialized popover. Popovers are not initialized automatically by Bootstrap — you probably have an event somewhere that initializes them on the first page load, like:

$(function () {
  $('[data-toggle="popover"]').popover()
})

When you use Ajax to replace the ranking on the page, the username popover it contains is not initialized. Try doing that in your userview controller:

// userview_controller.js
reveal(event) {
  const [data, status, xhr] = event.detail;
  
  $(this.usernameTarget).popover({content: xhr.response})
  $(this.usernameTarget).popover('show')
}
1 Like

Oh thank you! :clap::clap:

That was exactly it - by also adding a line initializing the popover in my ranking_controller.js (when the ranking is rendered) did the trick.

Many thanks, have a great day!

2 Likes

Great! You too :v: And welcome to the Stimulus community!