1

I have created a tabbed interface, utilizing page anchors. This is a problem because by default, a browser navigates to the anchor when a link linking to it is clicked on the same page:

showTab = function(tabName) {
  tabName = tabName.replace(" ", "_"); //Fix space in tab name so that JS can use it.
  $(".tab_selected").addClass("tab");
  $("#p_" + document.querySelector(".tab_selected").id).hide();
  $(".tab_selected").removeClass("tab_selected");
  $("#" + tabName).addClass("tab_selected");
  $("#p_" + tabName).show();
  location.hash = tabName;
  document.title = tabName.replace("_", " ") + " | AnED";
}

//if (location.hash.length < 1)
//  showTab("Information");
body {
  height:1200px;
}

.page_tabgroup {
 display:table;
 margin:0 auto;
 width:auto;
 margin-top:50px;
 border-radius:4px;
 background-color:#FFF;
 border:solid 2px rgba(0, 120, 255, 0.8);
}

.page_tabgroup > a {
 text-decoration:none;
 border:none;
}

.page_tabgroup > .tab {
 display:table-cell;
 padding:10px 20px 10px 20px;
 color:rgba(0, 120, 255, 0.8);
}

.page_tabgroup > .tab:hover, .primary_page > .page > .page_tabgroup > .tab_selected:hover {
 background-color:rgba(0, 120, 255, 0.95);
 border:inherit solid rgba(0, 120, 255, 0.6);
 color:#FFF;
}

.page_tabgroup > .tab_selected {
 display:table-cell;
 padding:10px 20px 10px 20px;
 color:#FFF;
 background-color:rgba(0, 120, 255, 0.8);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="page_tabgroup">
  <a href="javascript:showTab('Information')" class="tab tab_selected" id="Information">Information</a>
  <a href="javascript:showTab('Course_Dates')" class="tab" id="Course_Dates">Course Dates</a>
</div>

In the above example, the browser automatically scrolls down so that the anchor element is at the top. This is annoying behaviour, but unsurprising. I tried using preventDefault() as in this answer to Avoid window jump to top when clicking #-links, however it doesn't have any effect whatsoever. This is likely because I am not using a click handler (the function is directly executed via a javascript:showTab link).

Using click handlers blocks the showTab function from executing entirely, and appending it with showTab(e.id); creates a Cannot read property 'replace' of undefined error for line 2 of showTab:

$(".tab_selected").click(function(e) {
    e.preventDefault();
});

$(".tab").click(function(e) {
    e.preventDefault();
});

Is it possible to block the default anchor behaviour outside of a click handler? If not, how can I fix this?

Community
  • 1
  • 1
AStopher
  • 4,207
  • 11
  • 50
  • 75
  • What you have is totally removing the notion of using unobtrusive JavaScript. – Praveen Kumar Purushothaman Apr 25 '17 at 12:39
  • Why are you using href to call the function? There is no need to use inline events – epascarello Apr 25 '17 at 12:39
  • @epascarello I get a `Cannot read property 'replace' of undefined` if I do so (it should technically work, all the href is doing is forwarding the ID onto the handler anyway). – AStopher Apr 25 '17 at 12:41
  • It will be a big change to your code, or maybe not, but you can take a look at [scrollTop()](https://web-design-weekly.com/snippets/scroll-to-position-with-jquery/) – DIEGO CARRASCAL Apr 25 '17 at 12:47
  • The scrolling is being caused by you setting window.location.hash, now the e.id error is the fact that the event object does not have an id. – epascarello Apr 25 '17 at 12:47
  • @epascarello This is done on purpose to ensure that the page can be navigated to with only the link. This isn't desirable but I had no say in the decision unfortunately. – AStopher Apr 25 '17 at 12:49
  • Yes, cancelling the click i not going to keep it from scrolling the page. – epascarello Apr 25 '17 at 12:50

3 Answers3

0

You have to do the unobtrusive way.

  1. Remove the href and javascript:. They are age old.
  2. Use correct jQuery way of initialising the event listeners.
  3. Change the hash, the correct way, using history.pushState(stateObj, "page", "url");.

$(function () {
  $("a.tab").click(function(e) {
    e.preventDefault();
    var tabName = this.id;
    tabName = tabName.replace(" ", "_"); //Fix space in tab name so that JS can use it.
    $(".tab_selected").addClass("tab");
    $("#p_" + document.querySelector(".tab_selected").id).hide();
    $(".tab_selected").removeClass("tab_selected");
    $("#" + tabName).addClass("tab_selected");
    $("#p_" + tabName).show();
    // location.hash = tabName;
    document.title = tabName.replace("_", " ") + " | AnED";
    return false;
  });
});
body {
  height:1200px;
}

.page_tabgroup {
  display:table;
  margin:0 auto;
  width:auto;
  margin-top:50px;
  border-radius:4px;
  background-color:#FFF;
  border:solid 2px rgba(0, 120, 255, 0.8);
}

.page_tabgroup > a {
  text-decoration:none;
  border:none;
}

.page_tabgroup > .tab {
  display:table-cell;
  padding:10px 20px 10px 20px;
  color:rgba(0, 120, 255, 0.8);
}

.page_tabgroup > .tab:hover, .primary_page > .page > .page_tabgroup > .tab_selected:hover {
  background-color:rgba(0, 120, 255, 0.95);
  border:inherit solid rgba(0, 120, 255, 0.6);
  color:#FFF;
}

.page_tabgroup > .tab_selected {
  display:table-cell;
  padding:10px 20px 10px 20px;
  color:#FFF;
  background-color:rgba(0, 120, 255, 0.8);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="page_tabgroup">
  <a href="#" class="tab tab_selected" id="Information">Information</a>
  <a href="#" class="tab" id="Course_Dates">Course Dates</a>
  <a href="#" class="tab" id="Home_Study">Home Study</a>
  <a href="#" class="tab" id="In-House">In-House</a>
</div>
Praveen Kumar Purushothaman
  • 164,888
  • 24
  • 203
  • 252
0

Just change, location.hash = tabName; for history.pushState({}, '', tabName);. That should do the trick.

e.preventDefault() can't help here.

manelescuer
  • 827
  • 1
  • 9
  • 19
0

The scroll issue really has nothing to do with the anchor click, it has to do with scrolling because of setting the hash. Also using inline events and use href for calling JavaScript is not the best thing. So since you are using jQuery, you can use event delegation to add the click. You can than grab the ids and show and hide elements.

$(".page_tabgroup").on("click", ".tab", function(e) { //event delegation
  e.preventDefault(); //stop click
  var selectedId = $(".tab_selected").removeClass("tab_selected").attr("id"), //remove what is selected
    clickedElement = $(this).addClass("tab_selected"),
    clickedElementId = clickedElement.attr("id");

  $("#p_" + selectedId).hide(); //show the tab that was selected prev
  $("#p_" + clickedElementId).show(); //show the current tab

  //now to stop scroll, you need to remove the id of the element, set hash, and add it back.

  clickedElement.attr("id", "temp");  //remove
  window.location.hash = clickedElementId;   //set
  clickedElement.attr("id", clickedElementId);  //set back

});
epascarello
  • 204,599
  • 20
  • 195
  • 236