Search code examples
rubyopalrbvoltrb

How do I do a jQuery toggleClass in Volt?


I'm playing around with Volt and currently trying to do a simple toggleClass for a sidebar in my Volt app (with no luck). Here is a code sample.

app/main/views/main.html

<:Title>
  {{ view main_path, "title", {controller_group: 'main'} }}

<:Body>

  <div id="wrapper">
    <div id="sidebar-wrapper">
      <ul class="sidebar-nav">
        <li><a href="#">blah</a></li>
        <li><a href="#">blah</a></li>
        <li><a href="#">blah</a></li>
        ...
      </ul>
    </div>

    <div id="page-content-wrapper">
      <div class="container-fluid">
        <div class="btn btn-default sidebar-toggler">Toggle Sidebar</div>
        <:volt:notices />
        {{ view main_path, 'body', {controller_group: 'main'} }}
      </div>
    </div>
  </div>

app/main/assets/js/sidebar.js

$(document).ready(function() {
  $(".sidebar-toggler").click(function(e) {
    e.preventDefault();
    $("#wrapper").toggleClass("toggled");
  });
});

When clicking on div.sidebar-toggler a toggled class should be added to div#wrapper ... It doesn't, there maybe another way to do this with Volt.

The code above is not working. What's the good Volt way to do this ?


Solution

  • In volt, you would typically make the toggle state a "reactive accessors" on the controller, then use bindings to update the class state. Since controllers are the context for bindings, we can check the state of the reactive_accessor in an if binding.

    in the controller:

    module Main
      class MainController < Volt::ModelController
        reactive_accessor :toggled
    
        def toggle_sidebar
          self.toggled = !toggled
        end
        ....
    

    in the view:

    ...
    <div class="btn btn-default sidebar-toggler {{ if toggled }}toggled{{ end }}" e-click="toggle_sidebar">Toggle Sidebar</div>
    ...
    

    When we call the self.toggled = method, it changes the state and reactively updates any bindings using that data. The e-click calls the toggle_sidebar method on the controller. The common Volt way to do something simple like this is to put the if directly into the view. We could also put it into a method that returns a string and bind to that.

    def toggled_class
      toggled ? 'toggled' : ''
    end
    
    ....
    
    <div class="btn btn-default sidebar-toggler {{ toggled_class }}" e-click="toggle_sidebar">Toggle Sidebar</div>
    

    Hopefully that helps, I can clarify more if you need.