Change style/class with javascript on keydown - javascript

I'm trying to change the style of an element using javascript on a keydown event. I've already done it with mouse clicks like this :
#mpc ul li:active {
background:#844;
And these are the original properties of the element im trying to change:
<div id="mpc">
<div id="wrapper">
<ul>
<li id="kickDrum_p1">1<p>Kick</p></li>
<li id="snareDrum_p2">2<p>Snare</p></li>
<li id="closedHiHat_p3">3<p>ClosHat</p></li>
<li id="openHiHat_p4">4<p>Open HiHat</p></li>
</ul>
</div>
</div>
This is the original css.
#mpc ul li {
background:#999;
}
I'm really new to css/html and javascript and haven't started learning jquery so I prefer doing it all by javascript and css.
The idea is to assign a different key to every list item and when that key is pressed on the page, the list item's background changes, just like I've done the click event. The difference with the click event is I've made it so it doesn't follow the id's since you manually select the list item you want and then it changes it's style.
With key input however I need to specify which list item exactly I'm targeting.
So I think I need to create a new css class with the properties of the background I want the element to change to and using javascript to tell that when I press the 'H' key for example it should change the element's style to that and when I let go of the key to reverse it back to normal. If that makes sense. I do not know how to ahcieve that.
EDIT:
This is how I tried to do it:
var keypress = document.getElementById("kickDrum_p1")[0]
document.addEventListener("keydown", function (e) {
if(e.keyCode == 69) {
var key = e.keyCode
var color = keypress.getElementByClassName("color")
if(color.length !=0 ){
cur = color[0]
cur.className = " "
}
cur.className="color"
}
});
And in the styles I have this:
#mpc ul li.color {
background:#844;
}

<P ID="MyID" CLASS="Testclass">Test</P>
<SCRIPT>
Add here jQuery
$("*").keypress(function(event){
if(event.which==107 || event.which==75){
$("#MyID").attr("class", "newclass");
}
}
</SCRIPT>
BTW: 107 and 57 are the K and the k in the ASCII table.

Related

Closing one element when opening another within the same loop using Javascript

first time on here so i'll try my best to explain what I'm asking.
So I have 3 list items with the same class name. I've put them in a looping function so that when you click on one it will display a sub set of list items for that specific list item. I also have them inside an if statement that adds a new class name to the specific list item that was clicked. It allows opening and closing of the sub list items when you click the corresponding parent element.
My question is; how can I use this same principle of checking for the additional class name, when the user clicks any of the list items. In other words, I am trying to code it in a way that will allow me to close any of the open sub list items when the user clicks a new list item.
This is what I came up with but it doesn't know what button[i] is when I include it within the "click" function. What I was trying to do with this code is to take whatever list item was clicked, and then check the previous and next iterations of the class name "button" to see if any of the contain also contain the class name "clicked.
HTML
<div class="main">
<ul>
<li>One
<ul>
<li>One-1</li>
<li>One-2</li>
</ul>
</li>
<li>Two
<ul>
<li>Two-1</li>
<li>Two-2</li>
</ul>
</li>
<li>Three
<ul>
<li>Three-1</li>
<li>Three-2</li>
</ul>
</li>
</ul>
</div>
CSS
.main ul ul {
display: none;
}
.main ul ul li {
display: block;
}
Javascript
var button = document.getElementsByClassName("button");
for (i = 0; i < button.length; i++) {
button[i].addEventListener("click", function() {
var prevItem = button[i - 1];
var nextItem = button[i + 1];
if (prevItem.className !== "button") {
prevItem.className = "button";
prevItem.nextElementSibling.style.display = "none";
}
if (nextItem.className !== "button") {
nextItem.className = "button";
nextItem.nextElementSibling.style.display = "none";
}
if (this.className === "button") {
this.className += " clicked";
this.nextElementSibling.style.display = "block";
}
});
}
I am wanting to make this code usable no matter how many list items you add. So checking exactly button[0] button[1] and button[2] wasn't really an option, but I can see how button[i + 1] might not check every list item after it but rather just the next one. I tried adding another loop but ran into similar issues. anyway that's why I'm here. Thanks for any help in advance.
Since I am not sure whether I understood your question correctly, I quickly rephrase it in my own words.
Question: "I have an arbitrary number of list elements, of which each contains a button and a nested list. The button is always visible, the nested list is hidden by default. When the user clicks on a button, the corresponding nested list should be shown. At the same time, all other shown nested lists should be hidden again. How can I achieve this?"
The original HTML looks fine:
<div class="main">
<ul>
<li>One
<ul>
<li>One-1</li>
<li>One-2</li>
</ul>
</li>
<li>Two
<ul>
<li>Two-1</li>
<li>Two-2</li>
</ul>
</li>
<li>Three
<ul>
<li>Three-1</li>
<li>Three-2</li>
</ul>
</li>
</ul>
</div>
The CSS I did not fully understand, but I suggest the following:
.main ul ul {
display: none;
}
.main li.is-active ul {
display: block;
}
.main ul ul li {
display: block;
}
By adding the "is-active" class to an LI element, it is shown. This way, the CSS controls the visibility.
For the JavaScript part, I suggest this:
const buttonElements = Array.from(document.querySelectorAll('.button'));
buttonElements.forEach(buttonElement => {
buttonElement.addEventListener('click', () => {
const activeElements = Array.from(document.querySelectorAll('.is-active'));
activeElements.forEach(activeElement => {
activeElement.classList.remove('is-active');
});
buttonElement.parentElement.classList.add('is-active');
});
});
This solution assumes you can use newer versions of JavaScript/ECMAScript. Overall, it makes use of const and arrow functions.
First, we get all elements with the class "button" by using document.querySelectorAll(). Since the result is a NodeList and no array, we convert it using Array.from(). Afterwards, we loop through the array by using Array.prototpye.forEach(). We add an event listener for the "click" event. When a button is clicked, we search for all elements with the "is-active" class and for each one remove it. Finally, we add the "is-active" class to the parent element of the clicked button using Node.prototype.parentElement().
Here is another solution that works in older browsers:
var buttonElements = document.getElementsByClassName('button');
for (var i = 0; i < buttonElements.length; i++) {
buttonElements[i].addEventListener('click', function(event) {
var activeListElements = document.getElementsByClassName('is-active');
for (var i = 0; i < activeListElements.length; i++) {
activeListElements[i].setAttribute('class', '');
}
event.target.parentNode.setAttribute('class', 'is-active');
});
}
This is pretty much the same as the other approach but works with older versions of JavaScript.
Generally, the idea is to focus on an arbitrary sum of elements instead of an array with a specific length. In natural language something like: "Give me all buttons. For every button, add an event listener. When a button is clicked, give me all active list elements and remove their active status. Then, mark the list item above the button as active".
Hope this helps

Click outside an element doesn't work

I have this code:
function showAll(el){
var id = el.parentNode.id;
var all= document.getElementById(id).getElementsByClassName('items')[0];
if(all.style.display === 'block'){
all.style.display = 'none';
} else{
all.style.display = 'block';
window.addEventListener('mouseup', function(e){
document.getElementById('test').innerHTML = e.target.className;
if(e.target != all){
all.style.display = 'none';
}
});
}
}
<div id="parent">
<div class="selected" onClick="showAll(this);">
</div>
<div class="items" style="display: none">
</div>
</div>
Basically what i want to achieve is: click on selected to display items which is now hidden after that if i click again on selected or if i click outside of items(a random spot on that page or even on selected) i want to be able to hide items.
The problem is that without the EventListener when i click on selected it works to display items and then if i click again on selected it works to hide items but if i click on a random spot it doesn't work to close items.
But when i add EventListener and i click on selected it works to click a random spot to close items but it doesn't work to click selected again to close items.
Can anybody help me with a full JavaScript explanation, please?
You're going to want to use highly reusable code. I use change() and id_() on my web platform all of the time and it's very direct and simple. In the below example the second parameter will make the class empty (you can also use id_('items').removeAttribute('class') for a cleaner DOM (Document Object Model)).
HTML
<input onclick="change(id_('items','');" type="button" value="Display Items" />
<div clas="hidden" id="items"><p>Items here.</p></div>
CSS
.hidden {display: none;}
JavaScript
function change(id,c)
{
if (id_(id)) {id_(id).className = c; if (id_(id).className=='') {id_(id).removeAttribute('class');}}
else if (id) {id.className = c; if (id.className=='') {id.removeAttribute('class');}}
else {alert('Error: the class id \''+id+'\' was not found or has not yet been imported to the DOM.\n\nNew class intended: '+c);}
}
function id_(id)
{
if (id == '' && window['console']) {console.log('Developer: empty id called from: '+id_.caller.toString().split('function ')[1].split('(')[0]);}
return (document.getElementById(id)) ? document.getElementById(id) : false;
}
This code exists from years of refining the same platform instead of industry standard drama of pointlessly changing things. You are two clicks from finding more highly reusable functions on my platform's JavaScript documentation from the link in my profile.

Make div appear or disappear with javascript

I am attempting to make a few divs behave the way I want them to. Here is my relevant HTML:
<ul class="services">
<li class="business-formation" id="services-li-1">Business Formation</li>
<li class="domestic-relations" id="services-li-2">Domestic Relations</li>
<li class="estate-probate" id="services-li-3">Estate & Probate</li>
</ul>
<div class="business-formation-list" id="business-formation-list">
<ul>
<li>Items go here</li>
</ul>
</div>
<div class="domestic-relations-list" id="domestic-relations-list">
<ul>
<li>Items go here</li>
</ul>
</div>
<div class="estate-probate-list" id="estate-probate-list">
<ul>
<li>Items go here</i>
</ul>
</div>
I want the divs to appear and disappear when the corresponding li is clicked (they are links). Here is my Javascript:
document.getElementById('services-li-1').style.cursor = "pointer";
document.getElementById('services-li-2').style.cursor = "pointer";
document.getElementById('services-li-3').style.cursor = "pointer";
const div1 = document.querySelector('business-formation-list');
const div2 = document.querySelector('domestic-relations-list');
const div3 = document.querySelector('estate-probate-list');
const click2 = document.getElementById('services-li-2');
document.addEventListener('click', (event) => {
if (event.click2.className = 'domestic-relations') {
div1.style.display = 'none';
div2.style.display = 'block';
div3.style.display = 'none';
}
});
This doesn't make anything happen, but what I wanted it to do is to make the second div appear when the li with the class name "domestic-relations" is clicked. What am I doing wrong? Thanks!
If you're using querySelector, you need to tell it that it's a class. You do that by adding . before the class in question.
So document.querySelector('business-formation-list') should be document.querySelector('.business-formation-list').
However, if you're only using it once, it should be an ID, not a class.
Im also fairly new to this and had a similar problem to yours. I came up with a solution, so it might help you as well. The solution is quite long so I hope you can bear with me.
first thing is to change your your div class "domestic/estate/business" to just "list". When you're doing the css for it, you'll want to apply the same style to them. If you need more styling, you can always target the IDs or add another css class.
Once you've done that, apply to that list "display: none;". This will hide all your ul's at once.
The javascript looks something like this. i've added some description as to why I chose to do what I did.
var serviceType = document.querySelectorAll(".serviceType");
var serviceTypeArray = Array.prototype.slice.call(serviceType); // this will
//change your serviceType from a nodelist to an Array.
var serviceDescription = document.querySelectorAll(".list"); // to grab the
//list of descriptions and make it into an "array"
for ( i = 0 ; i < serviceTypeArray.length ; i++) {
var services = serviceTypeArray[i]; // I created this variable to store the
// variable "i"
services.addEventListener( "click" , displayServices); }
// created this "for loop" to loop through every element inside the array
//and give it the "click" function
function displayServices() {
var servicePosition = serviceTypeArray.indexOf(this); // when we click the
// event, "this" will grab the position of the clicked item in the array
if (serviceTypeArray[servicePosition].hasAttribute("id") == false) { //
// the hasAttribute returns values of true/false, since initially the
// serviceTypeArray didn't have the "id" , it returns as false
serviceTypeArray[servicePosition].setAttribute( "id" , "hide"); // I've
// added the "setAttribute" function as a unique indicator to allow
// javascript to easily hide and show based on what we are clicking
serviceDescription[servicePosition].style.display = "block"; // When you
//click one of the serviceType, it returns an the index number (aka the
// position it is inside the arrayList)
//this gets stored inside servicePosition(aka the actual number gets
// stored).
// Since i've made an array to store the the description of each service,
// their position in the array correspond with the service's position
//inside the serviceType array made earlier; therefore, when I press one
// particular serviceType (ie i clicked on "business formation"), the
// appropriate text will pop up because the position of both the name and
// its description are in the same position in both arrays made
} else if (serviceTypeArray[servicePosition].hasAttribute("id") == true ) {
//since the serviceType now has an attribute, when we check it, it'll come
// back as true
serviceTypeArray[servicePosition].removeAttribute("id"); //we want to
// remove the id so next time we click the name again, the first "if"
// condition is checked
serviceDescription[servicePosition].style.display = "none"; //this is
// so that the display goes back to "none"
}
}
This will allow to click any of the names and display/hide them at will. you can even show 2/3 or all three of them, it's up to you. I hope this helps and I hope the explanation is clear enough!
Let me know if you have any questions for this!

Hide a div if an element has been clicked twice in a row, else Show

I have several items in my navigation bar, and a div next to it, ie:
<nav>
<a id="a"></a>
<a id="b"></a>
<a id="c"></a>
</nav>
<div id="menu-col"></div>
If the same link is clicked twice in a row, I want to hide #menu-col. If not, I want #menu-col to remain visible.
I'm not a javascript guy so I tried this:
var lastClicked;
$('nav a').on('click', function(e) {
alert(e.target.id + " - " + this.lastClicked);
if (e.target.id == this.lastClicked) {
$('#menu-col').hide();
this.lastClicked = '';
}
else {
$('#menu-col').show();
this.lastClicked = e.target.id;
}
});
Then I remembered that javascript assigns references, and not values. So when I did this.lastClicked = e.target.id; I'm assigning a reference to my element's id, then on the next click I make that e.target.id == ''.
In javascript, what would be the proper way of closing a box if the same link is clicked twice, and if not making sure the box is visible.
You can achieve this using toggleClass() to set a state class on the clicked a and also using toggle() on the .menu-col to show or hide it based on that state class. Try this:
$('nav a').click(function(e) {
e.preventDefault();
var $a = $(this);
$a.toggleClass('active').siblings().removeClass('active');
$('.menu-col').toggle($a.hasClass('active'));
});
.menu-col {
display: none;
}
.active {
color: #C00;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<nav>
<a id="a" href="#">a</a>
<a id="b" href="#">b</a>
<a id="c" href="#">c</a>
</nav>
<div class="menu-col">menu-col</div>
As long as you keep those ids unique across you app (which you should be doing anyway) the approach you've chosen isn't wrong. Any primitive in javascript is actually stored by value. Those primitives are string, number, boolean, and symbol. For more info see here https://developer.mozilla.org/en-US/docs/Glossary/Primitive
I would suggest something like this, you should have some kind of condition in which the div shows after it has been hidden.
$('nav a').dblclick(function(event) {
event.preventDefualt();
alert($(this).attr('id'));
$('#menu-col').toggle();
});
Something like that should be exactly what you are looking for, like I said though, there should be a condition in which it shows itself again, I made it a toggle so any double click on any 'nav a' element will cause it to show/hide the div.
Just for the sake of an option. Here is another way for double clicks(clicked twice in a row).
Using ondblclick event.
Double-click me.

Modify this function to display all the checked checkboxes' values (instead of last selected)

I am replicating the functionality of a select/multiselect element and I'm trying to use this function to display the items which have been selected in the relevant container. I need to show all the values that have been selected in a comma-separated list, but it's currently only showing one selection (the last one made). It's also displaying the checkbox, background color, etc. of the list item selected instead of the checkbox value (i.e. value="Black").
I'm using this for a few multiselect form elements where I couldn't use the jQuery UI MultiSelect Widget because they needed to be styled in a very specific way (options displayed with background colors or images and spread out over several columns, etc.).
I've included the relevant code below, and I've posted a working example of the styled 'faux'-multiselect element here: http://jsfiddle.net/chayacooper/GS8dM/2/
JS Snippet
$(document).ready(function () {
$(".dropdown_container ul li a").click(function () {
var text = $(this).html();
$(".dropdown_box span").html(text);
});
function getSelectedValue(id) {
return $("#" + id).find("dropdown_box span.value").html();
}
});
HTML Snippet
<div class="dropdown_box"><span>Colors</span></div>
<div class="dropdown_container">
<ul>
<li><a href="#"><div style="background-color: #000000" class="color" onclick="toggle_colorbox_alt(this);" title="Black"><div class=CheckMark>✓</div>
<input type="checkbox" name="color[]" value="Black" class="cbx"/></div>Black</a>
</li>
<!-- More list items with checkboxes -->
</ul>
</div>
I've tried several other methods (including many of the ones listed here: How to retrieve checkboxes values in jQuery), but none of those worked with hidden checkboxes and/or the other functions I need to incorporate in these particular form elements.
well, to start with change click(..){..} in document.ready to
$(".dropdown_container ul li a").click(function () {
var text = $(this).html();
var currentHtml = $(".dropdown_box span").html();
var numberChecked = $('input[name="color[]"]:checked').length;
$(".dropdown_box span").html(currentHtml.replace('Colors',''));
if (numberChecked > 1) {
$(".dropdown_box span").append(', ' + text);
} else {
$(".dropdown_box span").append(text);
}
});
this will do the appending of text right.
however I couldn't understand the handling of images in the code.
Update, to handle just the value:
replace var text = $(this).html(); with
var text = $(this).find("input").val();
It might be easier to just grab all the values of the check boxes whenever the click event is triggered and then append the values to your span. Like http://jsfiddle.net/9w95b/
I would also suggest not putting the <input> tags inside your <a> tags.

Categories

Resources