Reveal Hidden element onclick while hiding other elements

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?

He means the actual helper is in the head ( or within a hype function, amended accordingly) But calling it for help is meant to be done from within a hype elements innerHtml

Hypeelement on the stage is chosen -> menu -> edit -> edit innerHTML
you can store any regular js, css, html here ...

So IF you need a function to be global, you need create a persistent symbol, hidden or off stage, and assign the function to that using innerHTML?

Seems like a an opportunity as a feature in Hype to encapsulate Head HTML scripts as global with the selection of a checkbox? Or maybe this case is not common...

Still think you misunderstand.

The function in the head is effectively global already.

This is why you can call to it from within the rectangle.

Is your problem that you are not using the exported html file but it instead using your own.
If so you may just want to copy the function to your own html head.

Or do as @MaxZieb says and put it in an Hype function

This is exactly what I am doing. In my Hype doc I use Head HTML so the function is global. Then on publish (->html5 folder) I copy the functions to the end file that used to display the Hype doc. This usually works well but in this last case it created a condition where the script was still looking for hypeDocument. Jonathans suggestion to add the Object value of [0] worked just fine. But I am trying to fully understand both the proper methods that should be used and if this was a bug.

So now I think I should explore using a Hype function to better isolate within the Hype container/environment (rather than Head HTML).

Ok. Well it is not a bug just procedure.

I think is if you do not need to use the head then don't.

I see you doing this

__MigrationHistory (empty)<br>
<a href="#" onclick="showElement('MigrationLog')">__MigrationLog</a><br>
__MigrationLogCurrent<br>
__RefactorLog<br>
__SchemaSnapshot<br>

SM_AutoActionsLog<br>
<a href="#" onclick="showElement('SM_BillingAddress')">SM_BillingAddress</a><br>
SM_BlastSettings<br>

SM_DontSolicitList<br>
SM_DynamicWIP<br>
SM_EmailTemplates<br>
SM_EmployeeDepartment<br>
<a href="#" onclick="showElement('SM_EventsStatistics')">SM_EventsStatistics</a><br>
SM_Feedbacks<br>
SM_Invoice<br>
SM_Invoice_Archive<br>

in the innerHTML which would need the functions in the head but not sure why you need the structure above ?

What you are seeing is a list of items that get assigned the showElement function that then targets a hidden layer. This layer contains information presented on the same page and also hides any other similar layers/elements that might have been displayed using the same function.

The end goal is to have this list (truncated in the example) linked to information on each Database Table Name (which is what these actually are). In some cases I move onClick to a different scene if more visuals are needed. The showElement function is global also because another Scene uses this function to show Stored Procedures from a similar list.

So maybe structure it like so

<span class="datbasname" name="MigrationLog">__MigrationLog</span><br>
<span class="datbasname" name="SM_BillingAddress">SM_BillingAddress</span><br>
<span class="datbasname" name="SM_EventsStatistics">SM_EventsStatistics</span><br>

And have a hype function that adds an addEventListener to each list item using the class name datbasname ( meant it to be databasname but misspelled it, lol )

and get the value from the name attribute.

var datbasnames = document.querySelectorAll('.datbasname')
 
for (let i = 0; i < datbasnames.length; i++) {
  datbasnames[i].addEventListener('click', listener);
}



function  listener(){
 
 var val = this.getAttribute('name')
 
   var blockEl_ = document.querySelectorAll('.blockEl')
		
		for (let i = 0; i < blockEl_.length; i++) { 
  					hypeDocument.getElementById(blockEl_[i].id).style.display='none';
			}
  
		hypeDocument.getElementById(val).style.display='block';
		 
 
 }

And do away with all the head code.

SLM_DB_R2_v2.hype.zip (131.3 KB)

Yes, that works well. Thanks. I did update the text list to be proper anchors so we know which are linked to some resource or not.

But, now I lost my ability to link to the other scenes which was a secondary function in showElement()

function goScene(val2){
	var sceneName = (val2);
	hypeDocument.showSceneNamed(sceneName, hypeDocument.kSceneTransitionCrossfade, 1.1)
	};

I created a new separate goScene() function, loaded it with On Scene Load but that throws a "Uncaught ReferenceError: goScene is not defined" error.

Since the function is fired using an onclick event I tried removing it from the On Scene Load but getting the same error. :tired_face:

SLM_DB_R2_v3.hype.zip (128.3 KB)

A couple things to note:

This is because the function would be made within the scope of that function, and not globally visible.

If you want to make it as a global, you can instead define it as:

window.goScene = function (val2){

Functions made in the Hype editor are not assigned to the global scope. Therefore if you call it like in your code:

<a href="#" onclick="goScene('Notes')">Notes</a><br>

It will not find it, since you are trying to call a global.

Instead, it is assigned in the .functions() array of a hypeDocument object.

The getHypeDocument() call is really something that was supposed to help out for calling it in these situations by either using it at that time or assigning as a global hypeDocument object so you could call it like hypeDocument.functions().goScene(...).

However, it appears you have removed getHypeDocument() from the head. It does seem like from a console error you have an element with inner HTML that's trying to use it though.

As another point on this, you are passing a string into the goScene() function, but this is not really good programming practice since hype functions should be taking (hypeDocument, element, event) arguments.

Note that On Scene Load action will run the function at that time. So this is probably also inappropriate. It is created when your document loads.

showElement does appear to be a setup function, so this would be okay to use at this time. (That said, I think showElement may not be the best name, since it implies it will show an element when invoked).

It is a hidden Symbol that was initiating the Global Hype Document.
hypeDocument-presistent
Now removed in the project below.


The point of changing the text links to include a name attribute and class so you could add a listener to each was so you could avoid putting a function calls directly in the innerHTML.

I missed that you had also had another one in there to change scene.
But you just needed to take the idea of adding your listeners and use a similar one for changing scene.

<a href="#" class="datbasname" name="MigrationLog">__MigrationLog</a><br>
<a href="#" class="datbasname" name="SM_BillingAddress">SM_BillingAddress</a><br>
<a href="#" class="datbasname" name="SM_EventsStatistics">SM_EventsStatistics</a><br>
<a href="#" class="showscene" name="Notes" > Notes</a><br>

In the Hype Function now named initLinks
We can put all of the link inits that add listeners and the functions that do the work.

/// init listiner for show / hide element links	
var datbasnames = document.querySelectorAll('.datbasname' )
 
for (let i = 0; i < datbasnames.length; i++) {
  datbasnames[i].addEventListener('click', showeHidelements);
}

/// init listiner for show scene links
var showscenes = document.querySelectorAll( '.showscene')
 
for (let i = 0; i < showscenes.length; i++) {
  showscenes[i].addEventListener('click', goScene);
}


/// Go to Scene 
function  goScene(){

var sceneName  = this.getAttribute('name');

		hypeDocument.showSceneNamed(sceneName, hypeDocument.kSceneTransitionCrossfade, 1.1);

}


/// Show hide elements

function  showeHidelements(){
 
 var val = this.getAttribute('name')
 
    var blockEl_ = document.querySelectorAll('.blockEl')
		for (let i = 0; i < blockEl_.length; i++) { 
  					hypeDocument.getElementById(blockEl_[i].id).style.display='none';
			}
  		hypeDocument.getElementById(val).style.display='block';
 }

SLM_DB_R2_v4.hype.zip (133.4 KB)

I have no idea of your real setup but all of this is to help keep hype functions within hype and not have to go to global/head ( if you do not need to ?)

If you do need global then for your case @jonathan 's original solution I think works best with your original setup.
var hypeDocument = Object.values(HYPE.documents)[0];

Also if you wanted to not use any innerHTML


Single function for all links

     var val = element.dataset.name 
	 
	 if (element.classList.contains('dataBase')){
	 		var blockEl_ = document.querySelectorAll('.blockEl')
			
			for (let i = 0; i < blockEl_.length; i++) { 
  					hypeDocument.getElementById(blockEl_[i].id).style.display='none';
			}
			
  		hypeDocument.getElementById(val).style.display='block';
 
	 }
	 
	 if (element.classList.contains('changeScene')){
  

			hypeDocument.showSceneNamed(val, hypeDocument.kSceneTransitionCrossfade, 1.1);
 		}

SLM_DB_R2_v5.hype.zip (137.4 KB)

1 Like