How to extend a div backwards? - javascript

Does anyone know how to extend a div 2 to the back, lowering the div 1 to the down, when clicking, in a simple way? It looks easy but with css it is not possible and with javascript it is difficult.
I want when clicking on the 2 extends back and the 1 goes down:
But instead this happens:
div 2 goes down.
Html and Css:
.frame {
width: 50%;
height: 400px;
font: bold 70px roboto;
color: black;
background-color: yellow;
float: left;
}
input:checked + .frame {
width: 100%;
}
input{
display: none;
}
<body class="gallery">
<input type="checkbox" id="a" />
<label for="a" class="frame a">1</label>
<input type="checkbox" id="b" />
<label for="b" class="frame b" style="background-color: green">2</label>
<input type="checkbox" id="c" />
<label for="c" class="frame a" style="background-color: green">3</label>
<input type="checkbox" id="d" />
<label for="d" class="frame b">4</label>
</body>
I tried with this javascript:
Demo

To Make the clicked div moves above all:
You can easily do that:
1-Make the gallery parent flex
2-Give order: 2; for all children
3-Change the order to 1 when checked
Apply:
body{
margin: 0;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.frame {
width: 50%;
height: 100px;
font: bold 70px roboto;
color: black;
text-align: center;
order: 2;
}
input:checked + .frame {
width: 100%;
order: 1;
}
input{
display: none;
}
<body class="gallery">
<input type="checkbox" id="a"/>
<label for="a" class="frame" style="outline: 2px solid">1</label>
<input type="checkbox" id="b"/>
<label for="b" class="frame" style="outline: 2px solid">2</label>
<input type="checkbox" id="c"/>
<label for="c" class="frame" style="outline: 2px solid">3</label>
<input type="checkbox" id="d"/>
<label for="d" class="frame" style="outline: 2px solid">4</label>
<input type="checkbox" id="e"/>
<label for="e" class="frame" style="outline: 2px solid">5</label>
<input type="checkbox" id="f"/>
<label for="f" class="frame" style="outline: 2px solid">6</label>
</body>
And now, when you click anyone, it will go to the top and fill the parent width.
And when you click another one while the first is still active, it will be move to the top too and fill the parent width without affecting the older one.
If you want to stop having many frames selected at the top, just turn your inputs to be radio instead of checkbox and connect them all with the same name attribute.
To make the clicked div moves above its brother only:
Here you must dived every two frames in a separate row div and do the same job for the rest.
Apply:
body {
margin: 0;
display: flex;
flex-direction: column;
flex-wrap: nowrap;
}
.row {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.frame {
width: 50%;
height: 100px;
font: bold 70px roboto;
color: black;
text-align: center;
order: 2;
}
input:checked + .frame {
width: 100%;
order: 1;
}
input {
display: none;
}
<body class="gallery">
<div class="row">
<input type="checkbox" id="a" />
<label for="a" class="frame" style="outline: 2px solid">1</label>
<input type="checkbox" id="b" />
<label for="b" class="frame" style="outline: 2px solid">2</label>
</div>
<div class="row">
<input type="checkbox" id="c" />
<label for="c" class="frame" style="outline: 2px solid">3</label>
<input type="checkbox" id="d" />
<label for="d" class="frame" style="outline: 2px solid">4</label>
</div>
<div class="row">
<input type="checkbox" id="e" />
<label for="e" class="frame" style="outline: 2px solid">5</label>
<input type="checkbox" id="f" />
<label for="f" class="frame" style="outline: 2px solid">6</label>
</div>
</body>
Now if you clicked a div, it will go above its brother only, there is a small difference that the other elements will not merge with its brother.
And absolutely there is many many many other ways using css or javascript, but I think the first one does what you want.

Nice question. Yep, it does not have pure-css solution, unfortunately...
Fully agree with previous comment regarding to "swapping" strategy via "order" css property. It's definitely less code and more performant then "physically moving" html elements in DOM
Also, "display: grid" is always better then flex for multi-dimensional layouts (2-column in our case)
Supposing that initial requirement expects that any "even cell" should behave as "2", I see full solution like this:
const el_cells = document.querySelectorAll('.wrapper .cell');
el_cells.forEach((el_clicked, index) => {
const el_prev = index > 0 ? el_cells[index - 1] : null;
el_clicked.addEventListener('click', () => {
// checking if element was already expanded
const expanding = !el_clicked.classList.contains('active')
// restoring initial cells state
el_cells.forEach((el, i) => {
el.classList.remove('active');
el.style.order = i + 1;
});
if (expanding) {
// resizing selected cell
el_clicked.classList.add('active');
// swapping 'even' cell with previous one (f.e. 2 with 1, 4 with 3, etc...)
if (index % 2 === 1) {
el_clicked.style.order--;
el_prev.style.order++;
}
}
})
})
/* some not very important global styles */
* {
margin: 0;
padding: 0;
font-size: 40px;
font-weight: bold;
}
/* our yellow-green grid */
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr;
}
.wrapper .cell {
height: 100px;
background: yellow;
}
.wrapper .cell.green {
background: green;
}
.wrapper .cell.active {
grid-column: span 2;
}
<div class="wrapper">
<div class="cell">1</div>
<div class="cell green">2</div>
<div class="cell green">3</div>
<div class="cell">4</div>
<div class="cell">5</div>
<div class="cell green">6</div>
<div class="cell green">7</div>
<div class="cell">8</div>
</div>
Improved this example a bit to make expanded cells to collapse on click :)

"Uladzimir Interesting, when you click on 2 it extends, then you click on 4 and everyone else resets. Can you tell me how to keep the 2 extended after clicking another one?"
Well, this small clarification adds additional "layer of complexity" to the initial question :)
The reason is that when initially you click "2" - you know that all "even elements" should push "odd ones" below them. On the other hand, when "2" gets expanded and you click "5" - how system should behave if not getting "2" collapsed ?
Seems that "5" has to push "4" below like "2" did that with "1".
So now logics of re-ordering elements has to become "generic" not like it was previously (re-ordering even-index elements when clicked)
And now user clicks, for example, "3", how to process this situation then ? Where do we have to push "1" in this case ? Under "5" probably ? I do not know... But, you see, lots of "edge cases" start appearing here...
What's bad here is that if you implement that - the solution would be definitely bulky, dirty and not very readable and understandable, unfortunately... So, I think, the best way here - to suggest your customers some easier-to-implement option (for example as I suggested initially when collapsing previously expanded elements)
Just a possible and not "too complicated" variant is to list selected elements always "on top":
const el_cells = document.querySelectorAll('.wrapper .cell');
let el_expanded = [];
el_cells.forEach((el_clicked) => {
el_clicked.addEventListener('click', () => {
const expanding = !el_clicked.classList.contains('active');
// resizing/collapsing current cell
if (expanding) {
el_clicked.classList.add('active');
} else {
el_clicked.classList.remove('active');
}
// refreshing expanded element collection
if (expanding) {
el_expanded = [el_clicked, ...el_expanded];
} else {
el_expanded = el_expanded.filter(_ => _ !== el_clicked);
}
// re-indexing not-expanded elements
el_cells.forEach((el, idx) => {
if (el_expanded.indexOf(el) !== -1) return;
el.style.order = 1000 + idx + 1 // 1000 added here to list them after "expanded" ones
})
// re-indexing expanded elements
el_expanded.forEach((el, idx) => {
el.style.order = idx + 1;
})
});
});
/* some not very important global styles */
* {
margin: 0;
padding: 0;
font-size: 40px;
font-weight: bold;
}
/* our yellow-green grid */
.wrapper {
display: grid;
grid-template-columns: 1fr 1fr;
}
.wrapper .cell {
height: 100px;
background: yellow;
}
.wrapper .cell.green {
background: green;
}
.wrapper .cell.active {
grid-column: span 2;
}
<div class="wrapper">
<div class="cell">1</div>
<div class="cell green">2</div>
<div class="cell green">3</div>
<div class="cell">4</div>
<div class="cell">5</div>
<div class="cell green">6</div>
<div class="cell green">7</div>
<div class="cell">8</div>
</div>
Again, this is not "ideal" option, you see. With lots of elements in list it would also require some "scroll-to-top" logics :( Anyway, it is understandable, predictable and requires "not too much" code to create and maintain

Related

Multi-line label for radio button

I would like "This is label" text to stack right underneath the "Prefix Text", while radio button to be aligned right next "Prefix Text". Is it possible to get this done by updating class for div element that contains "This is label" only? I would like to keep label-container class untouched if possible as I may add icon in front of "Prefix Text" so I will need display: inline-flex to wrap them up. https://codepen.io/Judoboy/pen/OJQqPEW?editors=1100
.label-container {
display: inline-flex;
justify-content: flex-start;
align-items: center;
}
.label-text {
display: flex;
justify-items: center;
align-items: center;
height: 100%;
}
.prefix {
font-weight: bold;
}
.text-spacing {
padding-inline-start: 8px;
padding-inline-end: 4px;
}
<label class="label-container">
<input type="radio" />
<div class="label-text text-spacing prefix">Prefix Text</div>
<div class="label-text text-spacing">This is label</div>
</label>
You can do this:
Wrap both Prefix Text and This is label with additional div.
Change align-items in .label-container class to start (you can keep display: inline-flex).
.label-container {
display: inline-flex;
justify-content: flex-start;
align-items: start;
}
.label-text {
display: flex;
justify-items: center;
align-items: center;
height: 100%;
}
.prefix {
font-weight: bold;
}
.text-spacing {
padding-inline-start: 8px;
padding-inline-end: 4px;
}
<label class="label-container">
<input type="radio" />
<div>
<div class="label-text text-spacing prefix">Prefix Text</div>
<div class="label-text text-spacing">This is label</div>
</div>
</label>
just use some transform.
.AlignmentFix {
transform: translate(-100%, 17px);
}
<label class="label-container">
<input type="radio" />
<div class="label-text text-spacing prefix">Prefix Text</div>
<div class="label-text text-spacing AlignmentFix">This is label</div>
</label>
// finding the only <button> element in the document, and binding
// an anonymous Arrow function as the event-handler for the 'click'
// event on that <button>:
document.querySelector('button').addEventListener('click', (e) => {
// we retrieve the first element in the document that matches
// the selector supplied to document.querySelector():
let original = document.querySelector('label.label-container'),
// we then clone that node, and its descendant elements
// with the Boolean true argument passed to Node.cloneNode():
clone = original.cloneNode(true);
// e.currentTarget is the element to which the anonymous function
// was bound; from that element we navigate to the first ancestor
// element that matches the selector and then append the 'clone'
// to that <main> element:
e.currentTarget.closest('main').append(clone);
});
/* overriding browser default layout calculations,
and zeroing all margin and padding for cross-
browser consistency: */
*,
::before,
::after {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* element added for layout purposes, to avoid changing the <body>
element's styles in case of conflict with your real-world
preferences: */
main {
border: 1px solid #000;
border-radius: 1em;
display: flex;
flex-flow: row wrap;
gap: 0.5em;
justify-content: space-between;
margin-block: 1em;
margin-inline: auto;
padding: 0.5em;
width: clamp(10rem, 60vw, 1000px);
}
/* styling the <button> to occupy the whole width, or a full
'row': */
button:first-child {
flex-basis: 100%;
flex-grow: 1;
padding-block: 0.5em;
}
.label-container {
/* while 'inline grid' (note the space) is a valid property-
value, regardless of Chrome's claim to the contrary,
I've changed the property-value to 'inline-grid' for
compatibility with Chrome, Edge, etc: */
display: inline-grid;
/* here we create a grid-layout of two columns, and two
rows with three 'cells'. The first cell is placed in
the first column, and spans both rows. The other
cells take only one 'cell' each. */
grid-template-areas: "radio prefix" "radio text";
}
.label-text {
display: flex;
justify-items: center;
align-items: center;
height: 100%;
}
.prefix {
font-weight: bold;
}
input {
align-self: center;
}
.text-spacing {
grid-column: 2;
padding-inline-start: 8px;
padding-inline-end: 4px;
}
<!-- this element is purely for the wrapping, to supply padding and layout; obviously
adjust to your preferences: -->
<main>
<!-- added a <button> to handle the addition of new <label> elements to demonstrate the layout -->
<button>Add another <label> element</button>
<label class="label-container">
<input type="radio">
<div class="label-text text-spacing prefix">Prefix Text</div>
<div class="label-text text-spacing">This is label</div>
</label>
<label class="label-container">
<input type="radio">
<div class="label-text text-spacing prefix">Prefix Text</div>
<div class="label-text text-spacing">This is label</div>
</label>
<label class="label-container">
<input type="radio">
<div class="label-text text-spacing prefix">Prefix Text</div>
<div class="label-text text-spacing">This is label</div>
</label>
</main>
JS Fiddle demo.

How can I make a "board of tiles" for this game?

I want to make a board consisting of tiles but I do not know how to fill up the entire board area. I have only gotten up to 1 column of the board, as shown in the image. How can I fill this board so that each tile can be changed if clicked on or such?
body {
font-family: Arial, Helvetica, sans-serif;
text-align: center;
}
hr {
width: 500px;
}
#board {
width: 1000px;
height: 1000px;
float: center;
display: grid;
background-color: rgb(126, 124, 122);
border: 6px solid rgb(0, 0, 0);
}
.tile {
width: 200px;
height: 200px;
border: 5px solid bisque;
border-radius: 10%;
font-size: 40px;
font-weight: bold;
display: flex;
justify-content: center;
align-items: center;
}
.picker {
width: 100px;
height: 100px;
border: 5px solid bisque;
margin: 0 auto;
border-radius: 10%;
align-content: left;
align-self: left;
}
.tile {
background-color: rgb(255, 255, 255);
color: black;
}
.float-child {
width: 10%;
padding: 10px;
border: 2px solid rgb(0, 0, 0);
vertical-align: left;
}
<body>
<h1>Play-Color</h1>
<hr>
<div class="game">
<div class="float-child">
<button class="picker" style="background-color: red"></button>
<h4>count = 0</h4>
<br>
<button class="picker" style="background-color: blue"></button>
<h4>count = 0</h4>
<br>
<button class="picker" style="background-color: green"></button>
<h4>count = 0</h4>
<br>
<button class="picker" style="background-color: yellow"></button>
<h4>count = 0</h4>
<br>
<button class="picker" style="background-color: grey"></button>
<h4>count = 0</h4>
<br>
<button class="picker"></button>
<br>
</div>
<div id="board" class="float-child" style="position:relative; left:900px; top:-1000px" >
<button class="tile"></button>
<button class="tile"></button>
<button class="tile"></button>
<button class="tile"></button>
<button class="tile"></button>
</div>
</div>
</div>
</body>
[2]UpdatedImage
........................................................................................................................................................................................
There are many steps to achieve the wanted result. Normally I wouldn't code this on SO. I just did it because I had fun it it. For the feature dont expect others to code a whole game for you for free!
See the comments within HTML, CSS and JS for furtehr info.
You have to create your color to pick from. The smartest solution IMHO is the use of radio-buttons. The Radio button will even without a script only allow the selection of one choice:
<input type="radio" name="color" value="color-name" id="color-name">
To not break the game you should always have one color selected. To ensure that on start one color is already selected you add the checked-attribtue to one color such as:
<input type="radio" ... checked>
Next you have to hide the checkboxes to be invisible and not cunsumign any space which you do through CSS:
input { display: none; }
Then you have to add the color as visual box by adding a <label>. That has the advantage that you can click on the label and it will select the correct radio button:
<label for="color-name">
After that you color the label with the color you want. While you do that, you can also set a CSS-Class to the same color in the same instance to allow the painting with that color:
label[for=color-name],
.color-name {
background-color: color-name;
}
Finally you have to create a grid. You can do that easily through JS or hardcode it to HTML. Sicne I dont want to explain you on how to do it correctly through JS (which would cost me another 30 minutes of my lifetime) I will hardcode it through HTML. In my case I used a grid-container: <div class="game-board">. Then I added 25x child elements: <div class="card"></div>. To make the grid 5x5 dimensions I used CSS on the Grid-Container to create 5 columns:
.game-board {
display: grid;
grid-template-columns: repeat(5, 1fr);
}
As said already in the comments, you don't need buttons to be clickable for JS. The label of the radio buttons are clickable already (as they are labels). You can run a script even when not being clickable by simply usign the EventListener to check for a click-event by using JS:
element.addEventListener('click', e => {
// statements
});
To only select the grid-cards and not the container itself or possibel other content you can check if the element that was clicked on contains a specific class:
if (e.target.classList.contains('card')) {
// statements
}
In case that grid-card already has a color as CSS-Class applied to, we have to remove all potencial classes that would prevent the CSS to work correctly (it would only show the color of the class that is listed last in CSS):
e.target.className = ''
Unfortunatly the last step also removed the card class and as such we have to re-add this class:
e.target.classList.add('card');
Once we did that, we use a switch-case-statement which is cleaner then writing tons of if/else-statements. You can google guides and tutorials on your own. That switch-statement now checks what radio-button is checked and applies a class to the element you clicked on that adds the background-color:
e.target.classList.add('color-name');
EDIT
To include a counter you can use the JS lenght-statement:
document.querySelectorAll('.game-board .color-name').length. this statement will count the number of elements that contain a specific class.
Then simply use innerHTML-statement to display the count:
element.innerHTML = document.querySelectorAll('.game-board .color-name').length
var board = document.querySelector('.game-board')
// eventListener to listen to click events on the game board
board.addEventListener('click', e => {
console.clear();
// checks if a card and not the agme baord itself was clicked on
if (e.target.classList.contains('card')) {
const card = e.target.classList;
// checks which color has been selected
var color = document.querySelector('.color-picker input:checked').value;
// removes all classes from the clicked on element to allow re-painting
e.target.className = '';
// re-adds the "card" class to the clicked element
card.add('card');
// switch statement to add the class with the selected color to paint the grid-card
switch (color) {
case "red":
card.add('red');
break;
case "blue":
card.add('blue');
break;
case "green":
card.add('green');
break;
case "yellow":
card.add('yellow');
break;
case "gray":
card.add('gray');
break;
}
// color-counter
var countRed = document.querySelectorAll('.game-board .red').length,
countBlue = document.querySelectorAll('.game-board .blue').length,
countGreen = document.querySelectorAll('.game-board .green').length,
countYellow = document.querySelectorAll('.game-board .yellow').length,
countGray = document.querySelectorAll('.game-board .gray').length;
// displaying the counter
var labelRed = document.querySelector('#count-red span'),
labelBlue = document.querySelector('#count-blue span'),
labelGreen = document.querySelector('#count-green span'),
labelYellow = document.querySelector('#count-yellow span'),
labelGray = document.querySelector('#count-gray span');
labelRed.innerHTML = countRed;
labelBlue.innerHTML = countBlue;
labelGreen.innerHTML = countGreen;
labelYellow.innerHTML = countYellow;
labelGray.innerHTML = countGray;
}
});
/* aligning the color picker and game board next to each other */
body {
margin: 0;
padding: 10px;
box-sizing: border-box;
display: flex;
gap: 10px;
min-height: 100vh;
}
/* box for the color */
.color-picker {
border: 1px solid black;
display: flex;
flex-direction: column;
padding: 5px 30px;
gap: 10px;
}
/* hides the radio button */
.color-picker > input {
display: none;
}
/* creatign a visual border to see what color has been selected */
input:checked + label {
border: 3px solid black;
}
/* setting a "color-box" to the radio-button */
.color-picker > label {
display: block;
box-sizing: border-box;
aspect-ratio: 1 / 1;
min-width: 50px;
}
/* settign the color of the color picker and classes for painting */
label[for=red],
.red {
background-color: red;
}
label[for=blue],
.blue {
background-color: blue;
}
label[for=green],
.green {
background-color: green;
}
label[for=yellow],
.yellow {
background-color: yellow;
}
label[for=gray],
.gray {
background-color: gray;
}
/* game board that creates a board of 5x5 with equal dimensions */
.game-board {
flex-grow: 1;
display: grid;
grid-template-columns: repeat(5, 1fr);
grid-gap: 5px;
}
/* Setting the grid-cards to be squares */
.game-board > .card {
aspect-ratio: 1 / 1;
border: 1px solid red;
border-radius: 5px;
display: flex;
justify-content: center;
align-items: center;
}
/* To make the grid-cards and label appear like buttons on hover */
.color-picker > label:hover,
.card:hover {
cursor: pointer;
}
<!-- Letting you select the color -->
<div class="color-picker">
<input type="radio" name="color" value="red" id="red" checked>
<label for="red"></label>
<div id="count-red">Count: <span>0</span></div>
<input type="radio" name="color" value="blue" id="blue">
<label for="blue"></label>
<div id="count-blue">Count: <span>0</span></div>
<input type="radio" name="color" value="green" id="green">
<label for="green"></label>
<div id="count-green">Count: <span>0</span></div>
<input type="radio" name="color" value="yellow" id="yellow">
<label for="yellow"></label>
<div id="count-yellow">Count: <span>0</span></div>
<input type="radio" name="color" value="gray" id="gray">
<label for="gray"></label>
<div id="count-gray">Count: <span>0</span></div>
</div>
<!-- The game board as a grid -->
<div class="game-board">
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
<div class="card"></div>
</div>

Change parent block background when child input is checked(vanilla js)

I am new to the world of coding, and would be very grateful for an advise or any idea. I was wondering if it is possible to change color of current parent block background(.checkbox-container), when child input is checked. And the main problem is that I have multiple blocks with inputs, and require to change background color only to current block, not to all? As I understood there is no pure css solution without mark-up change, but this is not my case. Could someone please give any idea how that could be done in vanilla js?
Here is the link to fiddle:
https://jsfiddle.net/william_eduards/r4jxvuz5/4/
and visual code example here:
.checkbox-container {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: nowrap;
background: #E8EBF0;
border: 1px solid #E8EBF0;
transition: background .3s ease-in-out;
margin-bottom: 8px;
border-radius: 4px;
}
<div class="dimensional-container checkbox-container">
<input type="checkbox" name="snapchat" class="checkbox-container__snapchat" id="snapchat">
<label for="snapchat">snapchat</label>
</div>
<div class="dimensional-container checkbox-container">
<input type="checkbox" name="facebook" class="checkbox-container__facebook" id="facebook">
<label for="facebook">Facebook</label>
</div>
<div class="dimensional-container checkbox-container">
<input type="checkbox" name="hangouts" class="checkbox-container__hangouts" id="hangouts">
<label for="hangouts">hangouts</label>
</div>
Find all input using querySelectorAll.
Loop over all input and addEventListener
check if the elment is checked or not using e.target.checked, If it is checked change its parent e.target.parentElement background style.
I've used red, you can select color on your own.
const allInputs = document.querySelectorAll("input");
allInputs.forEach(input => {
input.addEventListener("click", e => {
if (e.target.checked) {
e.target.parentElement.style.background = "#ff0000";
} else {
e.target.parentElement.style.background = "#E8EBF0";
}
})
})
.checkbox-container {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: nowrap;
background: #E8EBF0;
border: 1px solid #E8EBF0;
transition: background .3s ease-in-out;
margin-bottom: 8px;
border-radius: 4px;
}
<div class="dimensional-container checkbox-container">
<input type="checkbox" name="snapchat" class="checkbox-container__snapchat" id="snapchat">
<label for="snapchat">snapchat</label>
</div>
<div class="dimensional-container checkbox-container">
<input type="checkbox" name="facebook" class="checkbox-container__facebook" id="facebook">
<label for="facebook">Facebook</label>
</div>
<div class="dimensional-container checkbox-container">
<input type="checkbox" name="hangouts" class="checkbox-container__hangouts" id="hangouts">
<label for="hangouts">hangouts</label>
</div>

hiding a "No file chosen" tooltip in Javascript

I know there are many question about it, but they don't answer properly.
After readings and looking for, I tried this:
<input id="ext-element-47" class="x-input-file x-input-el" type="file" accept="" style="display:none">
hiding the file-input and then
this.element.down(".x-input-file").dom.click();
this works on Chrome's console but in my JS code it doesn't. It doesn't click.
Anyone knows why? and what can I do for make click?
Notes:
I need to make click because the file element is not visible and so when it clicks it does not show unless I do element.click ().
Here is an example what I'm doing:
document.getElementsByClassName('o-file-field-input')[0].click()
.o-file-field-input {
display: none;
}
.o-big-btn {
background-color: red;
height: 3em;
width: 3em;
}
<div class="x-container x-unsized o-cont-option" data-componentid="ext-container-5" id="ext-container-5">
<div class="x-inner x-align-center x-pack-center x-horizontal x-layout-box" id="ext-element-50">
<div class="x-button x-button-plain open-field-icon o-big-btn x-layout-box-item x-flexed x-stretched" id="ext-OUI_BaseButton-1" data-componentid="ext-OUI_BaseButton-1" tabindex="0" style="-webkit-box-flex: 1;">
<span class="x-button-icon x-shown smf smf-upload-file" id="ext-element-45"></span>
<div class="o-button-bg"></div>
<div class="x-unsized x-field-input x-has-height" id="ext-fileinput-1" data-componentid="ext-fileinput-1" style="height: 38px;">
<input id="ext-element-47" class="x-input-file x-input-el o-file-field-input" type="file" accept="">
<div class="x-field-mask x-hidden-display" id="ext-element-48"></div>
<div class="x-clear-icon" id="ext-element-49">
</div>
</div>
</div>
</div>
</div>
See ya!
Here's what I usually do: Wrap the input inside a <label> element, and then style the element as a button, for example:
.pretty-file {
border: 1px solid #000;
cursor: pointer;
display: inline-block;
padding: 5px 15px;
}
.pretty-file input[type="file"] {
display: none;
}
<label class="pretty-file">
Choose File
<input type="file" />
</label>
This finally works well:
var obElement = document.getElementsByClassName('input-file')[0];
//the title property overrides tooltip's description
obElement.setAttribute('title', ' ');
.flex-style{
display: flex;
}
.input-file{
opacity: 0;
margin-left: -40px;
width: 40px;
height: 45px;
}
.icon{
width: 40px;
height: 45px;
background-color: blueviolet;
}
<div class='flex-style'>
<div class='icon'></div>
<input class='input-file' type='file'>
</div>

Need Help Creating A Segmented Control

I'm trying to create a segmented control to help organize content on my website. So far, I've got the segmented control created and looking the way I want using HTML and CSS. Now, I would like to expand the functionality of this control to show / hide a series of div tags when each segment is selected. However, JavaScript is definitely not my forte, and I haven't been able to find a good, responsive solution to this problem.
Below is the code I've got so far. You'll also notice a series of div tags whose text indicates which tags should be shown when each segment in the control is selected. I'm pretty sure JavaScript would be the easiest solution to this problem, but as I said, I'm not familiar enough with that language to come up with a good solution here. Any help you can provide on expanding this segmented control so I can use it to show and hide different div tags based on the active segment that is selected would be greatly appreciated.
Here's the HTML I've got:
<ul class="segmented-control">
<li class="segmented-control__item">
<input class="segmented-control__input" type="radio" value="1" name="option" id="option-1" checked>
<label class="segmented-control__label" for="option-1">Step 1</label>
</li>
<li class="segmented-control__item">
<input class="segmented-control__input" type="radio" value="2" name="option" id="option-2" >
<label class="segmented-control__label" for="option-2">Step 2</label>
</li>
<li class="segmented-control__item">
<input class="segmented-control__input" type="radio" value="3" name="option" id="option-3" >
<label class="segmented-control__label" for="option-3">Step 3</label>
</li>
</ul>
Here's the various div tags that should be displayed when a segment within the control is selected. Obviously they are all displaying right under the segmented control right now, and nothing happens to any of these div tags when a new segment is selected. This is what the JavaScript would need to do :)
<div class="Step_1_Content" align="center">
<p>This is the content that should be displayed when the Step 1 segment has been selected</p>
</div>
<div class="Step_2_Content" align="center">
<p>This is the content that should be displayed when the Step 2 segment has been selected</p>
</div>
<div class="Step_3_Content" align="center">
<p>This is the content that should be displayed when the Step 3 segment has been selected</p>
</div>
And here's the CSS I'm using for the Segmented Control:
<style>
.segmented-control {
display: table;
width: 100%;
margin: 2em 0;
padding: 0;
}
.segmented-control__item {
display: table-cell;
margin: 0;
padding: 0;
list-style-type: none;
}
.segmented-control__input {
position: absolute;
visibility: hidden;
}
.segmented-control__label {
display: block;
margin: 0 -1px -1px 0; /* -1px margin removes double-thickness borders between items */
padding: 1em .25em;
border: 1px solid #E62033;
color: #E62033;
font: 14px/1.5 sans-serif;
text-align: center;
cursor: pointer;
}
.segmented-control__label:hover {
background: #ffffff;
color: #E62033;
}
.segmented-control__input:checked + .segmented-control__label {
background: #E62033;
color: #ffffff;
}
</style>
Once again, thanks in advance for your help!
You can simply store the state of the checkboxes in variables, and hide the divs based on those variables.
The first variables I included below are used on page load, the other ones when the object has changed.
Check it out here: https://jsfiddle.net/ezfy66f9/
var checked1 = $('#option-1').is(':checked');
var checked2 = $('#option-2').is(':checked');
var checked3 = $('#option-3').is(':checked');
if (checked1 == 1) {
$('.Step_1_Content').show();
$('.Step_2_Content').hide();
$('.Step_3_Content').hide();
} else if (checked2 == 1) {
$('.Step_2_Content').show();
$('.Step_1_Content').hide();
$('.Step_3_Content').hide();
} else if (checked3 == 1) {
$('.Step_3_Content').show();
$('.Step_1_Content').hide();
$('.Step_2_Content').hide();
}
$(".segmented-control").change(function () {
var checked1 = $('#option-1').is(':checked');
var checked2 = $('#option-2').is(':checked');
var checked3 = $('#option-3').is(':checked');
if (checked1 == 1) {
$('.Step_1_Content').show();
$('.Step_2_Content').hide();
$('.Step_3_Content').hide();
} else if (checked2 == 1) {
$('.Step_2_Content').show();
$('.Step_1_Content').hide();
$('.Step_3_Content').hide();
} else if (checked3 == 1) {
$('.Step_3_Content').show();
$('.Step_1_Content').hide();
$('.Step_2_Content').hide();
}
});
here the code:
$( document ).ready(function() {
// load initial state
hideContent();
$(".step1").show();
// click on li-element
$( "li" ).on( "click", function() {
var li = $(this);
// find the content number
var number = li.find("input").attr("value");
hideContent();
showContent(number) ;
});
});
function hideContent() {
$(".content").hide();
}
function showContent(number) {
$(".content.step"+number).show();
}
.segmented-control {
display: table;
width: 100%;
margin: 2em 0;
padding: 0;
}
.segmented-control__item {
display: table-cell;
margin: 0;
padding: 0;
list-style-type: none;
}
.segmented-control__input {
position: absolute;
visibility: hidden;
}
.segmented-control__label {
display: block;
margin: 0 -1px -1px 0; /* -1px margin removes double-thickness borders between items */
padding: 1em .25em;
border: 1px solid #E62033;
color: #E62033;
font: 14px/1.5 sans-serif;
text-align: center;
cursor: pointer;
}
.segmented-control__label:hover {
background: #ffffff;
color: #E62033;
}
.segmented-control__input:checked + .segmented-control__label {
background: #E62033;
color: #ffffff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<ul class="segmented-control">
<li class="segmented-control__item">
<input class="segmented-control__input" type="radio" value="1" name="option" id="option-1" checked="checked">
<label class="segmented-control__label" for="option-1">Step 1</label>
</li>
<li class="segmented-control__item">
<input class="segmented-control__input" type="radio" value="2" name="option" id="option-2" >
<label class="segmented-control__label" for="option-2">Step 2</label>
</li>
<li class="segmented-control__item">
<input class="segmented-control__input" type="radio" value="3" name="option" id="option-3" >
<label class="segmented-control__label" for="option-3">Step 3</label>
</li>
</ul>
<div class="step1 content" align="center">
<p>This is the content that should be displayed when the Step 1 segment has been selected</p>
</div>
<div class="content step2" align="center">
<p>This is the content that should be displayed when the Step 2 segment has been selected</p>
</div>
<div class="content step3" align="center">
<p>This is the content that should be displayed when the Step 3 segment has been selected</p>
</div>
Look this jsfiddle, it's html+css only solution. But this one requires a placement of your div's with content inside of appropriate segment control li elements, like this:
<li class="segmented-control__item">
<input id="option-1" ...>
<label class="segmented-..." for="option-1">Step 1</label>
<div class="Step_1...">
<p>some content...</p>
</div>
</li>
and also some additional css.

Categories

Resources