1

I am trying to include two tabs in my application. I have written all JS but it's in my HTML file. I would like to add it separately as .js file that I will only use in that page but I couldn't find a way to do.

In the page, I am getting user's anime and manga lists. Displaying animes in one tab and mangas in another.

I have tried to do it

  • with application.js: I can only use console.log() from application.js. With anything else, the user's page is not loading.
  • created action_name.js: As I know, I should tell the HTML page that it should use ujs, but I don't know where to put remote:true. (I only used it for forms so far)
  • tried to implement from outside with <%= javascript_include_tag "js_file_name.js" %> (created new js_file_name.js file under assets/javascript)

But they didn't work. Is there something that I am missing to do?

Have a nice day!

Edit:

JS:

document.getElementById('tab_anime').addEventListener("click", animeFunction);
document.getElementById('tab_manga').addEventListener("click", mangaFunction);

function mangaFunction() {
  console.log('manga');
  
  var mangas = document.getElementById('manga');
  mangas.classList.add("active");
  mangas.classList.add("show");
  mangas.classList.remove("fade");
  
  var anime = document.getElementById('anime');
  anime.classList.remove('show');
  anime.classList.remove('active');
  anime.classList.add('fade');
  
  var children = anime.firstElementChild.children;
  var i;
  for (i = 0; i < children.length; i++) {
    children[i].style.display = "none";
  }
  
  document.getElementById('tab_anime').parentElement.classList.remove('show');
  document.getElementById('tab_anime').parentElement.classList.remove('active');
  document.getElementById('tab_anime').getAttribute("aria-selected") ==  false;
  document.getElementById('tab_manga').parentElement.classList.add('show');
  document.getElementById('tab_manga').parentElement.classList.add('active');
  document.getElementById('tab_manga').getAttribute("aria-selected") ==  true;
} 


function animeFunction() {
  console.log('anime');
  
  var anime = document.getElementById('anime');
  anime.classList.add("active");
  anime.classList.add("show");
  anime.classList.remove("fade");
  
  var children = anime.firstElementChild.children;
  var i;
  for (i = 0; i < children.length; i++) {
    children[i].style.display = "block";
  }
  
  var mangas = document.getElementById('manga');
  mangas.classList.remove('show');
  mangas.classList.remove('active');
  mangas.classList.add('fade');
  
  document.getElementById('tab_manga').parentElement.classList.remove('show');
  document.getElementById('tab_manga').parentElement.classList.remove('active');
  document.getElementById('tab_manga').getAttribute("aria-selected") ==  false;
  document.getElementById('tab_anime').parentElement.classList.add('show');
  document.getElementById('tab_anime').parentElement.classList.add('active');
  document.getElementById('tab_anime').getAttribute("aria-selected") ==  true;
} 

HTML:

<div class="d-flex flex-column">
  <div class="mt-5 mb-3 border-0 p-0">
    <div class="row">
      <div class="col-md-3">
        <img src="https://cdnb.artstation.com/p/assets/images/images/013/162/715/large/muzu-violet-evergarden-by-muzuart.jpg?1564079658" class="card-img" alt="...">
      </div>
      <div class="col-md-9 d-flex">
        <div class="card-body d-flex flex-column pt-0 pb-0 pr-0">
          <div class="d-flex justify-content-between align-items-center">
            <h3 class="d-flex card-title m-0">User name here</h3>
            <div class="d-flex flex-row-reverse">
              <%= link_to 'Edit', edit_path, class: 'btn btn-outline-secondary mr-3 text-right' %>
              <button type="submit" class="btn btn-outline-danger mr-3">Delete</button>
            </div>
          </div>
          <p class="mt-auto">User_name here has watched 9 anime.s and has read 3 manga.s until now. </p>
          <p class="card-text">User-name has made a comment on @manga-anime.</p>
          <p class="card-text">
            <small class="text-muted">Last updated 3 mins ago</small>
          </p>
        </div>
      </div>
    </div>
  </div>

  <ul class="nav nav-tabs mt-5" id="MangAnimeTab" role="tablist">
    <li class="nav-item show active" role="presentation">
      <a class="nav-link" id="tab_anime" data-toggle="tab" href="#anime" role="tab" aria-controls="anime" aria-selected="true" >Anime</a>
    </li>
    <li class="nav-item" role="presentation">
      <a class="nav-link" id="tab_manga" data-toggle="tab" href="#manga" role="tab" aria-controls="manga" aria-selected="false">Manga</a>
    </li>
  </ul>

  <div class="tab-content p-3" >
    <div id="anime" class="tab-pane d-flex flex-column justify-content-between show active" role="tabpanel">
      <div class="d-flex flex-row">
        <div class="col-md-1 p-0 mr-3">
          <img src="https://cdnb.artstation.com/p/assets/images/images/013/162/715/large/muzu-violet-evergarden-by-muzuart.jpg?1564079658" class="card-img" alt="...">
        </div>
        <div class="flex-fill pl-3 border-right border-left">
          <p>Anime name here</p>
          <p>When user has added this anime to his/her list</p>
        </div>
        <div class="flex-fill pl-3">
          <p>This anime has been took 9.8 points on avarage.</p>
        </div>
      </div>
    </div>
    <div class="tab-pane fade" id="manga" role="tabpanel">
      <p>manga</p>
    </div>
  </div>
</div>

What I wanted to do is: whenever user page has displayed, I wanted to be able to toggle between manga and anime tabs. I can do that with this JS but I had do implement it in html.erb file in between <script></script> tags.

I have tried to create toggle.js under app/assets/javascript and added //= require_tree . to application.js under app/assets/javascript. But when I opened the page, JS is not working.

yektt
  • 67
  • 1
  • 8

1 Answers1

0

with application.js: I can only use console.log() from application.js. With anything else, the user's page is not loading.

I couldn't get what exactly you are saying but for other options from your list please consider the following answers:

  1. if you want to use action_name.js: remote: true should be put as an argument of form_for helper

<%= form_for @form, remote: true do %>...

  1. If you want to add a js file in assets: check if your application.js has //= require_tree . it ensures that all the files under app/assets/javascripts/ folder. If you don't want all the files under app/assets/javascripts then use //=required js_file_name to load the file specifically.

UPDATE

To confirm if the file is being loaded on view :

Please add an alert('test') at the top of the page which will popup when you refresh the page and it will confirm that file is implemented but your selectors are not working


If you are able to see above alert then we need to work on js code as followed


as you said you are able to see your js working if you put it in a script tag, I had this problem many times the issue might be that the elements you are trying to select in first 2 lines are not yet loaded in DOM and your js has executed. Please make sure your complete js runs after dom has been loaded

I usually write my js scripts on document ready event. which makes sure that all the lazy loading is done and the dom is ready. If you can use jquery its $(document).ready(function(){ YOUR CODE HERE }); else this (Pure JavaScript equivalent of jQuery's $.ready() - how to call a function when the page/DOM is ready for it) might help you find an alternative to document ready event callback

raviture
  • 959
  • 7
  • 11
  • I tried to say, if I would put my js in application.js, the page is not loading properly. Unfortunately, I am not using form_for. I added //=require_tree and created a .js file under app/assets/javascripts, but it's still not working. I know that there JS code is working because in between – yektt Dec 01 '20 at 08:11
  • it would really help if you could post some of the code snippets as to what your js code is doing also just confirming, make sure your require_tree statement is not missing with the `'.'` – raviture Dec 02 '20 at 00:44
  • I have added the codes, and thanks for reminding `'.'` but it didn't help. Should I download a specific gem to do that? I have searched but I could find for Rails-6 but not for Rails-5. – yektt Dec 02 '20 at 10:51
  • as you said the problem was because of the running time. When I wrote `alert()` in JS, I was able to see it but my functions weren't work. I wrote a function to run them after loading the page and voilà! they're working now. Thank you so much for your help:) – yektt Dec 03 '20 at 13:26
  • In such conditions always try to console.log the elements you have added callbacks to so that you will see if the elements were present when the script was loaded – raviture Dec 04 '20 at 01:13