Hide the menu when tapping outside on a tablet device

Currently working with HTML, CSS, and JS (specifically Angular)

  • I have a Header menu that contains dropdown sub-menus and sub-sub-menus in desktop view.
  • On a PC, the sub-menus appear on hover and clicking on an entry redirects you somewhere.
    • Clicking on the main entry leads to a different location - serving as both a link and the trigger for the dropdown menu upon hover.
  • Not every root element has a sub-menu.
  • There is a separate mobile menu created using media queries for width. However, Tablets in landscape mode display the desktop style, causing some issues.

When testing on tablets (Safari iOS and Chrome for iPad) interesting behavior is observed...

  • If an element does not have a dropdown, tapping on it directs you to the link.
  • If an element has a dropdown sub-menu,
    • The first tap activates the hover effect without triggering the link but reveals the menu.
    • A second tap activates the link.

Quite intriguing!

The problem arises when the menus do not disappear upon tapping off them.

  • Tapping anywhere on the page itself has no effect (no click-event is raised).
  • Tapping on another clickable element clears the menu while triggering the link associated with that element.

Initially, I thought of adding a transparent layer across the page under the menu to bind a click event for clearing the menu. However, I faced difficulties making both the transparent layer and underlying page clickable simultaneously. Check out the challenges encountered here.

Even setting the click event on the body to trigger a bubble up did not work as expected (click event didn't fire.)

Experimented with ngTouch which triggered click events everywhere but disrupted the behavior of opening sub-menus - all links started activating immediately, hindering access to the sub-menus.

Any insights or suggestions would be greatly appreciated! Help needed!

Answer №1

To ensure that the dropdown menu is hidden when a click occurs outside of it, you can use the following code snippet:

$('html').click(function (e) {
    if (e.target.id != 'yourDropdown') {
        $('#yourDropdown').hide();
    }
});

Answer №2

Instead of depending on 'mobile browser magic', I prefer to implement it manually. While I don't have experience with Angular, in jQuery the code would likely resemble something like this:

$('.menu li').on('click', function(e) {
    var $target = $(this);
    var $sub = $target.children('ul');

    // only if sub and not yet active
    if ($sub.length && ! $target.hasClass('active')) {
        // show sub
        $target.addClass('active');
        // done
        e.stopPropagation();
        return false;
    }

    // normal click action triggered here
    alert($target.children('a').text());
    e.stopPropagation();
});

$('html').on('click', function(e) {
    // clear all active menu items
    $('.menu > li.active').removeClass('active'); 
});

For a demonstration, you can check out this quick example: http://jsfiddle.net/b0aqr1wc/

Answer №3

:Sigh: Earlier today, a coworker shared with me a clever solution to this problem that worked like magic:

Implement the "cover sheet" technique, where the sheet collapses simultaneously with the menu.

Although you may lose the ability to interact with the background page for just one tap, the user will clearly see the menu collapsing and be prompted to give it another try.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Steps to insert a personalized attribute into a TypeScript interface

UPDATED EXPLANATION: I'm fairly new to TypeScript, so please bear with me if this question seems basic. I'm working with an existing library (ngx-logger) that I don't want to or can't modify. My goal is to create a service that generat ...

The D3.extent() function is raising a TypeError because it is unable to iterate over the

I have been struggling with this issue for the past few hours, and I could really use some help. I'm not very familiar with using D3 in conjunction with React. Essentially, I have an anomaly detection algorithm running on the backend Flask App that r ...

Using Node.js to update information within Firebase

Here's a problem I'm facing: I have a cron job running in Node.js that sends data to a Firebase database every minute. The issue is, even when there are no changes, the database still receives information. Take a look at my code snippet below: l ...

What is the best way to bring a JavaScript file from the source file into an index.html document

I am currently in the process of developing a system using React, and as someone new to the framework, I have encountered an issue. I need to include a JavaScript file in my index.html that is located within the src folder. This js file is essential for th ...

JavaScript: End the program upon clicking CANCEL

Scenario: In my application, there is a confirmation pop-up message that appears when I try to save an entry. Clicking the OK button proceeds with saving the entry, while clicking the CANCEL button should go back to the booking content page - this functio ...

Configuring a timeout for your Next.JS API can help optimize the performance

Due to restrictions on another API, my own API takes 10 minutes to return a result. When running locally, I am able to wait and successfully receive the data after 10 minutes. However, when deployed on Vercel, I encounter a timeout error (status code 504). ...

AngularJS failing to execute Ajax request

I've been working on implementing an Ajax call in a controller to retrieve a list of all the students, but I'm having trouble getting it to work when clicking a button. Here is the code that I've written - can anyone help? module.controll ...

Move the image inside the box without directly following the mouse cursor, but at a slightly faster pace

I am facing an issue with a Vue component that allows me to zoom in on an image and move it around the container. The problem is, when the image is zoomed in, it moves faster than the mouse due to using the scale transform. Additionally, I noticed that cl ...

How can I retrieve all element attributes in TypeScript using Protractor?

I came across this solution for fetching all attributes using protractor: Get all element attributes using protractor However, I am working with TypeScript and Angular 6 and struggling to implement the above method. This is what I have tried so far: im ...

"Encountering Issues with Angular's Modules and EntryComponents during Lazy Loading

Upon lazy loading an Angular module, I encountered an issue when trying to open my DatesModal that resulted in the following error: No component factory found for DatesModal. Have you included it in @NgModule.entryComponents? The declaration and entryCom ...

Configuring webpack for live reloading and Hot Module Replacement on static pages

The title of this post may not be very clear, but I appreciate your patience. I am currently in the process of setting up React for an older Rails application that uses static ERBs. Due to the size of the project, I am gradually transitioning towards a Si ...

Chrome extension: some APIs disappear after chrome.runtime.reload() is called

Issue with my Chrome Extension involving the chrome.tabs API. Extension runs smoothly, but encounters a problem after chrome.runtime.reload(); occasionally, the chrome.tabs reference becomes undefined upon restart. This renders the extension unusable and ...

Retrieving data from a dynamic form using jQuery

Can someone assist me with the following issue: I have a dynamic module (generated by a PHP application) that includes input fields like this: <input type="text" class="attr" name="Input_0"/> <input type="text" class="attr" name="Input_1"/> ...

Utilize jQuery to showcase elements in a dropdown menu

Hey everyone, I'm working on an ASP.NET MVC4 project and I'm using a jQuery script on the edit page. However, I am encountering an issue with displaying elements on the page. Here is the initial HTML markup of my dropdown before any changes: & ...

Updating the `link` function to target a specific DOM element within an Angular 2 component

Angular 1 uses the link function in a directive to target DOM elements. link: function (scope, element, attr) { // do something with element[0], e.g. put generated graphics // inside the node } What is the equivalent feature in Angular 2? ...

Incorporating JSTree Into Your Website's Heading: A Step-By-Step

I'm in search of a way to integrate the following code snippet as a JSTree into the heading section of a webpage, depicted below: <div id="jstree"> <ul> <li>Core 1 <ul> & ...

Tips for maintaining space beneath an image when text wraps around it

.blogimgarea { width: 38%; padding-right: 26px; float:left; } img{max-width:100%} .blogtextarea { width:55%; padding:22px 32px 0 0; float:right; } <div class="newpostregion pt70"> <div class="blogimgarea"> <img class="featblogimg" src="https ...

Error message in TypeScript: A dynamic property name must be a valid type such as 'string', 'number', 'symbol', or 'any'

Attempting to utilize the computer property name feature in my TypeScript code: import {camelCase} from "lodash"; const camelizeKeys = (obj:any):any => { if (Array.isArray(obj)) { return obj.map(v => camelizeKeys(v)); } else if (ob ...

How to access v-model from a separate component in Vue.js

How can I access a v-model that is located in a different component? The search field is within the App.vue file and I am trying to activate the :search='search' property in the Datatable.vue component. Code in App.vue: <v-text-field ...

Extending a universal design concept to a new theme within the MUI (Material UI) framework

I have implemented MUI's ThemeProvider and set up a Themes.js file. Within this file, I have defined the globalTheme for managing global styles such as typography and border-radius. My intention is to extend the properties of globalTheme to both light ...