Change style of div with specific class? - javascript

I am truely sorry if this is a repeated question.
I want to set max-height of #menudd.show to satify my transition. I want to do this in javascript so i can specify the value more precisely.
This is what i got and its not working for some reason...
HTML:
<div id="menudd">
Home
About Me
Short-Term
Middle-Term
Long-Term
</div>
CSS:
#menudd {
position: fixed;
overflow: hidden;
max-height: 0px;
opacity: 0;
width: 200px;
border-radius: 10px;
box-shadow: 0 0 35px 15px black;
transition: all 1s ease;
}
#menudd.show {
opacity: 1;
}
JavaScript:
$("#menudd." + show).get(0).style.maxHeight = document.getElementById("menudd").getElementsByTagName("A")[0].offsetHeight * document.getElementById("menudd").getElementsByTagName("A").length + "px";
This outputs "show is not defined" in the console.
If i use $("#menudd.show").get(0).style.maxHeight it outputs "cannot read property 'style' of undefined" in the console.
If i use $("#menudd.show").style.maxHeight it outputs "cannot read property 'maxHeight' of undefined" in the console.
Any help is highly appreciated! Good day to you. :)

In your question, you said you wanted to look for an element with class "show" inside a div.
You are currently looking for a variable, and not a class. Change this:
$("#menudd." + show)
To this:
$("#menudd.show")
To set the max height, change it to this:
$( "#menuadd.show" ).css( { "maxHeight": document.getElementById("menudd").getElementsByTagName("A")[0].offsetHeight * document.getElementById("menudd").getElementsByTagName("A").length + "px" } );

First, I will add some stuff for readability - like a padding: 0.5em; into you dropdown menu. Also, the <br /> tag after the </a> tags (excluding the last one).
Second, the errors happened because there are no element in the page with the class show. I added it to the <div> of the dropdown to show it working and make the errors go away.
Remember this: if the console says there it is undefined, chances are that either you messed up in how to select the element OR it seriously doesn't exists because you misspelled a letter or let's say you forgot to add a class to a given tag (like in this case).
Third, your code in working condition is available below. It isn't using jQuery easing stuff but pure JavaScript - except by the onclick event that is better to use with jQuery:
$("#menu-dropdown").on("click", function() {
var menu_dropdown = document.getElementById("menudd");
var menu_item = menu_dropdown.getElementsByTagName("A");
$("#menudd").toggleClass("show");
menu_dropdown.style.maxHeight = menu_item[0].offsetHeight * menu_item.length + "px";
} );
#menudd {
padding: 0.5em;
position: fixed;
overflow: hidden;
max-height: 0px;
opacity: 0;
width: 200px;
border-radius: 10px;
box-shadow: 0 0 35px 15px black;
transition: all 1s ease;
}
#menudd.show {
opacity: 1;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<span id="menu-dropdown">DropDown</span>
<div id="menudd">
Home<br />
About Me<br />
Short-Term<br />
Middle-Term<br />
Long-Term<br />
</div>
You can view it working also on this video (Youtube) that I recorded.
Fourth, you can add classes, in pure JavaScript, easily. I won't write about it in full since there is a famous question with a godly answer by Peter Boughton already on Stack Overflow. Read it here.
Anyway, to add a class, simply call:
document.getElementById("MyElementID").className += " MyClass";
It is important to note the space. Since it is a string with values, you need to put it otherwise it will treat all the classes as one word (one class) that doesn't exists.
To remove:
document.getElementById("MyElementID").className = document.getElementById("MyElementID").className.replace( /(?:^|\s)MyClass(?!\S)/g , '' );
Explanation available through Peter's answer. So read it there (important)!
Finally, this is out of the scope of the question and merely a reminder: I need to state that if this is a dropdown menu, you will need to add the show class after some focus (or click even) by calling a function in a master menu of some sort and not by hardcoding it into the <div> like I did to show the code working. For example, a "Cars Brand" item of a menu would have a dropdown with the available car brands (Ford, Toyota and etc) after focusing on it.
So, it is wise to transform it in a function that receives the ID of the target dropdown to open. And do not forget to close it after losing focus (or whatever).

Related

How do I connect html transforms in multiple classes? [duplicate]

This question already has answers here:
How can I apply multiple transform declarations to one element?
(5 answers)
How to have multiple CSS transitions on an element?
(9 answers)
Closed 2 years ago.
I'm trying to use multiple transforms in a single element so that the end product is a combination of all of the transformations applied together.
However, the only one transform property will be ignored when there are multiple of them.
Say, if I want a div transformed by rotate(20deg) and skewY(20deg), this wouldn't work:
.foo {
transform: rotate(20deg);
}
.bar {
transform: skewY(20deg);
}
<div class="foo bar"></div>
Only one will be applied. Although compounding the transformations could work, it would be impractical as there can be potentially many combinations to the transformations. Rather than doing this:
.one-one {transform: rotate(10deg) skewY(1deg);}
.one-two {transform: rotate(10deg) skewY(2deg);}
.one-three {transform: rotate(10deg) skewY(3deg);}
.one-four {transform: rotate(10deg) skewY(4deg);}
.two-one etc.
I want to do this, so that i can apply the transformations on button clicks, rather than to exhaust all possible combinations of the transformations:
.one {transform: rotate(10deg);}
.two {transform: rotate(20deg);}
.three {transform: rotate(30deg);}
.four {transform: rotate(40deg);}
.uno {transform: skewY(10deg);}
.dos {transform: skewY(20deg);}
.tres {transform: skewY(30deg);}
Current solutions I think are possible:
There is a way to add to the transform property of a <div>
Somehow modify classes in some way
Changing the CSS using jQuery, but it seems like this will also overwrite the property with css() rather than adding to the transform style
I'd prefer css/js solutions, but jQuery answers are welcome too, I'm just not familiar with it.
You may look at CSS var(--X) (see links below snippet's demo) and , set all transformation you intend to 0 by default and update them via the className :(mind support before use : https://caniuse.com/#feat=mdn-css_properties_custom-property_var and eventually a polyfill https://github.com/nuxodin/ie11CustomProperties )
possible exemple without JavaScript https://codepen.io/gc-nomade/pen/RwWLOWr :
.foo {
--rotate: 20deg;
}
.bar {
--skewY: 20deg;
}
div[class] {
transform: rotate( var(--rotate, 0)) skewY( var(--skewY, 0));/* fallback value is here 0 */
}
/* demo purpose */
div[class] {
float: left;
border: solid;
}
html {
display: flex;
height: 100%;
}
body {
margin: auto;
}
<div class="foo bar">foo bar</div>
<div class="foo ">foo</div>
<div class="bar">bar</div>
<div class="nop">no transform</div>
https://developer.mozilla.org/en-US/docs/Web/CSS/--*
Property names that are prefixed with --, like --example-name, represent custom properties that contain a value that can be used in other declarations using the var() function.
Custom properties are scoped to the element(s) they are declared on, and participate in the cascade: the value of such a custom property is that from the declaration decided by the cascading algorithm.
Fallback : https://drafts.csswg.org/css-variables/#example-abd63bac
Note: The syntax of the fallback, like that of custom properties, allows commas. For example, var(--foo, red, blue) defines a fallback of red, blue; that is, anything between the first comma and the end of the function is considered a fallback value.
if supports comes a question, you may look at : IE11 - does a polyfill / script exist for CSS variables?
There's many ways you can approach that. How about this below?
I have created two ` to read the values for skew and rotation and them apply the effects.
Remember it doesn't matter where the values come from. They can be hard-coded in your buttons as data-* attributes(if you want them fixed). This is just to show you how you can approach it with javascript( Ihave added some commends to make it simpler to understand):
var object = document.querySelector(".shape");
// this function takes care of Rotational effect
function rotate(event)
{
var rotation_val = document.getElementById("rotationVal").value;
// this get's the css transform expression for rotation which is
// stored as data-attribute on every button, because it tells you what button is resposible for what transformation. But you can store this anywhere you want.
var css_transform = event.currentTarget.getAttribute("data-rotation");
// this here just replaces say rotate(_r_) to rotate(15deg) if val was 15
var effect = css_transform.replace("_r_",rotation_val + "deg");
// Take not of this. ere I am not overriding the transform property. Instead
// I am adding a transformation to it. more like compounding but dynamically.
object.style.transform += effect;
}
// this function takes care of Skewing effect
function skewY(event)
{
var skew_val = document.getElementById("skewVal").value;
var css_transform = event.currentTarget.getAttribute("data-skew");
var effect = css_transform.replace("_s_",skew_val + "deg");
object.style.transform += effect;
}
function apply_all(){
var buttons = document.querySelectorAll(".effect_button");
buttons.forEach( function(button){
button.click();
});
}
.container{
padding: 60px;
border: thin solid #dbdbdb;
}
.shape{
width: 60px;
height: 60px;
background-color: green;
}
<div class="container">
<div class="shape">
</div>
</div>
<input id="rotationVal" />
<button class="effect_button" data-rotation="rotate(_r_)" onClick="rotate(event)">rotate</button>
<br />
<input id="skewVal" />
<button class="effect_button" data-skew="skewY(_s_)" onClick="skewY(event)">Skew</button>
<br />
Or Rotate and Skew at the same time:
<button onClick="apply_all(event)">Transform</button>

Click Propagation failing in Jquery

For part of the site I'm working on, I have a set of sidebars that can pull out. To have them hide when the users are done with them, I've set up a div with a click event (see below) so that whenever the user clicks somewhere outside of the sidebar, the sidebar closes. The problem that I'm running into, however, is that the click event handler is grabbing the event, running its method, and then the click event seems to stop. I've tried using return true and a few other things I've found around here and the internet, but the click event just seems to die.
$('.clickaway').click(function() {
$('body').removeClass(drawerClasses.join(' '));
return true;
});
EDIT: Here is a fiddle with an example: https://jsfiddle.net/2g7zehtn/1/
The goal is to have the drawer out and still be able to click the button to change the color of the text.
The issue is your .clickaway layer is sitting above everything that's interactive, such as your button. So clicking the button, you're actually clicking the layer.
One thing you could do is apply a higher stacking order for elements you want to interact with, above the .clickaway layer. For example, if we apply position: relative, like this:
.show-drawerHotkey .ColorButton {
position: relative;
}
The element will now be in a higher stacking order (since it comes after the clickaway, and we've applied no z-index to clickaway)
Here's a fiddle that demonstrates: https://jsfiddle.net/2g7zehtn/5/
Using this somewhat famous SO answer as a guide, you can bind to the $(document).mouseup(); event and determine whether certain "toggling" conditions apply:
[EDIT] - Example updated to illustrate clicking a link outside of the containing div.
// Resource: https://stackoverflow.com/questions/1403615/use-jquery-to-hide-a-div-when-the-user-clicks-outside-of-it
var m = $('#menu');
var c = $('#menuContainer');
var i = $('#menuIcon');
i.click(function() {
m.toggle("slow");
});
$(document).mouseup(function(e) {
console.log(e.target); // <-- see what the target is...
if (!c.is(e.target) && c.has(e.target).length === 0) {
m.hide("slow");
}
});
#menuIcon {
height: 15px;
width: 15px;
background-color: steelblue;
cursor: pointer;
}
#menuContainer {
height: 600px;
width: 250px;
}
#menu {
display: none;
height: 600px;
width: 250px;
border: dashed 2px teal;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
I'm a link outside of the container
<div id="menuContainer">
<div id="menuIcon"></div>
<div id="menu"></div>
</div>

The CSS input[value=whatever] selector doesn't seem to match against input.value. What am I missing?

N.B.: I should note that the proper solution to this is to just use the 'placeholder' attribute of an input, but the question still stands.
Another N.B.: Since, as Quentin explains below, the "value" attribute stores the default value, and the input.value IDL attribute stores the current value, the JavaScript I used to "fix" the problem in my below example is non-conforming, as it uses the (non-IDL) value attribute to store current, rather than default, values. Besides, it involves DOM access on every key press, so it was always just a flawed demo of the problem I was having. It's actually quite terrible code and shouldn't be used ever.
CSS selectors made me think that I could make an input with a label that acts as a preview without any JS. I absolutely position the input at 0,0 inside the label (which is displayed as an inline-block) and give it a background of "none", but only if it's got a value of "" and isn't focussed, otherwise it has a background colour, which obscures the label text.
The HTML5 spec says that input.value reflects the current value of an input, but even though input.value updates as you type into an input, CSS using the input[value=somestring] selector applies based only on what was explicitly typed into the document, or set in the DOM by the JavaScript setAttribute method (and perhaps by other DOM-altering means).
I made a jsFiddle representing this.
Just in case that is down, here is an HTML document containing the relevant code:
<!doctype html>
<head>
<meta charset="utf-8" />
<title>The CSS Attribute selector behaves all funny</title>
<style>
label {
display: inline-block;
height: 25px;
line-height: 25px;
position: relative;
text-indent: 5px;
min-width: 120px;
}
label input[value=""] {
background: none;
}
label input, label input:focus {
background: #fff;
border: 1px solid #666;
height: 23px;
left: 0px;
padding: 0px;
position: absolute;
text-indent: 5px;
width: 100%;
}
</style>
</head>
<body>
<form method="post">
<p><label>name <input required value=""></label></p>
</form>
<p><button id="js-fixThis">JS PLEASE MAKE IT BETTER</button></p>
<script>
var inputs = document.getElementsByTagName('input');
var jsFixOn = false;
for (i = 0; i < inputs.length; i++) {
if (inputs[i].parentNode.tagName == 'LABEL') { //only inputs inside a label counts as preview inputs according to my CSS
var input = inputs[i];
inputs[i].onkeyup= function () {
if (jsFixOn) input.setAttribute('value', input.value);
};
}
}
document.getElementById('js-fixThis').onclick = function () {
if (jsFixOn) {
this.innerHTML = 'JS PLEASE MAKE IT BETTER';
jsFixOn = false;
} else {
this.innerHTML = 'No, actually, break it again for a moment.';
jsFixOn = true;
}
};
</script>
</body>
</html>
I could be missing something, but I don't know what.
The value attribute sets the default value for the field.
The value property sets the current value for the field. Typing in the field also sets the current value.
Updating the current value does not change the value attribute.
Attribute selectors only match on attribute values.
There are new pseudo classes for matching a number of properties of an input element
:valid
:invalid
:in-range
:out-of-range
:required
A required element with no value set to it will match against :invalid. If you insist on using the value instead of placeholder, you could simply add a pattern or a customValidity function to force your initial value to be counted as invalid.

Add to Favorites Array

What I want to do in Javascript/Jquery is be able to click a button (a button on each item), that adds it to an array. This array will then be posted in order when you click on a favorites page.
I'm just having a hard time wrapping my head around how this would work. Because I may want each item in the array to contain a few things, such as a picture and text describing the item.
In general terms/examples, how would this be set up?
There are a number of ways to do this. But, I'll go with one that's a bit more general - which you can extend for yourself:
http://jsfiddle.net/TEELr/11/
HTML:
This simply creates different elements with the favorite class - which will be the selector by which we check if an element has been clicked.
<div class="favorite"><p>Add to favorites</p></div>
<div class="favorite type2"><p>Just another favorite type</p></div>
<button id="reveal">
Reveal Favorites
</button>
JS:
Every time an element with the "favorite" CSS class is clicked, it is added to the array - this also works for elements with more than one class (that have the "favorite" CSS class).
Now, when the "Reveal Favorites" button is clicked, it will alert what's in the array - which is in the order clicked (as asked).
$(document).ready(function() {
var favorites = [];
var counter = 0;
$('.favorite').click(function() {
++counter;
favorites.push("\"" + $(this).text() + " " + counter + "\"");
});
$('#reveal').click(function() {
alert(favorites);
});
});
CSS:
Simple CSS that only exist for demonstration purposes to prove previous point with multiple CSS class selectors:
.favorite {
width: 400px;
height: 50px;
line-height: 50px;
text-align: center;
display: block;
background-color: #f3f3f3;
border-bottom: 1px solid #ccc;
}
.favorite.type2 {
background-color: #ff3;
}
.favorite:hover {
cursor:hand;
cursor: pointer;
}

jquery ui droppable's greedy setting is not working?

By setting droppable widget's greedy to true, only the top-most element should respond to a drop event. There's really no complexity here but I just cannot get it to work. And this is all I have so not much to work on:
CSS:
.page{
position: absolute;
width: 150px;
height: 150px;
left: 0px;
top: 0px;
text-align: center;
background: #F0FFFF;
border: 1px solid #89B;
}
HTML:
<div class = 'page' id = 'page1'> page1 </div>
<div class = 'page' id = 'page2'> page2 </div>
<div class = 'page' id = 'page3'> page3 </div>
JS:
document.ready = function(){
$('.page').draggable()
$('.page').droppable({
greedy: true,
drop: function( event, ui ){
console.log( 'assert drop once')
}
})
}
what's happening right now is that all the dropped on elements are responding to the drop event. Since there's so little code to hold on to, I have no idea how to diagnose this.
Reading the documentation for the greedy property I'm not sure I understand the same as you:
By default, when an element is dropped on nested droppables, each droppable will receive the element. However, by setting this option to true, any parent droppables will not receive the element.
For me it means if you have a large div droppable which contains another smaller div droppable then if you drop an element in the small one only the small one will receive the event.
Check this demo to understand what I'm explaining : http://jquery-ui.googlecode.com/svn/tags/1.6rc4/demos/droppable/greedy.html

Categories

Resources