skip to Main Content

I am not familiar with javascript and facing this weird situation.
I am using javascript to iterate over div element and retrieve href values from all <a> element inside, the purpose is to handle click on <a> element by JavaScript instead of default by HTML.

The iteration works but all links target replaced to the last <a> href values.

$(document).ready(function() {
  //NavMenu();
  //NavActive();
  NavClick();
  console.log('tes');
});

function NavClick() {
  var nav_item = document.getElementById('nav-menu').querySelectorAll('div')
  for (let i = 0; i < nav_item.length; i++) {
    item = nav_item[i].querySelector('a').getAttribute('href')
    nav_item[i].addEventListener('click', function(e) {
      e.preventDefault();
      $.ajax({
        url: item,
        contentType: 'application/json',
        dataType: 'json',
        success: function(data) {
          $('title').html(data.title)
          window.history.replaceState({}, '', item)
          $('#content').html(data.data)
        }
      });
    });
  }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
<div class="row col-12 justify-content-end" id="nav-menu">
  <div class="col-auto">
    <a href="/" class="px-1">
            Short
        </a>
  </div>
  <div class="col-auto">
    <a href="/myurl/' %}" class="px-1">
            My URL
        </a>
  </div>
  <div class="col-auto">
    <a href="/group/" class="px-1">
            My Collection
        </a>
  </div>
  <div class="col-auto">
    <a href="/group/create/" class="px-1">
            New Collection
        </a>
  </div>
</div>

What I expecting is my code will add event listener to each element and retrieve the "href" value so I can send request to server with the url.

eg. when I click this link, javascripts will send request to 127.0.0.1 but what i get is request send to 127.0.0.1/group/create/.

<div class="col-auto">
    <a href="/" class="px-1">
        Short
    </a>
</div>

is my logics wrong or I miss something on my codes?

4

Answers


  1. Use let for item:

    By declaring item with let, its scope is limited to the block of the loop iteration, avoiding the issue of it being overwritten.

    let item = nav_item[i].querySelector('a').getAttribute('href');
    
    Login or Signup to reply.
  2. function NavClick(){
        const homeurl = 'http://127.0.0.1';
        var nav_item = document.getElementById('nav-menu').querySelectorAll('div')
        for (let i=0; i<nav_item.length; i++){
            item = nav_item[i].querySelector('a').getAttribute('href')
            nav_item[i].addEventListener('click', function(e){
                e.preventDefault();
                $.ajax({
                    url: homeurl + item,
                    contentType: 'application/json',
                    dataType: 'json',
                    success: function(data){
                        $('title').html(data.title)
                        window.history.replaceState({}, '', item)
                        $('#content').html(data.data)
                    }
                });
            });
        }
    }
    

    Hope it will help you. Try to define the homeurl as constant variable.

    By default if you click the link("/") from 127.0.0.1/group/create page, by default it will go to 127.0.0.1/group/create link. So, always use as const variable for homepage url is safe option

    Login or Signup to reply.
  3. All you need to do is set up a click listener, check if it’s an a tag that’s being clicked, and use preventDefault() to override the navigation.

    No loop required. No JQuery required.

    window.addEventListener('load', () => {
      function hijackLink(event) {
        if (event.target.tagName == 'A') {
          console.log(event.target.href);
          event.preventDefault();    
        }
      }
    
      document.addEventListener('click', hijackLink);
      // EDIT, due to comment
      // document.getElementById('nav-menu').addEventListener('click', hijackLink)
    });
    <div class="row col-12 justify-content-end" id="nav-menu">
      <div class="col-auto">
        <a href="/" class="px-1">
                Short
            </a>
      </div>
      <div class="col-auto">
        <a href="/myurl/' %}" class="px-1">
                My URL
            </a>
      </div>
      <div class="col-auto">
        <a href="/group/" class="px-1">
                My Collection
            </a>
      </div>
      <div class="col-auto">
        <a href="/group/create/" class="px-1">
                New Collection
            </a>
      </div>
    </div>
    Login or Signup to reply.
  4. Since you don’t want the actual anchor behavior and direct it to another resource, you should not use an anchor.
    As you said that you want to make an API call, you should use a button as a semantic "script trigger element". The link/url you placed wrongly inside a hrefcan be placed within a data attribute. In the code example, I gave it the name link (data-link).

    Add the event listener directly to the button and make your element selector shorter and more readable by using document.querySelectorAll('#nav-menu button'). Then iterate through the Node List (what querySelectorAll returns) and add the event listener directly to each element. You can also look into event delegation if you want to improve your JS skills further.
    You can read out the URL then by using this.dataset.link

    window.addEventListener('DOMContentLoaded', function() {
      const NAV_ITEMS = document.querySelectorAll('#nav-menu button');
      NAV_ITEMS.forEach(item => {
        item.addEventListener('click', function() {
          const LINK = this.dataset.link;
          console.log(LINK);
        })
      })
    });
    <div class="row col-12 justify-content-end" id="nav-menu">
      <div class="col-auto">
        <button data-link="/" class="px-1">Short</button>
      </div>
      <div class="col-auto">
        <button data-link="/myurl/' %}" class="px-1">My URL</button>
      </div>
      <div class="col-auto">
        <button data-link="/group/" class="px-1">My Collection</button>
      </div>
      <div class="col-auto">
        <button data-link="/group/create/" class="px-1">New Collection</button>
      </div>
    </div>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search