More intuitive megamenu help

I built a sort of megamenu kind of like except not a dropdown.

Then I read this study about how TTT is actually the worst performing user design possible haha.

An article based on this research:

I am trying to imagine how I can transform it.

If I wanted to move the headers to the left side, and when I highlight them on the left, the information below is displayed on the right, what components would I use?

I want to avoid using repeaters or pulling in other views.
My preference is components and scripting on my view.

Is the space always reserved and displaying the content belonging to one of the headers, or is your expectation that a user see only the headers until hovering occurs?

1 Like

Thanks for helping me.
I don't want to burden you with construction questions.
I think I mainly need keywords and locations to find this stuff.

Space is reserved currently.

I want to make a page that shows only headers until I hover them.

I want to know how I can hover from above and expand down.
I want to know how I can hover from the left and expand to the right.

I am reviewing the menu tree, but I think I want to do something with a dropdown maybe.
I think I mainly need to know where to look to learn the techniques.


I think this Waytek page is really good.
I think I can almost make it with flex containers and style classes.
I can sort of reduce it's number of items to make a simple navigation page.

  1. I wasn't sure how to make the dropdown portion.
    I will mess with dropdowns for a bit. Maybe that is easy.
  2. I don't know how to make the images with a button to get to the next one, that is also animated I think.
  3. I think I can set a boxshadow on hover style, but I am not sure how I can make the flex container get different images for different users based on what they recently looked at.
    3a. I haven't done user detection/recognition before. Not sure what that is under, or keywords to look for.
  4. This is a kind of expandable dropdown that I have not done before. The closest component is a dropdown or menutree that I can recall. Maybe this is a button that toggles visibility on a flex container.
  1. Set up the main menu within whatever container you prefer, and have a View Canvas on the right.
  2. The View canvas should have only one instance which is using whatever View you want to configure.
  3. This instanced View should have a param which is used to build out all of the available options it will display.
  4. This singular instanced view should have its position configured such that it is rendered off-screen (for now). Make sure to set the overflow of the View Canvas to "hidden".
  5. Each of the main menu options should have an onMouseEnter Event (this will be for first "collapsing" any displayed options, and then "expanding" the hidden View with the newly "hovered" options) configured to invoke some specialized code.
  6. This is where you have some decisions to make: you can either do a message handler, or a custom function - just choose one and stick with it; the main menu options should be broadcasting and the View canvas should be listening, or the main menu options should be invoking custom functions which exist on the View canvas.
  7. Essentially, you'll need to have the View Canvas change the location of the instanced View during some sort of transition duration; this will make it appear as if the options are sliding into place.
    NavDemo (11.0 KB)

1 Like

You have been so extremely generous with your time here, thank you so much.
I will use what you shared the best I can to learn.

I was hoping not to use more than one view.
I read that it is not as responsive, but I don't know. Your example looks fast.

Just like anything, the more complicated you make it, the less "responsive" it will be. Perspective is designed to easily accommodate Views in Views in Views, and for something as simple as this you will notice no impact.

Will you please help me understand some of the linkages between the views?
I will try to number the premises so you can specify which ones are wrong, and correct my understanding.

I think I ask a lot though and it is time consuming.
Thank you for helping me as much as you do.

I want to express where my gaps in understanding are.
I want to express what conceptions I am believing for confirmation or correction.
I don't want to burden you, but I do want to learn.

My questions revolving around navDemo:

  1. Main view has two labels with mouse enter events that call the newHover method, delivering their text to it.

  2. The method is on the viewcanvas, and receives two args.

  3. This method receives self, a reference to the invoking component. Is that the labels or the canvas?

  4. Second, this method recieves the option_text parameter.

  5. In this case, the parameter is an "X" for one of the labels, and "Y" for the other.

I thought the labels invoked the function. In the method, self.props.transitionSettings.duration = 0.25
and that prop is on the viewcanvas.
The "invoking component" in this newHover method's context means the component that the method is configured on?

In the method, it says self.props.instances[0].viewParams["input"] = option_text
This creates that viewParameter?
Because when I click on viewCanvas viewParams {0} indicates it has no objects.

On Main view:
6. The mouse enters the label, the label's text goes to an input parameter on the view canvas after a 1.25 seconds.

  1. The view path on the viewcanvas is set to the view named Instanced.
  2. This view will receive the viewParams from the viewcanvas.

When does "input" view parameter exist?
Does the "input" parameter still exist 1.5 seconds after the mouse has left the label?
Will you explain what is causing the collapse for me?

I don't see what sets the position back to -500px.
Does the position remain 0px, but the parameter no longer exists so the value is blank making the appearance of collapse?
I see the transition go to the left though, so something is built into the component with the transition setting, what is it?

The view named instance has a repeater that receives the parameter named "input" from the viewcanvas on the view named Main.

  1. I can see the flex repeater in Instances has a script where a dictionary gets a list from the value of the input parameter property binding.
display_options = [{"label": _} for _ in labels]

I think this is creating the way that the list will be displayed.
The repeater has a path to the view named label, so the instances[0] with the returned list goes to the label as a value.
Why don't I see brackets on the perspective page?
How does the spacing get baked into the label?
I expected "OneTwo" and "ThreeFourFive", so can you explain how the spacing is established?

I want to politely explain my worries and politely ask if there is a way using only one view.

I prefer a more strict no repeaters or views in views policy, except if for overlays that might save me months of time. I make exceptions for months of time.

The performance concerns of views in views seems negligible in this implementation.
I have robustness concerns and I have upkeep concerns.

Partly, I am not comfortable with the linkages, which I don't want to hold me back. So I ask for so much explaining.
Partly, the interactions between multiple views are time consuming to examine, even a month later for me.
So I want to ask, and hope it is not rude to ask given these reasons, is there a way to do expandable primary, secondary, and tertiary horizontal/vertical dropdowns contained in a single view?

The invoking component is the View Canvas.


It both creates it - if it doesn't yet exist - or updates it based on the option_text being passed in. If the param exists and has content, you'll see displayed sub-items. In an effort to not display anything until you hover on one of the main menu items I've not supplied the param yet.

No, not quite. Setting the transition delay is just changing a property - not sleeping. The goal of this script is to quickly move old content out of the way, wait for it to be gone, update the params based on the incoming option_text value`, then slide the updated content into view, and wait for that to complete. The final sleep might be unnecessary due to the asynchronous nature of when this method might be invoked.

The View param always exists on the View being instanced. The param does not exist in ViewCanvas.props.instances.viewParams until we set it during the first execution of the newHover custom method.

Once we invoke the newHover method the input param is placed and stays in place until the page is refreshed, or is updated by a new invocation of the newHover method.

    self.props.transitionSettings.duration = 0.25
	self.props.instances[0].left = "-500px"

This piece of code is telling the ViewCanvas to position the instanced View so that it's origin (top-left corner) is 500px to the left of the top-left corner of the View Canvas. Since overflow is set to "hidden" the content is effectively slid out of view to the left of the ViewCanvas.

The instanced view is collapsed AND THEN EXPANDED every time the user's mouse enters one of the main menu Labels.

No, the appearance of the collapse is the combination of use changing the location of the instanced View's origin in conjunction with the transitionSettings.duration property.

We're binding the instances property of the Flex Repeater, which is an array (list). We're essentially making a list of objects, where each object has one key (label) and that key will be mapped as a param. We're making the Flex Repeater look like this:

path = "Label"
instances = [
    {"label": "One"},
    {"label": "Two"}

Each of those instances will be anew instance of the View defined by our path, and each key in the object is mapped to a param of that view; in our case here, the "Label" view expects a parma of "label".

The spacing is dependent on the settings defined in the Flex Repeater used in the Instanced View: the current settings use both the default height and width of the View being instanced. If you play with those settings you can manipulate the space between the Labels. Also, you can stack the options one on top of another by changing FlexRepeater.props.direction from "row" to "column".

You asked how to do it. THIS is how you do it. If you don't want Views in Views in Views, you don't get cool functionality. Sorry, but them's the rules.

These are EXACTLY why you should use approaches like this. I 100% guarantee you that templating like this will minimize your upkeep long-term.

Probably with complicated, unnecessary, even-harder-to-maintain, brittle CSS.


I don't want to say or designate the "invoking component" in the wrong way when talking to programmers.

Am I conflating evoke and invoke, or something semantic related?

Or is it that the method is on the viewcanvas and therefore the veiwcanvas is technically invoking the method because of the relationship between them?
Is the label that called that method also said to be invoking?

Every company is going to have different terminology and refer to items, components, events in their own way, so really you just need to settle on some sort of way of describing this that your co-workers will understand and then stick to using that going forward.

It think this might alleviate the confusion: the main menu Labels are acting upon the View Canvas, and requesting that the View Canvas invoke its own newHover custom method*. So in the strictest sense the View Canvas IS the invoking component, though it is invoking the function at the behest of the main menu labels.

This is sort of like saying "The cook prepared a meal because I was hungry". You were hungry, so you requested the cook do something. You didn't actually invoke the burners of the stove - the cook did.

As for evoke vs invoke,
Definition: subject "A" is acting on subject "B".
Example: The Druid invoked the power of the forest to summon strangling vines.
Definition: To remind someone of some thing
Example: The painting evoked strong memories of Alexander's childhood.

*implementation note: the reason the newHover function is on the ViewCanvas and NOT the main menu labels is so that you don't have to modify the function for each label if you make changes in the future.

1 Like

Thanks very much.

Thanks for your articulation, information, patience, and attention to detail.

1 Like

What is a very good way to code a method so that the method knows both if it's instance is the one to keep running, and to block other instances of that method from running on a session?

In this case for example for the method on viewcanvas, what is the best way to communicate to the method that the method is running on the current session, and if the instance is the method to keep going or a duplicate that should not run because it is a redundant trigger?

Or is that something I must take care of outside of the method?

If I move my mouse on and off the field, in this case I observe an expand, contract, and expand again.
I can imagine some methods that I would not want to be triggered when the method is already running.

I think I figured out a couple ways.

I can write a datetime relate key from when the method started to compare against.

Or I can just write that the method is running if it wasn't, and just always check that first in the method.

At the end write it has completed.

The easiest way is to have some sort of custom property which dictates whether an action should take place. In your example, placing a boolean custom property of in_progress on the View Canvas would allow for this, if you change the logic within the newHover method:

if not self.custom.in_progress:
    self.custom.in_progress = True
    # logic as it exists now
    self.custom.in_progress = False
1 Like

Thanks again.

1 Like