Reveal Hidden element onclick while hiding other elements

I'm trying to show a grouped element when clicking on an href link in a text object.

The project will have a very long list of links (50+ eventually) and is being used to document a large database project.

I've learned that internal Functions won't work so I am looking for a generic function in the Head HTML. It will take the parameter which is the ID of the hidden element and change its style to "visible".

I'm successfully passing the parameter from the link ("Show Element 2 (Head HTML function)") but the hidden element is not showing.

I wonder if the problem (other than any javascript coding errors) is that using the Display -> Hidden in the Element tab does more than just setting the style as display:hidden ?

Maybe I should use a common class to hide the elements?

Thanks for any advice on this!

Edit to remove outdated Hype file

I've further tested the ideas about hiding the element with a class. And then changing the function in the Head HTML to use display:block;

Reference:

.hidden {
display:none;
}

<script>
	function showElement2(val){
	console.log(val);
	var target = (val);
	alert(target);
	hypeDocument.getElementById(target).style.display='block';
	};
</script>

But now after "alert(target);" successfully fires I see an error
Uncaught ReferenceError: hypeDocument is not defined
In the browser inspector... Updated Hype file attached

Edited to remove outdated Hype file.

will help:

1 Like

Using Max's getHypeDocument function worked well. I ended up setting it as a persistent symbol as the ini on scene load did not work nor adding to the current Head HTML. Thank you h_classen and MaxZieb for this.

So the current file shows elements based on a click from a text field link. Sweet!
But as multiple links are clicked the elements stack on top of each other. Any tips on closing all the others when a new element is displayed?
Will I need to create an array of every potential element and then hide those before displaying the next one?

ShowOnClick.hype 2.zip (52.1 KB)

well a class or data-attribute to find and change an instance will do the job ...

and regarding setup: if the content you'd like to show is "quite" simular regarding its structure ... why not do a dynamic load instead of hardcoded groups of elements ...

This sounds similar to what was discussed here... Rogue Button Behaviors on animation ...and basically I suggested simply using JavaScript.

Are you having the same problem?

If so, I'll have a YouTube video online in a few of days. (Hopefully, HA HA!) It sounds like I picked a useful topic. But if you don't want to wait, here's the short version...

First, select all the elements...

var maps = document.querySelectorAll(".🗺"); // Don't forget the dot, very important 😊

(Yes, I use emoji as class names — it's valid :crazy_face:)

Then, I just hide them all...

 maps.forEach((e) => { e.style.opacity = 0; });

So basically, that's what I do.

Then, I make the elements I want appear. In this case, it's changing the opacity, but changing the display is also another option.

Here I get the selected map from the form/input...

var selectedMap = document.querySelector("input[name='🌎']:checked").value;

...and then I make it visible...

document.getElementById(selectedMap).style.opacity = 1;

I'm really excited about this video, so maybe it will be helpful to you too when it's done. It should be easier to understand when you can see it.

Photics,
The Rogue button post is no longer has active links to view the project. But, it sounds like you are hiding all with the opacity value and then bringing back those you want to see by targeting a select element and then changing just that elements opacity to show..?

My case is I have a function that reveals hidden elements BUT the user can still click on other "links" which continue to reveal more elements. The result is a bunch of stacked on top of each other elements (not desirable).

Currently, I put a simple button that reloads the page ( Clear ). It works but a more elegant solution would be to put the prior/last clicked element into a variable and then on the next click, show the new element and re-hide the prior.

Something like:
IF var current is not null (undefined){
hide current
then show new current } else { show current }

But I have no idea how to do that in JavaScript. It took me long enough to get the current JavaScript working. I'll put it on my list :slight_smile:
It's a transitory object of sorts. If no priors were selected go ahead and show it. But if there is a prior selected element, hide that one and now show the new one. If this were PHP I could set a $_SESSION value then check to see if it exists and then pull from it or the incoming elementID. Or populate an Array and search that for 1 value as we are not looking at all elements just IF there is one prior selected or if this is the first click.

That's right. I use opacity to fade between images, looks nicer, but I could have used style.display = none

Ah, in the map project, that is the desired outcome. They're supposed to be stacked.

It sounds similar to this project...

https://photics.com/free-template-tuesday-11-tumult-hype-multilingual/

It uses LocalStorage to get the previously selected language. So, if I select "Great Britain", that's stored locally and then that value is retrieved when the project is loaded again. If there is no value, use the browser's language. If that's not a match, default to English US.

This is that code...

// Check if a flag was selected or the language has been set already

if (element.id.length >= 2 && element.id.length <= 5){
column(element.id); // Search for a data column that matches the selected flag
localStorage.nl = id; // Save the prefered Navigator Language column ID number.
console.log(localStorage.nl);
} else if (localStorage.nl > 0) {
var id = localStorage.nl;
} else {
	if (data[0].indexOf(nl) > 0) {
	column(nl);  // Use the browser language if there's a match
	} else {
	column("en-US"); // Default to "en-US" if all else fails
	}
}

I have a different way of checking for undefined. HA HA... but basically it's looking for something between two and five characters.

If you don't understand that code, it's OK. The main idea is... maybe LocalStorage is what you're looking for?

1 Like

just add a common class like 'popup' to those elements
then add

var currSceneEl = document.getElementById(hypeDocument.currentSceneId());
var popUpEls = [ ... currSceneEl.querySelectorAll('.popup') ];
popUpEls.forEach(function(el){el.style.display='none'});

at the top of your function that shows up the elements

Maybe LayerRevealer helps.

PS: I also got a version that works with multiple revealer groups on my hard disk. Most user only need only one revealer group… else let me know.

Hmm,
If I understand right.
I would think all you need to do is give each element group a class name.
Then just use the simple trick of hiding them all at the beginning of the showElement2() function

function showElement2(val){
		//var hypeDocument = getHypeDocument();
		var blockEl_ = document.querySelectorAll('.blockEl')
		for (let i = 0; i < blockEl_.length; i++) { 
  				
  					hypeDocument.getElementById(blockEl_[i].id).style.display='none';
			}
		
		console.log(val);
		var target = (val);
		// alert(target);
		hypeDocument.getElementById(target).style.display='block';
		};

ShowOnClick.hype.zip (55.9 KB)

1 Like

Thanks to everyone that contributed in helping me solve this issue. Using MarkHunte's code it worked great for hiding any prior displayed elements.

I now need to run off and look up to understand "let" .

I'd really like to retire but like the line from the Godfather; "Just when I thought I was out, they pull me back in" both with JavaScript , C# in asp .net and also Azure Cloud... :tired_face: :slight_smile:

Thanks again, you guys are really great!

1 Like

I'm running into a bit of a problem... The Hype file works as expected when isolated in it's own html document. BUT if the same is wrapped in a theme (not WordPress) I get an Uncaught TypeError: hypeDocument is undefined error when an element clicked to execute the showElement function.

The Hype document shows and actually works on everything accept the showElement function.

I've tried creating a conditional case looking for if (hypeDocument !== undefined) { which did not help. I've tried declaring using "let" which also does not help.

Is there something else I should be doing to extend the hypeDocument to work within another pages framework?

Using getHypeDocument

I am not sure we’re you are running this code? Also the getHypeDocument function is meant to be used only if you are trying to use script inside an Hype rectangle on stage (inner HTML). It basically traverse the DOM tree upwards to find the corresponding hypeDocument. I am also not seeing you actually using it or assign the result?

Also, it doesn’t work when you extract the JavaScript into an external file. For that kind of scenario you would use the Hype event callbacks to hook up a Hype document to some code.

Register Hype Eventlistener

In that approach you an use an external listener to be notified about event in Hype (hence external code file or Head HTML).

Using a Hype function on a scene event

Then there is also the simple case of just using a Hype function on Scene load or prepare for display right in the IDE

Max, I'm currently taking apart the document that Hype generates and the one I need to work (themed). In other words the pages I provide here may change but I have taken the working one:
https://sgdesign.com/slm/SLM_DB_R2.html
and the one being culled of all other content to see just why one works and one does not:
https://sgdesign.com/slm/test2.php

It's interesting that at this point they are almost identical yet one works and the other fails Just on the click firing showElement()

SLM_DB_R2.hype.zip (147.3 KB)

Problem found... Super weird to me but it was due to a < script > with commented out content..

Edit to add: The same script, commented or not, does not interfere if it is above the hype script in the document. Looks like a bug.

It looks like the issue is getHypeDocument() is making a fallback assumption that the last script must be the one where the Hype document comes from:

var ds = document.scripts, hd=HYPE.documents
var e = e || ds[ds.length-1];

In your document, that last script tag is being used instead of the script tag for the *_hype_generated_script.js file, and so it is not properly finding a Hype document.

I'm not really sure why @MaxZieb wrote it that way, but in your document since you only have a single hype document on the page, you can probably just add this as the first line inside of showElement() and be okay:

var hypeDocument = Object.values(HYPE.documents)[0];

Because it it meant to be called from inside a script tag that needs it. As that script tag is being executed it is always just in that moment the last script tag. This works but is not ment to be used outside of a rectangle. It is specially written for getting the hypeDocument from rectangles containing code inside of Hype. Please check the following post for correct usage:

1 Like

Yes, adding the following solves the problem:
But what is this telling the doc? The var declaration using "let" did not work and I am far from a Javascript pro so can you tell me like a 5 year old? :slight_smile:

Hey Max,
What rectangle?

The scripts are in the HTML Head so exported as separate in the generated publish file. I don't see a way to make them self encapsulated in the hype js doc. Maybe I missed a setting?