How to handle click on Bulma's dropdown component? - javascript

I'm using bulma in an application and I have a dropdown as follows:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.css">
<div class="dropdown">
<div class="dropdown-trigger">
<button class="button"
onclick="javascript:document.querySelector('.dropdown').classList.toggle('is-active')"
onblur="javascript:document.querySelector('.dropdown').classList.toggle('is-active')" aria-haspopup="true" aria-controls="dropdown-menu">
<span>Dropdown button</span>
<span class="icon is-small">
<i class="fas fa-angle-down" aria-hidden="true"></i>
</span>
</button>
</div>
<div class="dropdown-menu" id="dropdown-menu" role="menu">
<div class="dropdown-content">
<a href="#" onclick="javascript:alert('clicked')" class="dropdown-item">
Dropdown item
</a>
<a class="dropdown-item" onclick="javascript:alert('clicked')">
Other dropdown item
</a>
<a href="#" onclick="javascript:alert('clicked')" class="dropdown-item is-active">
Active dropdown item
</a>
<a href="#" onclick="javascript:alert('clicked')" class="dropdown-item">
Other dropdown item
</a>
<hr class="dropdown-divider">
<a href="#" onclick="javascript:alert('clicked')" class="dropdown-item">
With a divider
</a>
</div>
</div>
</div>
I have the onblur event handler so it will close the dropdown when the user clicks outside of it, but then when the user clicks one of the items from the dropdown the blur event gets triggered and the onclick from the item doesn't. How should I handle this?

The click event is triggered the moment you click and release. You can use a onmousedown event instead so that you get to click the item before the blur get triggered:
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.css">
<div class="dropdown">
<div class="dropdown-trigger">
<button class="button"
onclick="javascript:document.querySelector('.dropdown').classList.toggle('is-active')"
onblur="javascript:document.querySelector('.dropdown').classList.toggle('is-active')" aria-haspopup="true" aria-controls="dropdown-menu">
<span>Dropdown button</span>
<span class="icon is-small">
<i class="fas fa-angle-down" aria-hidden="true"></i>
</span>
</button>
</div>
<div class="dropdown-menu" id="dropdown-menu" role="menu">
<div class="dropdown-content">
<a href="#" onmousedown="javascript:alert('clicked')" class="dropdown-item">
Dropdown item
</a>
<a class="dropdown-item" onmousedown="javascript:alert('clicked')">
Other dropdown item
</a>
<a href="#" onmousedown="javascript:alert('clicked')" class="dropdown-item is-active">
Active dropdown item
</a>
<a href="#" onmousedown="javascript:alert('clicked')" class="dropdown-item">
Other dropdown item
</a>
<hr class="dropdown-divider">
<a href="#" onmousedown="javascript:alert('clicked')" class="dropdown-item">
With a divider
</a>
</div>
</div>
</div>
Of course the above is assuming that you would want to close the dropdown the moment you click on one of the menu items.

Related

Populating large HTML div in JavaScript, based on JSON response from AJAX call

I currently have a significant amount of HTML inside a div which is generated within an iteration from a GET request to my .net core server.
Some of the values in the HTML is dynamic data returned from the server.
I've added a button to my website, which when pressed, makes an AJAX call to the server to return a JSON object representing the dynamic values for the next iteration.
So, I would like the JavaScript to add a new div to the DOM, which is the same, and has my dynamic values populated based on the JSON response.
For context, the DIV looks like this (which is from a bootstrap template I purchased):
<div class="card">
<!-- Card header START -->
<div class="card-header border-0 pb-0">
<div class="d-flex align-items-center justify-content-between">
<div class="d-flex align-items-center">
<!-- Avatar -->
<div class="avatar me-2">
<img class="avatar-img rounded-circle" src="#post.ProfileImageUrl" alt="profile picture">
</div>
<!-- Info -->
<div>
<div class="nav nav-divider">
<h6 class="nav-item card-title mb-0"> #post.ProfileName </h6>
<span class="nav-item small"> #post.PostTime</span>
</div>
</div>
</div>
<!-- Card feed action dropdown START -->
<div class="dropdown">
<a href="#" class="text-secondary btn btn-secondary-soft-hover py-1 px-2" id="cardFeedAction" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-three-dots"></i>
</a>
<!-- Card feed action dropdown menu -->
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="cardFeedAction">
<li><a class="dropdown-item" href="#"> <i class="bi bi-bookmark fa-fw pe-2"></i>Save post</a></li>
<li><a class="dropdown-item" href="#"> <i class="bi bi-person-x fa-fw pe-2"></i>Unfollow lori ferguson </a></li>
<li><a class="dropdown-item" href="#"> <i class="bi bi-x-circle fa-fw pe-2"></i>Hide post</a></li>
<li><a class="dropdown-item" href="#"> <i class="bi bi-slash-circle fa-fw pe-2"></i>Block</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#"> <i class="bi bi-flag fa-fw pe-2"></i>Report post</a></li>
</ul>
</div>
<!-- Card feed action dropdown END -->
</div>
</div>
<!-- Card header END -->
<!-- Card body START -->
<div class="card-body">
<p><strong>#post.PostBody</strong></p>
<!-- Card img -->
<img class="card-img img-fluid" src="#post.PostImageUrl" alt="Post">
<!-- Feed react START -->
<ul class="nav nav-stack py-3 small">
<li class="nav-item">
<a class="nav-link active" href="#!"> <i class="bi bi-hand-thumbs-up-fill pe-1"></i>Liked (56)</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#!"> <i class="bi bi-chat-fill pe-1"></i>Comments (12)</a>
</li>
<!-- Card share action START -->
<li class="nav-item dropdown ms-sm-auto">
<a class="nav-link mb-0" href="#" id="cardShareAction" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-reply-fill flip-horizontal ps-1"></i>Share (3)
</a>
<!-- Card share action dropdown menu -->
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="cardShareAction">
<li><a class="dropdown-item" href="#"> <i class="bi bi-envelope fa-fw pe-2"></i>Send via Direct Message</a></li>
<li><a class="dropdown-item" href="#"> <i class="bi bi-bookmark-check fa-fw pe-2"></i>Bookmark </a></li>
<li><a class="dropdown-item" href="#"> <i class="bi bi-link fa-fw pe-2"></i>Copy link to post</a></li>
<li><a class="dropdown-item" href="#"> <i class="bi bi-share fa-fw pe-2"></i>Share post via …</a></li>
<li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#"> <i class="bi bi-pencil-square fa-fw pe-2"></i>Share to News Feed</a></li>
</ul>
</li>
<!-- Card share action END -->
</ul>
</div>
<!-- Card body END -->
<!-- Card footer START -->
<div class="card-footer border-0 pt-0">
<!-- Load more comments -->
<a href="#!" role="button" class="btn btn-link btn-link-loader btn-sm text-secondary d-flex align-items-center" data-bs-toggle="button" aria-pressed="true">
<div class="spinner-dots me-2">
<span class="spinner-dot"></span>
<span class="spinner-dot"></span>
<span class="spinner-dot"></span>
</div>
Load more comments
</a>
</div>
<!-- Card footer END -->
</div>
<!-- Card feed item END -->
Question:
There's a lot of HTML here. What's the best way to build this out in Javascript? Is it just a case of biting the bullet and writing all of the JS code to create each element/class?
Would this be the best practice? Because it effectively means I'm maintaining the HTML markup in two places..
Thank you..!
I usually save the html of the template to be rendered inside an hidden element. Then I can always access it using that element.innerHTML. You could use specialized script tag instead. But the innerHTML part is the same.
After having the HTML as string you have 2 options
build the string with the values you want to populate, then add that as innerHTML to the target container.
but a better approach is to create an element from that html (see function below) then append it and manipulate it otherwise.
// render 5 cards
for (var i = 0; i < 5; i++) {
var html = document.querySelector("#card-template").innerHTML;
var elem = elemFromString(html)
// change something
elem.querySelector(".card-body>p strong").innerText = "card " + i
// append
document.querySelector("#container").append(elem)
}
// usefull utility
function elemFromString(html) {
var dummy = document.createElement("div");
dummy.innerHTML = html.trim();
if (dummy.children.length > 1) {
console.error("expecting one wrapping element for html. will return only firstChild")
}
var result = dummy.firstChild;
result.parentNode.removeChild(result)
return result;
}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap#4.6.2/dist/css/bootstrap.min.css" integrity="sha384-xOolHFLEh07PJGoPkLv1IbcEPTNtaed2xpHsD9ESMhqIYd0nLMwNLD69Npy4HI+N" crossorigin="anonymous">
<div id="container">
</div>
<div id="card-template" style="display:none">
<div class="card">
<!-- Card header START -->
<div class="card-header border-0 pb-0">
<div class="d-flex align-items-center justify-content-between">
<div class="d-flex align-items-center">
<!-- Avatar -->
<div class="avatar me-2">
<img class="avatar-img rounded-circle" src="#post.ProfileImageUrl" alt="profile picture">
</div>
<!-- Info -->
<div>
<div class="nav nav-divider">
<h6 class="nav-item card-title mb-0"> #post.ProfileName </h6>
<span class="nav-item small"> #post.PostTime</span>
</div>
</div>
</div>
<!-- Card feed action dropdown START -->
<div class="dropdown">
<a href="#" class="text-secondary btn btn-secondary-soft-hover py-1 px-2" id="cardFeedAction" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-three-dots"></i>
</a>
<!-- Card feed action dropdown menu -->
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="cardFeedAction">
<li>
<a class="dropdown-item" href="#"> <i class="bi bi-bookmark fa-fw pe-2"></i>Save post</a>
</li>
<li>
<a class="dropdown-item" href="#"> <i class="bi bi-person-x fa-fw pe-2"></i>Unfollow lori ferguson </a>
</li>
<li>
<a class="dropdown-item" href="#"> <i class="bi bi-x-circle fa-fw pe-2"></i>Hide post</a>
</li>
<li>
<a class="dropdown-item" href="#"> <i class="bi bi-slash-circle fa-fw pe-2"></i>Block</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li>
<a class="dropdown-item" href="#"> <i class="bi bi-flag fa-fw pe-2"></i>Report post</a>
</li>
</ul>
</div>
<!-- Card feed action dropdown END -->
</div>
</div>
<!-- Card header END -->
<!-- Card body START -->
<div class="card-body">
<p><strong>#post.PostBody</strong></p>
<!-- Card img -->
<img class="card-img img-fluid" src="#post.PostImageUrl" alt="Post">
<!-- Feed react START -->
<ul class="nav nav-stack py-3 small">
<li class="nav-item">
<a class="nav-link active" href="#!"> <i class="bi bi-hand-thumbs-up-fill pe-1"></i>Liked (56)</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#!"> <i class="bi bi-chat-fill pe-1"></i>Comments (12)</a>
</li>
<!-- Card share action START -->
<li class="nav-item dropdown ms-sm-auto">
<a class="nav-link mb-0" href="#" id="cardShareAction" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi bi-reply-fill flip-horizontal ps-1"></i>Share (3)
</a>
<!-- Card share action dropdown menu -->
<ul class="dropdown-menu dropdown-menu-end" aria-labelledby="cardShareAction">
<li>
<a class="dropdown-item" href="#"> <i class="bi bi-envelope fa-fw pe-2"></i>Send via Direct Message</a>
</li>
<li>
<a class="dropdown-item" href="#"> <i class="bi bi-bookmark-check fa-fw pe-2"></i>Bookmark </a>
</li>
<li>
<a class="dropdown-item" href="#"> <i class="bi bi-link fa-fw pe-2"></i>Copy link to post</a>
</li>
<li>
<a class="dropdown-item" href="#"> <i class="bi bi-share fa-fw pe-2"></i>Share post via …</a>
</li>
<li>
<hr class="dropdown-divider">
</li>
<li>
<a class="dropdown-item" href="#"> <i class="bi bi-pencil-square fa-fw pe-2"></i>Share to News Feed</a>
</li>
</ul>
</li>
<!-- Card share action END -->
</ul>
</div>
<!-- Card body END -->
<!-- Card footer START -->
<div class="card-footer border-0 pt-0">
<!-- Load more comments -->
<a href="#!" role="button" class="btn btn-link btn-link-loader btn-sm text-secondary d-flex align-items-center" data-bs-toggle="button" aria-pressed="true">
<div class="spinner-dots me-2">
<span class="spinner-dot"></span>
<span class="spinner-dot"></span>
<span class="spinner-dot"></span>
</div>
Load more comments
</a>
</div>
<!-- Card footer END -->
</div>
<!-- Card feed item END -->
</div>

dropdown javascript for bulma framework

i have the following problem, i am trying to use two dropdowns using javascript and bulma framework
but the problem is that only one dropdown is displayed when I click on it but if I click on the second one it doesn't open.
<div class="dropdown">
<div class="dropdown-trigger">
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu">
<span>Dropdown button</span>
<span class="icon is-small">
<i class="fas fa-angle-down" aria-hidden="true"></i>
</span>
</button>
</div>
<div class="dropdown-menu" id="dropdown-menu" role="menu">
<div class="dropdown-content">
<a href="#" class="dropdown-item">
Dropdown item
</a>
<a class="dropdown-item">
Other dropdown item
</a>
<a href="#" class="dropdown-item is-active">
Active dropdown item
</a>
<a href="#" class="dropdown-item">
Other dropdown item
</a>
<hr class="dropdown-divider">
<a href="#" class="dropdown-item">
With a divider
</a>
</div>
</div>
</div>
<div class="dropdown">
<div class="dropdown-trigger">
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu">
<span>Dropdown button</span>
<span class="icon is-small">
<i class="fas fa-angle-down" aria-hidden="true"></i>
</span>
</button>
</div>
<div class="dropdown-menu" id="dropdown-menu" role="menu">
<div class="dropdown-content">
<a href="#" class="dropdown-item">
Dropdown item
</a>
<a class="dropdown-item">
Other dropdown item
</a>
<a href="#" class="dropdown-item is-active">
Active dropdown item
</a>
<a href="#" class="dropdown-item">
Other dropdown item
</a>
<hr class="dropdown-divider">
<a href="#" class="dropdown-item">
With a divider
</a>
</div>
</div>
</div>
JavaScript Code:
var dropdown = document.querySelector('.dropdown');
dropdown.addEventListener('click', function(event) {
event.stopPropagation();
dropdown.classList.toggle('is-active');
});
I have the respective libraries loaded both bulma and jquery, but I still can't get both dropdowns to work.
You are on the right track, but you're using .querySelector() incorrectly. See the docs:
The querySelector() method returns the first element that matches a specified CSS selector(s) in the document
Emphasis mine.
The solution is to use .querySelectorAll(). This will return an array of all the dropdowns. You can then iterate through them and attach an eventlistener to them.
document.querySelectorAll('.dropdown').forEach(item => {
item.addEventListener('click', function(event) {
event.stopPropagation();
item.classList.toggle('is-active');
});
});

When tabbing only open dropdown when hitting enter

I have a few dropdowns in a list. Currently, when I hover over the dropdowns they open just fine. However, when tabbing through the website when I tab through each list item the dropdown opens. I would like to only open the dropdown when hitting enter then continue to tab through the menu afterwards while keeping the hover functionality the same.
<div class="container">
<ul>
<li class="dropdown tabindex="2">
<a class="menu-anchor" href="javascript:;" tabindex="-1">Program Areas</a>
<i class="dropdown-toggle" data-toggle="dropdown" style="display: none;"></i>
<div class="dropdown-menu">
</div>
</li>
<li class="dropdown tabindex="2">
<a class="menu-anchor" href="javascript:;" tabindex="-1">Program Areas</a>
<i class="dropdown-toggle" data-toggle="dropdown" style="display: none;"></i>
<div class="dropdown-menu">
</div>
</li>
<li class="dropdown tabindex="2">
<a class="menu-anchor" href="javascript:;" tabindex="-1">Program Areas</a>
<i class="dropdown-toggle" data-toggle="dropdown" style="display: none;"></i>
<div class="dropdown-menu">
</div>
</li>
</ul>
</div>
CSS
.dropdown:hover > .dropdown-menu {
display: block;
}

how to pushup the content when clicks on dropdown list item in bootstarp

Hi,My question is how to drag the content when clicks on any option in
dropdown,colud you please tel me...
it is leftside menu-bar,when clicks on any dropdown item it is covering the below menu-bar list,so i need to drag the other menu bar
list when clicks on any dropdown list..
<ul class="sidebar-menu">
<li>
<a href="index.html">
<i class="fa fa-dashboard"></i> <span>Dashboard</span>
</a>
</li>
<li class="active dropdown">
<a href="general.html" class="dropdown-toggle" data-toggle="dropdown">
<i class="fa fa-gavel"></i> <span>General <span class="caret"></span></span>
</a>
<ul class="dropdown-menu">
<li><a href="#General1" class="btn btn-success" data-toggle="tab" >General1</a></li>
<li><a href="#General2" class="btn btn-success" data-toggle="tab" >General2</a></li>
<li>General3</li>
</ul>
</li>
<li>
<a href="basic_form.html">
<i class="fa fa-globe"></i> <span>Basic Elements</span>
</a>
</li>
<li>
<a href="simple.html">
<i class="fa fa-glass"></i> <span>Simple tables</span>
</a>
</li>
</ul>

Bootstrap - Custom Content In Dropdowns?

As the title states, I'm looking to have one single dropdown then have other HTML content in another dropdown submenu, making the dropdown act as a pop out for HTML content. The issue I'm having so far is that once I try just putting a div and code into the UL tag for the secondary drop down, it no longer stays visible on hover. Here is my current markup,
<li class="dropdown">
<a class="dropdown-toggle" id="drop4" role="button" data-toggle="dropdown" href="#">GAMES <i class="icon-caret-down"></i></a>
<ul id="menu1" class="dropdown-menu" role="menu" aria-labelledby="drop4">
<li role="presentation" class="dropdown-submenu"><a role="menuitem" tabindex="-1" href="#">Battlefield 3</a>
<ul class="dropdown-menu">
<div>
<h1 style="color: #333;">Things</h1>
</div>
</ul>
</li>
The markup is to be honest horrendous as of now, but is there an easier way to have custom content in a Bootstrap sub drop down? This way is causing miles upon miles of issues.
You can think of this way:
<ul class="unstyled">
<li class="dropdown">
<a class="dropdown-toggle btn" id="drop4" role="button" data-toggle="dropdown" href="#">GAMES <b class="caret"></b></a>
<ul id="menu1" class="dropdown-menu" role="menu" aria-labelledby="drop4">
<li role="presentation" class="dropdown-submenu"><a role="menuitem" tabindex="-1" href="#">Battlefield 3</a>
<ul class="dropdown-menu">
<li>
<div class="custom">
<h1 style="color: #333;">Things</h1>
</div>
</li>
</ul>
</li>
</ul>
</li>
</ul>
This makes the menu more semantically correct and valid... I feel something you might require in the CSS is:
.custom {padding: 0 10px;}
.custom h1 {font-size: 1.5em; margin: 0; padding: 0;}
Preview
Fiddle: http://jsfiddle.net/praveenscience/yEJ3c/
If you don't need the other children and you're just looking for a rich dropdown, perhaps you want to be using the Popover component instead of the Dropdown component.
Update for Bootstrap 4 - it's now easy to add custom HTML to dropdowns:
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle btn-sm" type="button" id="dropdownMenuButton" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
Dropdown
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item active" href="#">Option one</a>
<a class="dropdown-item" href="#">Another action</a>
<a class="dropdown-item" href="#">Something else here</a>
<a class="dropdown-item" href="#">
<div class="row">
<div class="col">Html</div>
<div class="col">Content</div>
<div class="col">Here</div>
</div>
</a>
</div>
</div>

Categories

Resources