(Not using JQuery)
In order to ask this question properly, I have made a simple example of a website prising three pages A, B and C. Each of the pages are linked to a single JavaScript file.The JavaScript file is linked at the bottom of the body tag. Here is an example of one of the html pages:
<html>
<head>
<title>Page A</title>
<link rel="stylesheet"
type="text/css"
href="temp.css">
</link>
</head>
<body>
<h1 id = "headingA">Page A</h1>
<button id="enterA">Enter</button>
<script src = temp.js>
</script>
</body>
</html>
All three pages look alike, apart from the obvious substitutions of "A" for "B" and "C".
//this button is on page A
var btnA = document.getElementById("enterA");
btnA.onclick = function () {
"use strict";
window.console.log("Button A Pressed");
window.open("/pageB.html", "_self");
};
//this button is on page B
var btnB = document.getElementById("enterB");
btnB.onclick = function () {
"use strict";
window.console.log("Button B Pressed");
window.open("/pageC.html", "_self");
};
//this button is on page C
var btnC = document.getElementById("enterC");
btnC.onclick = function () {
"use strict";
window.console.log("Button C Pressed");
window.alert("Button C Pressed");
};
Obviously this isn't going to work because only one page can be loaded at any one time, so the elements that the script is trying to grab on the pages that are not loaded will cause a script error.
I can think of several ways to approach this problem, but I feel like a hack, and the reason I am asking here is for a best practice solution, as believe this must be second nature to practicing developers (unlike myself).
(Not using JQuery)
In order to ask this question properly, I have made a simple example of a website prising three pages A, B and C. Each of the pages are linked to a single JavaScript file.The JavaScript file is linked at the bottom of the body tag. Here is an example of one of the html pages:
<html>
<head>
<title>Page A</title>
<link rel="stylesheet"
type="text/css"
href="temp.css">
</link>
</head>
<body>
<h1 id = "headingA">Page A</h1>
<button id="enterA">Enter</button>
<script src = temp.js>
</script>
</body>
</html>
All three pages look alike, apart from the obvious substitutions of "A" for "B" and "C".
//this button is on page A
var btnA = document.getElementById("enterA");
btnA.onclick = function () {
"use strict";
window.console.log("Button A Pressed");
window.open("/pageB.html", "_self");
};
//this button is on page B
var btnB = document.getElementById("enterB");
btnB.onclick = function () {
"use strict";
window.console.log("Button B Pressed");
window.open("/pageC.html", "_self");
};
//this button is on page C
var btnC = document.getElementById("enterC");
btnC.onclick = function () {
"use strict";
window.console.log("Button C Pressed");
window.alert("Button C Pressed");
};
Obviously this isn't going to work because only one page can be loaded at any one time, so the elements that the script is trying to grab on the pages that are not loaded will cause a script error.
I can think of several ways to approach this problem, but I feel like a hack, and the reason I am asking here is for a best practice solution, as believe this must be second nature to practicing developers (unlike myself).
Share Improve this question edited Feb 24, 2016 at 21:22 Sam Hanley 4,7557 gold badges38 silver badges64 bronze badges asked Feb 24, 2016 at 21:08 Jason210Jason210 3,3802 gold badges18 silver badges18 bronze badges 1-
1
It's quite easy,
getElementById
returnsnull
if the element isn't there, so all you need to do isif ( btnA !== null ) btnA.onclick...
– adeneo Commented Feb 24, 2016 at 21:11
3 Answers
Reset to default 3There's no reason to have JavaScript that's specific to one page live in a .js file that's loaded across all your pages. In fact, it's potentially risky, because if you introduce elements with the same name, you could have ambiguous and unexpected behavior. You can (and usually will, on non-trivial projects) load more than one JavaScript file, per page, so while there's many ways to architect your code, here's one idea that I'd say is mon practice:
Keep your shared, non page-specific JavaScript in one file, such as
- Common.js
Then for each page, create a page-specific JavaScript file:
- PageA.js
- PageB.js
- PageC.js
Load the Common.js file across all of your pages, as you are today, but on each page, additionally load the script file containing that page's specific functionality. As mentioned in the ments, you could also write your JavaScript to check for the existence of the elements in question and act accordingly, but I'd encourage you to just start forming better habits around code organization and avoid the problem altogether.
Wrap each in a null check as below. If the button doesn't exist on the page it will not try to bind the onClick event.
//this button is on page A
var btnA = document.getElementById("enterA");
if (btnA != null) {
btnA.onclick = function () {
"use strict";
window.console.log("Button A Pressed");
window.open("/pageB.html", "_self");
};
}
I agree with sphanley's answer, in that that is one possibility.
Here are a few other options to consider:
If there isn't going to be any other functionality in the
onclick
handler than merely linking, you could consider simply having links in the HTML pages, styled as a button:<a href="/pageB.html" class="button">Enter</a>
... and then in the stylesheet:
a.button { /* styles to make links look like a button */ }
Another option could be to have one generic
id
on the button and have the link in some attribute of the button, like so:preferably prepend custom attributes name with data- 1
<button id="enter" data-href="/pageB.html">Enter</button>
...or use some other custom attribute for identifying the targeted resource
<button id="enter" data-target="enterA">Enter</button>
... then abstract the script, to read out the relevant attribute, like so:
var btn = document.getElementById( 'enter' ); // I like to use addEventListener in stead of the direct .onclick handler btn.addEventListener( 'click', function( e ) { // when using data-href: window.open( this.dataset.href, "_self" ); // when using data-target: switch( this.dataset.target ) { case 'enterA': window.open( "/pageB.html", "_self" ); break; case 'enterB': window.open( "/pageC.html", "_self" ); break; case 'enterC': // do something else? break; } // or, you could also use a map with targets, in stead of a switch statement, of course: var targets = { 'enterA': '/pageB.html', 'enterB': '/pageC.html', 'enterC': 'some other page', } if( targets.hasOwnProperty( this.dataset.target ) ) { window.open( targets[ this.dataset.target ], "_self" ); } // etc. } );
1.) more info on data attributes