1

We desperately need help with writing a small code that allows you to take the current page URL and the parameter in the href="parm" and create the link by joining the two with a slash.

The reason we need to do this is because we need relative links to the current page. The CMS system that we are working removes trailing slash from the end of URL.

Which is a problem because if you are at a page domain.com/fruit/apple

and create a link such as href="calories" or href="./calories" it will point to domain.com/fruit/calories

Instead, we want it to point to domain.com/fruit/apple/calories

Which is relative to the current page.

We don't want to change the way that our CMS works, therefore, the need JS solution.

Below you can see one example of what we are trying to accomplish but this only works on one link.

<a href="home" id="relurl" target="_blank" title="This is a relative link!">link</a>

Start JS

var x = window.location.href; // Current page URL
var link = document.getElementById("relurl"); // store the element
var curHref = link.getAttribute('href'); // Get HREF paramter
link.setAttribute('href', x + "/"+ curHref);

End JS

The idea is to build relative links every time links with id="relurl" is used.

As per previous example this link: a href="home" id="relurl" target="_blank" title="This is a relative link!">link

at this page: domain.com/fruit/apple

it should point to domain.com/fruit/apple/home

Meaning the link structure is the currentpageURL + / + href

One page may have multiple relative links.

Thanks for any help.

Progonat
  • 158
  • 6

2 Answers2

1

While you could just use relative URLs in your links (with href="./page"), it sounds like the problem is that you are using duplicate IDs (which results in invalid markup). You can test that you have valid markup with the W3C Markup Validation Service.

When you have duplicate IDs, JavaScript only applies to the first element. This can be seen in the following:

var x = window.location.href; // Current page URL
var link = document.getElementById("relurl"); // store the element
var curHref = link.getAttribute('href'); // Get HREF paramter
link.setAttribute('href', x + "/" + curHref);
<a href="home" id="relurl" target="_blank" title="This is a relative link!">Working Link</a>
<br />
<a href="home" id="relurl" target="_blank" title="This is a relative link!">NOT Working</a>

To resolve this, you should use classes instead of IDs for your links. You can then use document.getElementsByClassName to select the elements. Remember that this returns a NodeList collection of elements, so you'll need to set the new URLs inside of a loop, as can be seen in the following:

var x = window.location.href; // Current page URL
var links = document.getElementsByClassName("relurl"); // store the elements
for (var i = 0; i < links.length; i++) {
  var curHref = links[i].getAttribute('href'); // Get HREF paramter
  links[i].setAttribute('href', x + "/" + curHref);
}
<a href="home" class="relurl" target="_blank" title="This is a relative link!">Working Link</a>
<br />
<a href="home" class="relurl" target="_blank" title="This is a relative link!">Another Working Link</a>

Hope this helps! :)

Obsidian Age
  • 41,205
  • 10
  • 48
  • 71
  • Avoiding Id's is certainly a good idea. (Avoids global scope). But from what I remember you can do `querySelectorAll("#relurl")`. Not that I would like, classes or data-attributes is better. – Keith Jan 22 '18 at 22:36
  • @Keith - While `querySelectorAll("#relurl")` would select all of the IDs, it should not be used, as you would still have invalid markup. – Obsidian Age Jan 22 '18 at 22:38
  • `getElementsByClassName` returns an `HTMLCollection`, which seems to be missing some methods (like `forEach`) -- https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementsByClassName – anthonygood Jan 22 '18 at 22:59
  • @anthonygood - `.forEach` only works on arrays, and as you say `.getElementsByClassName` returns an `HTMLCollection`. As such, `.forEach` won't work on it. For `HtmlCollection` loops, you need to actually iterate over the index, as is explained in [**this answer**](https://stackoverflow.com/a/22754453/2341603), where they actually use `.getElementsByClassName` as an example. – Obsidian Age Jan 22 '18 at 23:13
  • It's not invalid markup that bothers me, some big names like Facebook / Twitter have even been know to have them. It the global scope getting polluted so avoiding id's totally is an even better idea.. :) – Keith Jan 23 '18 at 01:41
  • @ObsidianAge your answer says `getElementsByClassName` returns a `NodeList` when it returns an `HtmlCollection`. `NodeList` has `forEach`. – anthonygood Jan 23 '18 at 07:39
  • @anthonygood - I always get confused between the two; they're very similar. In fact, I'd argue they're synonymous. [**This answer**](https://stackoverflow.com/a/27024188/2341603) seems to suggest that it is impossible to do what you are suggesting, though the MDN would say otherwise. Either way, you're missing the point -- a regular for loop will work in both situations, and is either required or preferred. Additionally, using a regular loop will work for the intents and purposes of the question. You may be interested in doing some independent research into it or discussing it on the forums. – Obsidian Age Jan 23 '18 at 10:00
0

This will update all links in the current page:

const updateNode = node =>
  node.href = `${window.location}/${node.href}`

document.querySelectorAll('a').forEach(updateNode)
anthonygood
  • 402
  • 4
  • 8