1

I have links made like this:

- @glossaries.each do |g|
  %a.{ :href => glossary_path(g), data: { 'turbo_frame': :'entry' } }
    = g.title

How can I style active link (active glossary) if result of clicking g.title link is rendered in another frame? enter image description here

I've tried using helper to give a link some class if current path equal requested path, but it is not working. No 'active' class is given to link:

def current_class?(test_path)
    return 'active' if request.path == test_path
    ''
  end

When working with frames current path not showing in browser address bar, so I've tried to force it by data-turbo-action" => "advance". With that browser have current path in address bar, but still link do not have 'active' class..

Alexander V
  • 45
  • 1
  • 5

3 Answers3

3

I write this stimulus controller to handle turbo:click event and make a active state to the clicked element. There is an issue when another turbo:click event handler cancelled the visit, but in this place I don't care about it.

import { Controller } from "@hotwired/stimulus";

export default class extends Controller{
  static targets = ['link']
  static classes = ['active']

  initialize(){
    this.handleTurboClick = this.handleTurboClick.bind(this)
  }

  connect(){
    this.element.addEventListener('turbo:click', this.handleTurboClick)
  }

  disconnect(){
    this.element.removeEventListener('turbo:click', this.handleTurboClick)
  }

  handleTurboClick(event){
    this.linkTargets.forEach(target => {
      if(target == event.target){
        target.classList.add(...this._activeClasses)
      }else{
        target.classList.remove(...this._activeClasses)
      }
    })
  }

  get _activeClasses(){
    return this.activeClasses.length == 0 ? ['active'] : this.activeClasses
  }
}
<div data-controller="turbo-active-link" data-turbo-active-link-active-class="bg-gray-300 hover:bg-gray-300" data-turbo-frame="main">
  <a href="/a" data-turbo-active-link-target="link">link A</a>
  <a href="/b" data-turbo-active-link-target="link">link B</a>
</div
Xiaohui Zhang
  • 985
  • 8
  • 12
1

The reason why it would not update is because the other frame is navigating while the rest of the page stays the same. To make it show the active navigation link you are going to want to either reload both or use some custom JavaScript. I would rather just reload both sides I would do another turbo-frame around the navigation and the sidepanel like so

<%= turbo_frame_tag "glosarries_index" do %>
  ... Navigation links would be here but remove the data-turbo-frame it will automatically use the closest parent.
  <%= turbo_frame_tag "entry" do %>
    ...
  <% end %>
<% end %>
yungindigo
  • 241
  • 1
  • 6
  • I reworked my app and now navigation between glossaries works without frames and current active link is styling properly, but ofc I would like to have frames for such task. I will try to implement what you suggested a bit later and will say if it worked for me. Thank you! – Alexander V Feb 22 '22 at 16:57
1

I found the above answer worked but was overly complex so I built a more simple solution that requires less boiler plate. This solution also adheres to stimulus convention better as it does not use custom event handlers and only uses targets

The stimulus controller:

import { Controller } from "stimulus";

export default class extends Controller {
  static classes = ['active']

  connect() {
    this.active_link = null;
  }

  disconnect() {
    this.active_link = null;
  }

  handleTurboClick(event) {
    if (this.active_link) {
      this.active_link.classList.remove(this.activeClass);
    }
    this.active_link = event.target.closest('a');
    this.active_link.classList.add(this.activeClass);
  }
}

The html:

<div data-controller="turbo-active-link" data-turbo-active-link-active-class="bg-gray-300 hover:bg-gray-300">
  <a href="/a" action="turbo:click->turbo-active-link#handleTurboClick" data-turbo-frame="main">link A</a>
  <a href="/b" action="turbo:click->turbo-active-link#handleTurboClick" data-turbo-frame="main">link B</a>
</div
TERMINATOR
  • 1,180
  • 1
  • 11
  • 24