I need your valuable suggestions and guidance to help me get out of this tricky situation.
I have a scenario, where I need to build a Dropdown like the below one.
<ul class="dropdown">
<li>America</li>
<li>Brazil</li>
<li>China</li>
<li>Denmark</li>
<li>Egypt</li>
</ul>
The desired functionality is that I should be able to use keyboard input to scroll through the items, lets say i press key "E" on my keyboard it should hover/focus on Egypt.
I realize this functionality cant be achieved using UL>Li, However we can use Select tag to implement this functionality.
<select class="dropdown">
<option>America</li>
<option>Brazil</li>
<option>China</li>
<option>Denmark</li>
<option>Egypt</li>
<select>
But when we use select tags, we cannot style the dropdown, Especially like CSS padding doesnt work on select tag dropdowns on most broswers.
All I wanna ask Is, How can I build a drop-down with these 3 functionalities :
1.Open on Tab key press
2.Browse listed items using key input.
3.Style the dropdown for cross broswer compatibility.
I did spend ample time in finding a solution for this online, I dint find any perfect solution apart from this plugin
https://silviomoreto.github.io/bootstrap-select/
I'd regret to say that I'm not allowed to use any external plugins at work.To achieve this only tools I'm allowed to use is Bootstrap, jQuery, Javascript ,CSS ,HTML and cant use angular.
Can anyone help me with this.
Unfortunately, it’s not possible to style a <select> dropdown consistently across all browsers. Bootstrap Select and other similar plugins (e.g. Chosen) use JS and custom markup to create a faux <select>, which is bad for accessibility (see https://vimeo.com/84970341#t=614s).
Personally, I would use a <select> element and live with the default browser styling.
You can style the <select> toggle itself, though, without hurting accessibility. Just not the dropdown. Here are some examples:
http://adam.co/lab/jquery/customselect/
http://www.456bereastreet.com/lab/custom-select/
Another option could be to code the countries as a list of links and make it expandable with JS. Just be sure to add the appropriate aria roles.
http://edenspiekermann.github.io/a11y-toggle/
http://heydonworks.com/practical_aria_examples/
1.Open on Tab key press
Open on Tab key press of ul is a very bad solution because Tab key does various functions in the window as well. The dropdown toggle will become buggy as the focus has to be on the window. If you are using an input element like select then that's completely fine.
Still I have created a small mock-up using ONLY javascript as you are not allowed to use any external libraries. Created using ul.
Have a look at this fiddle : JS Fiddle
HTML :
<div>
<ul id="dropdown">
<li class='highlight' data-key='A'>America</li>
<li data-key='B'>Brazil</li>
<li data-key='C'>China</li>
<li data-key='D'>Denmark</li>
<li data-key='E'>Egypt</li>
</ul>
</div>
CSS :
ul {
list-style: none;
display: none;
}
ul li.highlight {
background: yellow;
}
Javascript :
document.addEventListener("keydown", keyDownListener, false);
function keyDownListener(e) {
var keyCode = e.keyCode;
var dropdwn = document.getElementById('dropdown');
if (keyCode == 9) {
dropdwn.style.display = (dropdwn.style.display != 'none' ? 'none' : 'block');
} else if (dropdwn.style.display != 'none') {
var items = dropdwn.getElementsByTagName("li");
items[0].classList.remove("highlight");
for (var i = 0; i < items.length; ++i) {
var aKey = items[i].dataset.key;
if (String.fromCharCode(e.keyCode) === aKey) {
for (var j = 0; j < items.length; ++j) {
items[j].classList.remove("highlight");
}
items[i].classList.add("highlight");
}
}
}
}
Explanation :
Add a keydown event listener on your document.
On press of Tab key show/ hide the dropdown.
On press of any other key, if the dropdown is visible check the data-key of each li and match it with the key pressed. If matches, highlight the respective list item.
And again a reminder, toggle of ul dropdown on Tab key press hurts accessibility. If it is a select dropdown then it's fine.
Related
This is trying to hide a checkout payment option from appearing when specific items are in cart (shown on the same page). If the text "BULK" appears in the cart/page to hide a list option based on its data attribute? I've tried learning js and the last 2 hours of watching a course, I understand more but this still seems more advanced than what I can do right now. Would a boolean argument using string.search and insert div.style.display "none"?
Cart example to search for text:
<h4 class="product-title optimizedCheckout-contentPrimary" data-test="cart-item-product-title">BULK Powder 50 lbs.</h4>
Payment option:
<li class="form-checklist-item optimizedCheckout-form-checklist-item" data-test="accordion-item_paypalcommerce">
Once you have a reference to the item (or items - same idea only in a loop) - read the text of the element. Using indexOf sounds reasonable to find a string inside another. And if all is well then just set display:none to the right payment option.
The javascript is basic, but you should also learn some about css selectors should you want to "select" the target elements using a different strategy.
var elem = document.querySelector(".product-title");
var bool = elem.innerText.indexOf('BULK')>=0
if (bool) {
var li = document.querySelector("li[data-test='accordion-item_paypalcommerce']");
li.style.display = 'none'
}
<h4 class="product-title optimizedCheckout-contentPrimary" data-test="cart-item-product-title">BULK Powder 50 lbs.</h4>
Payment options:
<li class="form-checklist-item optimizedCheckout-form-checklist-item" data-test="accordion-item_paypalcommerce">Cash</li>
<li class="form-checklist-item" data-test="accordion-item_paypalcommerce">Credit</li>
I'm very new to programming & working on creating a website for a work project.
In it, there will be a multi-level (w/sub-menus) vertical sidebar on each page.
The problem I'm facing is that every time a user clicks on one link, the sidebar resets to its original state & will have to redo the same thing & not very UX friendly.
I took the template of the accordian sidebar from here.
I've looked at various search results on both stack overflow & google, but can't seem to understand how to get it working to retain the state of the sidebar, regardless of how many levels are opened.
Can someone please help me with the JS code to get it working?
UPDATE:
Nathan, thanks for writing mate! I really appreciate the help.
So based on your suggestion, I've written the following (shoddy) code that injects the 'checked' attribute to the input element.
But it isn't transferring over to the new/redirected html page when a user clicks on one of the sub-menus. What am I missing here?
var menuIndex = -1;
//extract all the input elements
var inputs = document.querySelectorAll('.parent-menu');
//Find index of the element from the array that has "checked == true"
function indexFinder() {
for (var i = 0; i < inputs.length; i++) {
if (inputs[i].checked == true) {
menuIndex = i;
console.log(menuIndex);
}
};
}
//Function to set/inject the attribute
function attributeSetter() {
inputs[menuIndex].setAttribute('checked', 'checked')
}
//When a user clicks literally anywhere, it'll run the indexFinder function
//to check if any of the input elements were expanded (i.e. checked == true)
window.addEventListener('click', () => {
indexFinder();
});
//Run the attributeSetter function when a page loads
window.addEventListener('DOMContentLoaded', () => {
attributeSetter();
});
Welcome to the world of programming! Hopefully I can help you out a little!
So what you're asking is something that can easily get a little complicated.
In order to achieve what you're trying to do you need to specify how you want your menu to look on each individual page!
Allow me to present a few menu options for an imaginary site:
Home
Contact
Email
Mail
About
The Company
Our Owner
I've indented the page names based on how we want them to show up in our menu.
So for example you may click on "Contact" and it drops down with the Email and Mail options.
Well, if you take your regular code from that webpage and copy and paste it everywhere. Any time you reload a page (or travel to another page with the same code) it's gonna reset the code! Thus "closing" the menu. Think of it as some sort of multi-dimentional sci-fi. When you load a webpage, you are accessing the main flow of time, any time you make an update to that page it takes you to an alternate reality with that change! but once you reload the webpage you jump back to the main timeline as if you never made that change (when you get into more advanced web dev, this analogy will break down but it should work to help your understanding for now.)
So let's say I click on the Contact > Email option and it takes me to the Email page. Well, in order to make it seem like my changes to the menu bar (clicking "Contact" to expand the dropdown) are still active. I need to hardcode the change into the Email page!
Here's some sample code:
<nav class="nav">
<a class="navOption">Home<a>
<a class="navOption">Contact<a>
<div class="navDropdown">
<a class="navOption">Email<a>
<a class="navOption">Mail<a>
</div>
<a class="navOption">About<a>
<div class="navDropdown">
<a class="navOption">The Company<a>
<a class="navOption">Our Owner<a>
</div>
<nav>
By default the .navDropdown will be closed. However when we add a class to them .active they will expand! If this is my base menu, then how should I make it so that the "About" dropdown is expanded when you are on one of the About pages?
Simply by adding .active to that dropdown!
<nav class="nav">
<a class="navOption">Home<a>
<a class="navOption">Contact<a>
<div class="navDropdown">
<a class="navOption">Email<a>
<a class="navOption">Mail<a>
</div>
<a class="navOption active">About<a>
<div class="navDropdown">
<a class="navOption">The Company<a>
<a class="navOption">Our Owner<a>
</div>
<nav>
Now, my example is different from yours because it's meant more for JavaScript. However, you can use the same concept in your code too.
For you, instead of having a .active class to expand a dropdown menu. You are using a checkbox element! In your codem you have CSS which is checking to see if the checkbox is checked and then it is opening the dropdown menu if it is:
<input class="cd-accordion__input" type="checkbox" name ="group-1" id="group-1">
So, if we use this method on our example webpage. We could set it to be open by setting the checkbox to start out being checked. Like so:
<input class="cd-accordion__input" type="checkbox" name ="group-1" id="group-1" checked>
It's important to note that as you get better and better at web development (eventually learning JavaScript and a server side language such as PHP). You will be able to piece together more advanced methods to doing what we're trying to accomplish! But for now, I hope I was able to break this down for you!
I have select boxes in my app which appear properly, are selectable (ie: one can click them, and apparently make a selection), but don't behave the way they are supposed to:
After clicking an item in the list, the name/value of that option is not populated in the form.
I've found lots of stackoverflow questions/answers about select-box issues, but none of them seem to be exactly my problem. Nevertheless, I have tried these suggestions without success, including putting a high z-index value in the select box, adding some -webkit specific values to the CSS, etc.
I've tried:
<select> box not displaying on Android in PhoneGap
<select> not working in Phonegap app on Android 2.3.3
PhoneGap build webkit-appearance no drop down arrow for select tag
https://github.com/jquery/jquery-mobile/issues/6992
https://www.daniweb.com/web-development/threads/451455/phonegap-select-box-is-not-working
There is no jQuery involved.
Is there something I'm missing regarding select boxes?
An example-- the HTML:
<select name="people0" id="people0" onfocus="isDirty=1" style="display:inline-block;min-width:150px;" data-native-menu="true">
<option value="0">Choose Person</option>
<option value="15098">Desjardins, Emily</option>
<option value="17304">Hulley, Patrick</option>
<option value="1">Silver, Jason</option>
</select>
The CSS:
select{
/* Suggestions found: having trouble with not being able to select items: */
-webkit-user-select: auto !important;
-webkit-tap-highlight-color: rgba(0,0,0,0);
z-index:1000 !important;
}
UPDATE November 8:
I have found a terrible work-around -- but at least you can select options. When the HTML response comes from the server, I check to see if there are select elements in it, and attach event listeners to them if there are:
var allSelectElements = document.getElementsByTagName('select');
for (var i=0; i < allSelectElements.length; i++) {
allSelectElements[i].addEventListener('touchstart', function(e) {
alert('initiating touch');
this.focus;
}, false);
}
I wish someone could solve this once-and-for-all. :-/
I resolved using similar code:
var allSelectElements = document.getElementsByTagName('select');
for (var i=0; i < allSelectElements.length; i++) {
allSelectElements[i].addEventListener('touchstart', function(e){
//This is the important line
e.stopPropagation();
}, false);
}
The only way it worked for me was adding a jQuery trick:
$('select').click(function () {
$(this).focus();
});
Ok I made a site a while back and always had issues with the menu system is needed. Basically you click a location on a map, then it displays the list of sub locations in the dropdown menu to the right. These are always their they just chance to display based on the options class.
I have put the site at shiftera.co.uk so you can see it their.
The issue first.
1) IE - The list never filters out, it displays all results all the time regardless of class.
2) Chrome - The dropdown is sometimes squashed showing 1 result and hiding the others you need to use up/down arrows to change, sometimes it shows 3, sometimes 4.
3) Firefox - The list displays in 1 long row, not like a usual dropdown.
I think the issue is more of a css problem or multitude of css problems.
An example of the map link is
Scotland
The dropdown list although not seperated is generated from the database and appears as below
<option value='AB25 1UH' class="Scotland">Aberdeen</option><option value=' WA14 4DW' class="Northwest">Altrincham</option>
As you can see, some have the space before some don't. The dropdown has the id of apick and Im using css below to hide it on load.
#apick { display: none; }
Here is the javascript to display the correct items based on map click.
//<![CDATA[
$(document).ready(function(){
$('.areaselect').on('click', function(event){
$('#apick').css('display','inline');
var id = $(this).attr('id')
$('#apick option').not('.'+id).css('display','none');
$('.'+id).css('display','inline').first().attr('selected','selected');
event.preventDefault();
});
}); //]]>
This has been driving me mad for a long time now, it seem's if i fix 1 issue another 2-3 get created. So I figured i'd try here and see if any brightspark can narrow down my issue.
Updated removing windows load as per change to main website.
The simple answer is that you are setting the style to inline. An <option> tag should not be inline, or have any style like that. The inline style i causing the problems.
Instead add the <option> tags when you need them. Store all the values in a object to add/remove them.
By the way. Remove that window load thing.
Here is the javascript fix:
$(document).ready(function()
{
var options = $('#apick option');
var values = $.map(options, function(option)
{
return option;
});
$('.areaselect')
.on('click', function()
{
var apick = $('#apick').empty();
var id = $(this).attr('id');
var newValues = $.grep(values, function(n, i)
{
return $(n).hasClass(id);
});
apick.append(newValues).show().find('option:first').attr('selected','selected');
return false;
});
});
I am trying to enhance my page with a jquery right mouse menu, but am having trouble building the correct structures to populate it easily.
Currently my page contains (among other things) a list of items for the user to review. (an html table) Based on the users role, and the current state and context of the row, the user may take one of various actions on each row of data. (approve, reject, refer it to someone else, ect.) My ASP.Net page handles this by setting the visibility of an imagebutton within the row to true, if the option is available. I can control the Cssclass of each button, and am setting the class of for example the "approve" button to “approvebtn”.
Now I want to enhance my site with a right menu.
I am extending my site with Cory S.N. LaViska’s jQuery Context Menu Plugin -
http://abeautifulsite.net/notebook/80
This plugin allows the default right mouse behavior for any elelement to be overridden with a user controlled context menu. The menu is inserted into your page as an unordered list and becomes visible when it is needed.
<ul id="rightMenu" class="contextMenu">
<li class="details">Details </li>
<li class="addnote">AddNote </li>
<li class="listnote">ShowNotes </li>
<li class="approve">Approve </li>
<li class="reject">Reject </li>
<li class="release">Release </li>
<li class="takeover">Takeover </li>
</ul>
Your app gets a callback when something on the right menu is clicked, and you can interrogate the action (the bogus href element) to see which item it was.
I really like this menu because it is simple to use and is completely CSS styled.
However, I need to do something that this plugin does not nativly seem to support. I need to change which items are available on the menu from row to row. Basically if an Imagebutton (for say approve) is avaiable in the row, then its corrisponding menu item should exist as well.
I was able to gain access to the menu just before it is displayed by altering the plugin slightly, to call my function right before the menu is displayed.
This works, but the logic I had to write seems so brute force, that there must be a better way….
In my callback:
function jimsbuggeredfunction(menu,el)
"el" is the element that was right clicked on (usually a table cell), and "menu" is the menu that this right click is bound to. (so I should be using that name and not hardcoding to #rightMenu')
So, the “if” line finds out if the table row containing the element that was “right clicked” contains a specific button (by its class name) if it does the menu item is enabled, otherwise it is disabled. This process continues for every menu item that I want to be flexable row-to-row.
function jimsbuggeredfunction(menu,el) {
if($(el).parents("tr:eq(0)").find('.approvebtn').length > 0)
$('#rightMenu').enableContextMenuItems('#approve');
else
$('#rightMenu').disableContextMenuItems('#approve');
if($(el).parents("tr:eq(0)").find('.rejectbtn').length > 0)
$('#rightMenu').enableContextMenuItems('#reject');
else
$('#rightMenu').disableContextMenuItems('#reject');
if($(el).parents("tr:eq(0)").find('.releasebtn').length > 0)
$('#rightMenu').enableContextMenuItems('#release');
else
$('#rightMenu').disableContextMenuItems('#release');
if($(el).parents("tr:eq(0)").find('.takeoverbtn').length > 0)
$('#rightMenu').enableContextMenuItems('#takeover');
else
$('#rightMenu').disableContextMenuItems('#takeover');
if($(el).parents("tr:eq(0)").find('.revertbtn').length > 0)
$('#rightMenu').enableContextMenuItems('#revert');
else
$('#rightMenu').disableContextMenuItems('#revert');
if($(el).parents("tr:eq(0)").find('.removebtn').length > 0)
$('#rightMenu').enableContextMenuItems('#remove');
else
$('#rightMenu').disableContextMenuItems('#remove');
if($(el).parents("tr:eq(0)").find('.addnotebtn').length > 0)
$('#rightMenu').enableContextMenuItems('#addnote');
else
$('#rightMenu').disableContextMenuItems('#addnote');
if($(el).parents("tr:eq(0)").find('.listnotebtn').length > 0)
$('#rightMenu').enableContextMenuItems('#listnote');
else
$('#rightMenu').disableContextMenuItems('#listnote');
};
There must be a better way to set this up, so that it also just ignores menu items that I want to display all of the time) but it is escaping me at the moment. Is there a better way to accomplish this?
Thanks,
Jim
I would find some way to create a mapping between the two IDs and some more systematic way of finding the relevant button. For example, if the button always belongs inside a certain cell that has a class, let's say "buttonclass", then something like this should work:
var mapping = {
takeoverbtn: '#takeover',
listnotebtn: '#listnote'
// ...
};
function jimsbuggeredfunction(menu,el) {
var buttontype = $(el).parents("tr:eq(0)").find('.buttonclass').children().attr("class");
$('#rightMenu').disableContextMenuItems(mapping[buttontype]);
}
My jQuery is a little rusty, there's probably a cleaner way of retrieving the buttontype, but that general idea ought to work.