I have a project ready to go, except my lame JS is not working. It’s a toggle that A-Shows or hides a text block, and B-Swaps the button image. But it does not return to the default “More” image. I would greatly appreciate a response that educates me on how the JavaScript is “thinking”!
Example at codepen
if (div.getAttribute("data-text-swap") == div.innerHTML) {
This is never true because you are never setting the data-text-swap
attribute on the img. A very simple way to control this is to toggle a class on the img and then just look for the class to determine the state of the button. But sometimes the simplest method is not always the best, especially for accessibility.
What you are creating here is a disclosure widget. You should have the image inside of a <button>
. Personally, I would use an image for this (using images for text is usually a bad idea). So I would lose the image and just have regular old text in there and you can use either an html triangle entitly or an icon for the pointer. Then, for accessibility you have to add the aria-expanded
attribute to the button. When the widget is closed (no t showing the info) aria-expanded="false"
. When you click to open then aria-expanded="true"
. Now you can look at the aria-expanded
attribute in your JS to determine the state of the widget.
bbsmooth I will start folding in your ideas! One exception: The person I am doing this for specified those images, but with detailed “alt” text for accessibility in the final version. Plus, I’m going into overtime to create an HTML/CSS button.
I’m not surprised by this. Designers often don’t understand how such things affect accessibility. And since you can use plain old HTML/CSS to replicate this button exactly it really doesn’t make sense to use an image here, but sometimes we have to do what they pay us to do
With many revisions, I have narrowed down to a simple JS error “cannot read properties of NULL” that I cannot fully debug. Clicking “Read more…” is supposed to reveal a text box above the existing text. (I included two scripts because the real web page will have both, and I was checking for possible conflict.) Can someone please take a look at this new codepen ?
You can use the dev tools to show you exactly where this error is occurring. It’s the first if
condition in the fncShowHideTxt
function. The error is:
Uncaught TypeError: document.getElementById(...) is null
This means that getElementById
returned null
. I’ll leave it to you to figure out why. Hint: Use codepen’s HTML analyzer to help you find errors.
I would suggest using classList. The DOMTokenList it returns has methods like replace/add/remove/toggle/contains, etc.
For what you are doing, as long as the showtext
class comes after the hidetext
class in the CSS, or just add !important
to the height property so it always overwrites, you can just .toggle() the showtext
class.
window.fncShowHideTxt = function () {
document.getElementById("Disclosed01").classList.toggle("showtext");
};
Holy smoke two IDs. Found another five errors also. No more errors, and also no response to clicking the (now-displaying-wrong “Read more…”). I’m going to experiment with the Chrome dev tools to see if there are scripting tools I haven’t tried.
Wow that a promising fresh perspective; thanks!
UPDATE: The functional root of my js error is trying to trigger two functions. In this case, the blend of CSS, HTML and JS led to two IDs; a no-no. Found out I can have on js function that handles two separate functions. And not have problems with IDs.
Will report back.
@bbsmooth @lasjorg Today, trying to step through js with console.log in web dev tools. To see what happens onclick (it should reveal a box above that pushes down the existing box). But getting an error on “else” inside “fncShowHideTxt()” ?
Looked at this until my eyes are crossed?
The very top of your JS is:
function funcRunTwoFunc() {
function toggleDisclosure(btnID) {...
I’m assuming you intended to finish the definition of funcRunTwoFunc()
Well, the closing brace highlights with the one after the function is declared in VSCode… but… I realized the client expectations required two scripts, and two I had worked fine independently. But couldn’t realistically call two scripts from inside the onclick, unless I put the two scripts inside another function name…
Oh wait, what if …
function funcMaster() {
funcOne();
funcTwo();
}
function funcOne() {
down_1.innerHTML = 'From function 1';
}
function funcTwo() {
down_2.innerHTML = 'From function 2';
}
ALSO that let “elem = document…” stuff was an attempt to make Chrome web dev tools show me if the class content is toggling from hidetext to showtext. Let me know if that is doomed?
I’m not sure I understand what you are trying to do here? I don’t understand the client requirements you are trying to fulfill. All I know is that I get an syntax error message in the console when the page first loads so you’ll need to fix that first.
Apologies. I’ll limit my posts to technical matters.
I’m now getting msg “ReferenceError btnID is not defined.” That’s odd, because the example pen where I got my script works fine?
Without seeing your code we can’t really help. In the example code you posted btnID
is a function parameter. The error message suggests that you didn’t declare it.
Yipes. Been a long day…
function funcRunTwo() {
toggleDisclosure(btnID);
fncShowHideTxt();
}
function toggleDisclosure(btnID) {
// Get the button that triggered this
var theButton = document.getElementById(btnID);
// If the button is not expanded...
if (theButton.getAttribute("aria-expanded") == "false") {
// Now set the button to expanded
theButton.setAttribute("aria-expanded", "true");
// Otherwise button is not expanded...
} else {
// Now set the button to collapsed
theButton.setAttribute("aria-expanded", "false");
}
}
// FOLLOWING WAS function fncShowHideTxt() BUT SYNTAX ERROR
window.fncShowHideTxt = function() {
if (document.getElementById("toggletext").getAttribute("class") === "hidetext") {
document.getElementById("toggletext").setAttribute("class", "showtext");
} else {
document.getElementById("toggletext").setAttribute("class", "hidetext");
};
};
Where is btnID
coming from in your funcRunTwo
function?
function funcRunTwo() {
toggleDisclosure(btnID);
fncShowHideTxt();
}
The only way the variable btnID
would be available to the function is if it was declared somewhere outside the function scope.
In the example at Adrian Roselli’s codepen, I could not find it in either his HTML or CSS. I kept wondering what I overlooked. So here is that link.
You have to learn how scopes work. I know you are new and learning so that is just part of the process. I would suggest you go through the JS curriculum to learn more.
In the example code you linked to btnID
is a function parameter and it is getting its value from the argument in the HTML.
// the argument passed to the function is this.id
onclick="toggleDisclosure(this.id);"
// the parameter is btnID
function toggleDisclosure(btnID) {
...code
}
So btnID
containes the value of this.id
.
Some examples:
function logValueOfParameter(parameter) {
console.log(parameter); // Some value pass as an argument
}
logValueOfParameter('Some value pass as an argument');
const outerVariable = 'Some value that exists in an outer scope';
function logValueOfOuterVariable() {
console.log(outerVariable); // Some value that exists in an outer scope
}
logValueOfOuterVariable();
function logValueOfUndeclaredVariable() {
console.log(notParameterOrOuterVariable);
}
logValueOfUndeclaredVariable();
// Uncaught ReferenceError: notParameterOrOuterVariable is not defined
So which of the three examples does your code fit?
function funcRunTwo() {
toggleDisclosure(btnID);
fncShowHideTxt();
}
It would work if you passed the element id as a string argument to the function.
function funcRunTwo() {
toggleDisclosure('someElementId');
fncShowHideTxt();
}
function toggleDisclosure(btnID) {
// now btnID is the string 'someElementId' that was passed as an argument
// getElementById will look for an element with the id 'someElementId'
var theButton = document.getElementById(btnID);
...code
}