Reputation: 47
I'm currently having a small problem with some CSS/JS logic around creating a box inside-ish of a box. JsFiddle example : https://jsfiddle.net/pa7wt2g3/
I want to create 1 box and upon clicking the box, create a description field under it. however currently the description fields are all appering inside the first box when making additional boxes.
I suspect I have to give every box an uniqe ID which is later used to specifiy where to put the description area, but how do I go about this?
function textarea() { // Toggles dropdown and sets the dropdown and textfield as the same width as the created div
document.getElementById('dropdown').classList.toggle("show");
style = window.getComputedStyle(crtdiv);
wdt = style.getPropertyValue('width');
dropdown.style.width = wdt;
}
document.getElementById("läggatill").onclick = function () { // Run function when läggatill is clicked
var div = document.createElement('div'); // create div element
div.className = 'newrect'; // apply css
div.setAttribute("id", "crtdiv");
var button = document.createElement('button'); // create button element
button.setAttribute("id", "hej"); // Giving an id
var buttontext = document.createTextNode("X"); // Sets the button value
button.appendChild(buttontext); // Shows the value of the button
button.className = 'hej'; // apply css
button.setAttribute("onClick", "removeDiv(this)"); // runs the removeDiv funtion
var dropdown = document.createElement('dropdown'); // create dropdown element
dropdown.setAttribute("id", "dropdown"); // Giving an id
dropdown.className = 'dropdown'; //apply css
div.setAttribute("onClick","textarea()"); // Run textarea funtion
var ptext = document.createElement('p'); // create p element
var textnode = document.createTextNode("Add description"); // Sets the innerText of the p element
ptext.appendChild(textnode); // Shows the InnerText
ptext.className = 'text'; // apply css
ptext.setAttribute("id", "text"); // Giving an id
var textfield = document.createElement('Textarea'); // create textarea element
textfield.className = 'autoExpand'; // apply css
textfield.setAttribute("id", "textfield"); // Giving an id
var text = document.getElementById("myText").value; //take the value of the text field
div.innerHTML = text; // show text in the div
if (text === "") { // Shows every element if the textfield has text in it
return 0; // Returns nothing if the text field is empty
} else {
document.getElementsByTagName('span')[0].appendChild(div).appendChild(button);
document.getElementsByTagName('span')[0].appendChild(dropdown);
document.getElementsByClassName('dropdown')[0].appendChild(ptext);
document.getElementsByClassName('dropdown')[0].appendChild(textfield);
}
};
function removeDiv(elem) { // Removes div when pressing the button
$(elem).parent('div').remove();
}
/* Start of lägga till kompetens */
.newrect {
min-width: 55px;
max-width: 195px;
margin-top: 1%;
margin-right: 1%;
margin-left: 1%;
margin-bottom: 0%;
padding: 1% 3%;
border: 1px solid green;
border-radius: 40px;
text-align: center;
float: left;
position: relative;
background-color: white;
z-index: 2;
cursor: pointer;
}
.dropdown {
display: none;
background-color: darkgrey;
height: 400px;
position: absolute !important;
margin-top: 3%;
margin-right: 0%;
margin-left: 0.96%;
margin-bottom: 0%;
z-index: 1;
}
.show {
display: block;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
</head>
<body>
<input id="myText" type="text" class="skriv" name="Kompetenser" autocomplete="off" autofocus> <!-- Textfield for kompetenser -->
<input id="läggatill" class="läggatill" type="button" value="Add box"> <!-- Button lägga till -->
<span style="display:block;"></span>
</body>
</html>
Upvotes: 0
Views: 246
Reputation: 411
there! I've also worked in a solution and I would like to share it. It is very similar to what @Tomasz Kasperczyk answered, I've rewritten your code using jQuery and added some flexbox features to the CSS (plus some classes I renamed so I wouldn't confuse myself). It's more simplified now and working. I hope it is easy for you to understand.
function addTagBox(text) {
var $tagBox = $($('#tagBoxTemplate').html());
$tagBox.find('.tagBox-label').text(text);
$('#tagsContainer').append($tagBox);
}
$('#addTagBoxButton').click(function(e) {
e.preventDefault();
var tagName = $('#myText').val();
if (tagName.length) {
addTagBox(tagName);
}
})
//listeners for the dynamic elemtens
$('#tagsContainer').on('click', '.tagBox', function(evt) {
$('.tagBox-dropdown').removeClass('dropdown--isVisible');
$(this).find('.tagBox-dropdown').toggleClass('dropdown--isVisible');
})
$('#tagsContainer').on('click', '.tagBox-destroy', function(evt) {
$(this).parent().remove();
})
html,
body {
/* So you can adjust height */
height: 100%;
margin: 0;
padding: 0;
}
#tagsContainer {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
justify-content: flex-start;
}
.tagBox {
min-width: 55px;
max-width: 195px;
margin: 0 1rem 2rem 0;
padding: .5rem 1rem;
text-align: center;
border: 1px solid green;
border-radius: 40px;
position: relative;
cursor: pointer;
}
#myText {
border-radius: 40px;
outline: none;
padding: 0 2%;
width: 51%;
margin: 2%;
}
.addTagBoxButton {
border: 1px solid black;
background-color: white;
border-radius: 5px 5px 5px 5px;
outline: none;
margin: 2% 5%;
width: 23%;
max-width: 200px;
float: right;
}
.tagBox-dropdown {
display: none;
padding: 1rem;
background-color: darkgrey;
position: absolute;
top: calc(100% + 5px);
left: 0;
z-index: 1;
}
.dropdown--isVisible {
display: block;
}
.tagBox-destroy {
position: relative;
border: none;
background-color: white;
color: darkblue;
}
.tagBox-dropdown-textarea {
margin-top: 10%;
margin-right: 0%;
margin-left: 0.96%;
margin-bottom: 0%;
z-index: 2;
display: block;
overflow: hidden;
padding: 10px;
font-size: 14px;
border-radius: 6px;
border: 0;
resize: none;
}
.text {
text-align: center;
margin-top: 30%;
cursor: default;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<input id="myText" type="text" name="Kompetenser" autocomplete="off" autofocus>
<input id="addTagBoxButton" class="addTagBoxButton" type="button" value="Add box">
<div id="tagsContainer"></div>
<script src="./script.js"></script>
<template id="tagBoxTemplate">
<div class="tagBox">
<span class="tagBox-label"></span>
<button class="tagBox-destroy">X</button>
<div class="tagBox-dropdown">
<textarea name="description" class="tagBox-dropdown-textarea" placeholder="Type some description here"></textarea>
</div>
</div>
</template>
</body>
</html>
PS: for the tag boxes I opted for wrapping its base structure in a template element so it does not mess our JS code with HTML (this is very subjective though). And I linked the JS to an external file.
Upvotes: 0
Reputation: 2093
You're correct - all IDs must be unique. In order to achieve this, you'll have to refactor a large portion of your code. For example, the textarea
function is triggered by clicking on the added boxes - that's fine. The problem is that the function isn't aware of which box was actually clicked - it refers to an element with a fixed ID "dropdown". Since there are multiple elements with the same ID, it has no way of knowing which box needs to be expanded.
You could simply pass this
as an argument to this function and refer to the context, but then you'd have to account for the fact that you're using a global variable dropbox
declared outside of the function's scope.
I've rewritten the whole thing. That's how I would implement this feature. I saw you're using jQuery in a few lines, hence my code largely depends on it. If you can't use jQuery in your final project, let me know, I'll post a version in pure vanilla JS. I also had to make some tiny CSS changes (flexbox).
Fiddle: https://jsfiddle.net/zLm2x5k6/
Snippet:
$(document).ready(() => {
//You can use IDs here because these elements are unique
const $addBtn = $("#läggatill");
const $inputBox = $("#myText");
const $flexBox = $("#flexbox");
$addBtn.click(() => {
//Creating a new box that contains everything we need and saving it to a variable
//I'm using ES6 template strings to embed the value of $inputBox
const $box = $(`
<div class="box">
<div class="newrect">
${$inputBox.val()}
<button class="hej">X</button>
</div>
<div class="dropdown">
<p class="text" id="text">Add description</p>
<textarea class="autoExpand"></textarea>
</div>
</div>
`);
//Adding event listeneres for the box elements
$box.find(".hej").click(function () {
//Removing the parent .box wrapper DIV
$(this).closest(".box").remove();
});
$box.find(".newrect").click(() => {
const $dropdown = $box.find(".dropdown");
//If the dropdown is invisible, show it. Otherwise, hide it
if ($dropdown.css("display") === "none") {
$box.find(".dropdown").show();
} else {
$box.find(".dropdown").hide();
}
});
//Appending the box to the flexBox
$box.appendTo($flexBox);
});
});
html, body { /* So you can adjust height */
height: 100%;
margin: 0;
padding: 0;
}
/* Start of lägga till kompetens */
.newrect {
min-width: 105px;
max-width: 195px;
margin-top: 1%;
margin-right: 1%;
margin-left: 1%;
margin-bottom: 0%;
padding: 5px 10px 5px 10px;
border: 1px solid green;
border-radius: 40px;
text-align: center;
background-color: white;
z-index: 2;
cursor: pointer;
}
.flexbox{
display: flex;
flex-direction: row;
}
.skriv {
border-radius: 40px 40px 40px 40px;
outline: none;
padding: 0 2%;
width: 51%;
margin: 2%;
}
.läggatill {
border: 1px solid black;
background-color: white;
border-radius: 5px 5px 5px 5px;
outline: none;
margin: 2% 5%;
width: 23%;
max-width: 200px;
float: right;
}
.dropdown {
display: none;
background-color: darkgrey;
height: 400px;
margin-top: 3%;
margin-right: 0%;
margin-left: 0.96%;
margin-bottom: 0%;
z-index: 1;
width: 100px;
}
.dropdown textarea{
width: 100px;
}
.show {
display: block;
}
.hej {
position: relative;
border: none;
background-color: white;
color: darkblue;
}
.autoExpand {
/* display: none; */
/* position: absolute !important; */
margin-top: 10%;
margin-right: 0%;
margin-left: 0.96%;
margin-bottom: 0%;
z-index: 2;
display: block;
overflow: hidden;
padding: 10px;
font-size: 14px;
border-radius: 6px;
border: 0;
resize: none;
}
.text {
text-align: center;
margin-top: 30%;
cursor: default;
}
/* End of lägga till kompetens */
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="css/Profil.css"> <!-- Länk till CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"> <!-- Bootstrap -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>
</head>
<body>
<input id="myText" type="text" class="skriv" name="Kompetenser" autocomplete="off" autofocus> <!-- Textfield for kompetenser -->
<input id="läggatill" class="läggatill" type="button" value="Add box"> <!-- Button lägga till -->
<div class="flexbox" id="flexbox"></div> <!-- Container for the boxes -->
<span style="display:block;">
</span>
</body>
</html>
Upvotes: 2