Keep element in the bottom of dynamically changing panel - javascript

I'm using bootstrap and i have text fields which will make panel larger as they're added dynamically. Now these text fields are inside of a panel element and textfield size is col-lg-9 and there's more room in the col-lg-3 right next to it.
I would like to place a button in that col-lg-3 div, which would stay always in the bottom of the panel - so if the panel height increases due to new text field the button stays still in the bottom. I've tried absolute and relative positioning but nothing has helped + some of the methods pointed out break the scalability (which i really need to keep).
I'm adding my code:
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title panel-header-text">Sisesta nimed, mis pannakse tabelisse</h3>
</div>
<div class="panel-body">
<div class="col-lg-9" id="inputcontainer">
<h4>Sisestamisel tekib uus väli (TAB-iga saab vahetada rida). Tühjasid välju ei arvestata!</h4>
<div class="input-group input-group-lg pdgtop">
<span class="input-group-addon" id="basic-addon1">1.</span>
<input type="text" id="one" class="form-control text-controller" placeholder="Sisesta nimi siia">
</div>
</div>
<div class="col-lg-3 konteiner">
<button type="button" class="btn btn-success buttonel">Valmista tabel</button>
</div>
</div>
The javascript:
/*
#FN01: This function handles the creation of new text fields according to the change in the textfield.
*/
var createNew = true;
var counter = 2;
function getNewInsertion() {
var container = document.getElementById("inputcontainer");
var inputs = document.getElementsByClassName("text-controller");
var lastField = inputs[inputs.length-1];
if (document.activeElement.value.length == 0 && createNew == false){ //if new element is chosen createNew will be set true
createNew = true;
}
else if (createNew == true && lastField.value.localeCompare("") != 0 ){
createNew = false;
//Creates Input Field
var input = document.createElement("input");
input.type = "text";
input.className = "form-control text-controller";
input.placeholder = "Sisesta siia nimi";
//Creates Span to hold the count
var span = document.createElement("span");
span.textContent = counter;
span.className = "input-group-addon";
//Creates input group to put span & input field together
var inputgroup = document.createElement("div");
inputgroup.className = "input-group input-group-lg";
inputgroup.appendChild(span);
inputgroup.appendChild(input);
container.appendChild(inputgroup);
counter += 1;
}
return createNew;
}
/*
#FN02: This is the function to delete the last field (empty) in case the one before last is empty.
*/
function canWeDeleteField(){
var inputs = document.getElementsByClassName("input-group");
var lastInput = inputs[inputs.length-1];
var lastArr = lastInput.childNodes
if (inputs.length < 2){
var last = lastArr[3];
}
else{
var last = lastArr[1];
}
console.log(lastArr);
if (inputs.length >= 2){
var last_prev_Input = inputs[inputs.length-2];
var last_prev_Arr = last_prev_Input.childNodes
if (inputs.length == 2){
var last_prev = last_prev_Arr[3];
}
else{
var last_prev = last_prev_Arr[1];
}
if (last.value.localeCompare("") == 0 && last_prev.value.localeCompare("") == 0){
lastInput.parentNode.removeChild(lastInput);
counter = counter - 1;
}
}
}
/*
#FN03: The call-out function which is triggered when key is pressed while focus is on the textfield.
*/
$(function() {
$("#inputcontainer").bind("paste cut keydown",function(e) {
getNewInsertion();
canWeDeleteField();
})
});
AND THE CSS:
.konteiner {
position: relative;
}
.buttonel {
width: 95%;
padding-right: 1%;
position: absolute;
}

You can check the solution to your problem in the following link Bootstrap equal-height columns experiment.
Basically you have to wrap your columns in a div element containing the classes "row" and "row-eq-height".
Here's a snippet of the result (using your code):
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<link rel="stylesheet" href="http://getbootstrap.com/dist/css/bootstrap.min.css">
<style type="text/css">
.row-eq-height {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
}
.buttonel {
position: absolute;
bottom: 0;
}
</style>
</head>
<body>
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title panel-header-text">Sisesta nimed, mis pannakse tabelisse</h3>
</div>
<div class="panel-body">
<div class="row row-eq-height">
<div class="col-lg-9 col-md-9" id="inputcontainer">
<h4>Sisestamisel tekib uus väli (TAB-iga saab vahetada rida). Tühjasid välju ei arvestata!</h4>
<div class="input-group input-group-lg pdgtop">
<span class="input-group-addon" id="basic-addon1">1.</span>
<input type="text" id="one" class="form-control text-controller" placeholder="Sisesta nimi siia">
</div>
</div>
<div class="col-lg-3 col-md-3">
<button type="button" class="btn btn-success buttonel">Valmista tabel</button>
</div>
</div>
</div>
</div>
<script type="text/javascript">
var createNew = true;
var counter = 2;
function getNewInsertion() {
var container = document.getElementById("inputcontainer");
var inputs = document.getElementsByClassName("text-controller");
var lastField = inputs[inputs.length - 1];
if (document.activeElement.value.length == 0 && createNew == false) { //if new element is chosen createNew will be set true
createNew = true;
} else if (createNew == true && lastField.value.localeCompare("") != 0) {
createNew = false;
//Creates Input Field
var input = document.createElement("input");
input.type = "text";
input.className = "form-control text-controller";
input.placeholder = "Sisesta siia nimi";
//Creates Span to hold the count
var span = document.createElement("span");
span.textContent = counter;
span.className = "input-group-addon";
//Creates input group to put span & input field together
var inputgroup = document.createElement("div");
inputgroup.className = "input-group input-group-lg";
inputgroup.appendChild(span);
inputgroup.appendChild(input);
container.appendChild(inputgroup);
counter += 1;
}
return createNew;
}
/*
#FN02: This is the function to delete the last field (empty) in case the one before last is empty.
*/
function canWeDeleteField() {
var inputs = document.getElementsByClassName("input-group");
var lastInput = inputs[inputs.length - 1];
var lastArr = lastInput.childNodes
if (inputs.length < 2) {
var last = lastArr[3];
} else {
var last = lastArr[1];
}
console.log(lastArr);
if (inputs.length >= 2) {
var last_prev_Input = inputs[inputs.length - 2];
var last_prev_Arr = last_prev_Input.childNodes
if (inputs.length == 2) {
var last_prev = last_prev_Arr[3];
} else {
var last_prev = last_prev_Arr[1];
}
if (last.value.localeCompare("") == 0 && last_prev.value.localeCompare("") == 0) {
lastInput.parentNode.removeChild(lastInput);
counter = counter - 1;
}
}
}
/*
#FN03: The call-out function which is triggered when key is pressed while focus is on the textfield.
*/
$(function() {
$("#inputcontainer").bind("paste cut keydown", function(e) {
getNewInsertion();
canWeDeleteField();
})
});
</script>
</body>
</html>
Hope it helps!

Related

Detecting last item with display flex

Following having applied display flex/ display none with javascript, I want a function that detects the last item that contains display flex, in my example that would be the letter B.
Example code:
const containerDiv = document.querySelector('.container');
const listArray = Array.from(containerDiv.children);
listArray.forEach((item) => {
if(item.innerHTML === "A" || item.innerHTML === "B"){
item.style.display = "flex";
} else {
item.style.display = "none";
}
});
<div class="container">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
</div>
Any ideas?
Instead of use inline css you can use class and querySelectorAll for catch last item with .flex class
const containerDiv = document.querySelector('.container');
const listArray = Array.from(containerDiv.children);
listArray.forEach((item) => {
if(item.innerHTML === "A" || item.innerHTML === "B"){
item.classList.add("flex");
} else {
item.classList.add("none");
}
});
const divFlex = [...containerDiv.querySelectorAll('div.flex')];
console.log(divFlex[divFlex.length - 1])
.flex{
display:flex;
}
.none{
display:none;
}
<div class="container">
<div class="item">A</div>
<div class="item">B</div>
<div class="item">C</div>
</div>

Making a "Guess the Color" game and can't figure out how to add the correct answer

I'm stumped on how to make the hex code displayed at the top one of the choices on the "board." This is what I've tried so far.
var colorCode = '#' + Math.random().toString(16).slice(2, 8);
hexCode.innerHTML = colorCode;
var divs = document.getElementsByTagName('div')
for (var i = 0; i < divs.length; i++) {
divs[i].style.backgroundColor = '#' + Math.random().toString(16).slice(2, 8);
}
.panel {
height: 100px;
width: 100px;
border: 2px solid yellow;
border-radius: 25%;
}
<header>
<h1>Guess the Color</h1>
</header>
<main>
<span id="hexCode"></span>
<div id="one" class="panel"></div>
<div id="two" class="panel"></div>
<div id="three" class="panel"></div>
<div id="four" class="panel"></div>
</main>
https://jsfiddle.net/magoo/6vdfcmnL/6/
Is not clear if you want to show the text above every panel or just make one of the panel below the title the correct one; By the way i edited the code to do both.
Try to edit the code like this to check if result as intended.
HTML part:
<header>
<h1>Guess the Color</h1>
</header>
<main>
<!-- question -->
<p id="hexCodeToGuess"></p>
<br>
<!-- one -->
<span id="oneHexCode" class="label"></span>
<div id="one" class="panel"></div>
<!-- two -->
<span id="twoHexCode" class="label"></span>
<div id="two" class="panel"></div>
<!-- three -->
<span id="threeHexCode" class="label"></span>
<div id="three" class="panel"></div>
<!-- four -->
<span id="fourHexCode" class="label"></span>
<div id="four" class="panel"></div>
</main>
Javscript part:
var colorCodeToGuess = '#' + Math.random().toString(16).slice(2, 8);
// set the first label with the question (the color code to guess)
hexCodeToGuess.innerHTML = colorCodeToGuess;
// list of panels
var panels = document.getElementsByClassName('panel');
// list of labels
var labels = document.getElementsByClassName('label');
// generate the position of the right answer panel (random to make it unpredictable)
var correctPanelIndex = getRandomInt(panels.length);
// cycle trough the divs
for (var i = 0; i < panels.length; i++) {
// set by default a random new color
var currentColorCode = '#' + Math.random().toString(16).slice(2, 8);
// the div is in the right answer position => override the current color with the colorCodeToGuess generate at the start (the problem of the previous code)
if(i == correctPanelIndex){
currentColorCode = colorCodeToGuess;
}
// set the color to the panel
panels[i].style.backgroundColor = currentColorCode;
// set the text on a label above the panel
labels[i].innerHTML = currentColorCode;
}
// an useful function to get a random integer passing it the numer of values possible
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
You will notice that one of the panels have the same code of the question of the first code written below the title.
I've also commented the code so you can remove the unwanted logic consciously.
Your question is a little vague but if i got it right you want to display the background color of one of your divs in hex format. The following code will do that. I have added comments on the code to explain what im doing.
//get your panels (using selector is better that using div)
var divs = document.querySelectorAll(".panel");
for (var i = 0; i < divs.length; i++) {
divs[i].style.backgroundColor = '#' + Math.random().toString(16).slice(2, 8);
}
//get the current backgrounds of all panels and add them to an array in hex format
curruntColorsArr = [];
x = document.querySelectorAll(".panel");
for (i = 0; i < x.length; i++) {
//get background color
backgroundColors = x[i].style.backgroundColor
//convert to hex
function rgbToHex(rgb) {
return '#' + rgb.match(/[0-9|.]+/g).map((x, i) => i === 3 ? parseInt(255 * parseFloat(x)).toString(16) : parseInt(x).toString(16)).join('')
}
//push to array
curruntColorsArr.push(rgbToHex(backgroundColors));
}
//get random color from the array and set it to innerHTML
function random_item(items) {
return items[Math.floor(Math.random() * items.length)];
}
const hexCode = document.getElementById("hexCode")
hexCode.innerHTML = random_item(curruntColorsArr)
.panel {
height: 100px;
width: 100px;
border: 2px solid yellow;
border-radius: 25%;
}
<header>
<h1>Guess the Color</h1>
</header>
<main>
<span id="hexCode"></span>
<div id="one" class="panel"></div>
<div id="two" class="panel"></div>
<div id="three" class="panel"></div>
<div id="four" class="panel"></div>
</main>

Animation and transition property with setTimeout() function

I'm fairly new to JS, and I'm trying to make a simple text slide animation. However, when the animation event is activated the first time, the transition property doesn't apply. Every time after that it works fine.
So I'm struggling with the first execution of the slide animation.
Here is the code:
function slide_animation(direction){
// Init
let text = document.querySelector(".story .box .right-part .text");
let text_html = text.innerHTML;
let text_slide = [
"Text n°1",
'Text n°2',
'Text n°3'
];
let current_slide = 0;
// Looking for the current_slide
for(let i=0;i<text_slide.length;i++){
if (text_slide[i]==text_html){current_slide = i};
}
// Calculating the next slide position
if (direction=='right'){
if (current_slide >= text_slide.length-1){
current_slide = 0;
}
else {current_slide+=1;}
}
else {
if (current_slide <= 0){
current_slide = text_slide.length-1;
}
else {
current_slide = current_slide-=1;
}
}
// Animation
setTimeout(()=>{
text.style.transition = '0.5s';
text.style.opacity = 0;
text.style.left = '100px';
},250);
setTimeout(()=>{
text.innerHTML = text_slide[current_slide];
text.style.opacity = 1;
text.style.left = '0px';
},750)
}
.story .box .right-part .text-container .text {
line-height: 1.25;
position: relative;
}
<div class="box">
<div class="left-part">
<div class="text-container">
<p class="text">
<span class="text-padding fontsize-md">----</span>
</p>
</div>
<div class="buttons-container">
<button class="backward" onclick="slide_animation('left')"></button>
<button class="forward" onclick="slide_animation('right')"></button>
</div>
</div>
<div class="right-part">
<div class="text-container">
<p class="text fontsize-sm">Text n°1</p>
</div>
</div>
</div>
Anyway , it is fixed. I added another setTimeOut that did nothing really useful on the text , i placed it just before the others setTimeOut and it seems to work out properly.
Here is what is inserted :
setTimeout(()=>{
text.style.left=0;
},0)

How to reveal text from a button that is clicked, then hide the previous text if new button is cllicked

I am trying to make it so that when I click on a category, the text, for that category appears. Then when a new category is clicked, the previous category text is removed, and the text for the new category takes its place. Right now, no matter what button I click, all items appear.
index.html
<div class='container'>
<button class="button">Fit guide</button>
<button class="button">Care</button>
<button class="button">Materials</button>
<div class="single-entry">
<p class="fit">lkasdnf;aksdjf;askdjflkjsdhflkajsdhflaksjdhfaksjdhflkasjdhfasjdbflaksjdhflkasdjhfkajsdbas</p>
</div>
<div class="single-entry">
<p>lkasdnf;aksdjf;askdjflkjsdhflkajsdhflaksjdhfaksjdhflkasjdhfasjdbflaksjdhflkasdjhfkajsdbas</p>
</div>
<div class="single-entry">
<p>lkasdnf;aksdjf;askdjflkjsdhflkajsdhflaksjdhfaksjdhflkasjdhfasjdbflaksjdhflkasdjhfkajsdbas</p>
</div>
</div>
index.js
const displayEntryButton = document.querySelectorAll('.button');
const test = document.querySelector('.fit');
for (var j = 0; j < displayEntryButton.length; j++) {
displayEntryButton[j].addEventListener('click', function () {
const allEntries = document.querySelectorAll('.single-entry');
for (let index = 0; index < allEntries.length; index++) {
if(allEntries[index].style.display === 'none') {
allEntries[index].style.display = 'block'
} else {
allEntries[index].style.display = 'none';
}
}
})
}
I've adjusted your code a bit to get things working.
My adjustment primarily adds an id to each entry div and a matching data-value to each button.
The id and data-value are then used for comparison when a button is clicked. If there's a match, the corresponding content is displayed.
Try the snippet below. - Comments are included within the code.
const displayButtons = document.querySelectorAll('.button');
const entryDivs = document.querySelectorAll('.single-entry');
//start for loop to iterate over each button
for (j = 0; j < displayButtons.length; j++) {
//btnValue is declared to capture the data-value attribute
const btnValue = displayButtons[j].getAttribute('data-value');
displayButtons[j].addEventListener('click', function() {
//nested loop to iterate over each entry div
for (i = 0; i < entryDivs.length; i++) {
//entryId is declared to capture the div id
const entryId = entryDivs[i].id;
//if btnValue matches entryId
if (btnValue === entryId) {
//show the corresponding content
entryDivs[i].style.display = "block"
} else {
//otherwise show nothing
entryDivs[i].style.display = "none"
}
}
})
}
/*set all entries to display none by default*/
.single-entry {
display: none;
}
<div class='container'>
<!-- Here we are setting a data-value on each button -->
<!-- The data-value must match the id for each corresponding div -->
<button class="button" data-value="fit">Fit guide</button>
<button class="button" data-value="care">Care</button>
<button class="button" data-value="materials">Materials</button>
<!-- Each div below has an id to match each buttons data-value -->
<div class="single-entry" id="fit">
<p>FIT ENTRY</p>
</div>
<div class="single-entry" id="care">
<p>CARE ENTRY</p>
</div>
<div class="single-entry" id="materials">
<p>MATERIALS ENTRY</p>
</div>
</div>

Javascript - How to limit character in a contentEditable div?

I am learning english yet. Thank you for you patience.
I created a todo list CRUD. The code is working well but I am improving even more my code.
When I press the button "plus" I create a div with the text, button delete and edit as you can see in the pic.
Task created
But when I pass a certain number of characters, it happens. (See the pic)
When the task is big, it passes to other line
How can I put a limit to it? Thank you!
My HTML code:
<body>
<header>
<h1>Lista de Tarefas</h1>
</header>
<form>
<input type="text" name="task" id="task" maxlength="34">
<button class='btnadd'><i class="fas fa-plus"></i></button>
</form>
<div class="container-tasks">
<ul class="list-task"></ul>
</div>
<script src="/js/app.js"></script>
</body>
My Javascript code:
let input = document.getElementById('task');
let btnAdd = document.querySelector(".btnadd");
let list = document.querySelector(".list-task");
// Events
btnAdd.addEventListener('click', addTask);
// Functions
function addTask(event){
event.preventDefault();
if (input.value === ''){
alert('You must type something');
return false;
} else {
addTask
}
let divTask = document.createElement("div");
divTask.classList.add("task");
let newTask = document.createElement("div");
newTask.innerText = input.value;
newTask.classList.add("new-task");
divTask.appendChild(newTask);
let btnDelete = document.createElement('button');
btnDelete.innerHTML = 'Remover';
btnDelete.classList.add("btn-remover");
divTask.appendChild(btnDelete);
let btnEdit = document.createElement('button');
btnEdit.innerHTML = 'Editar';
btnEdit.classList.add("btn-editar");
divTask.appendChild(btnEdit);
list.appendChild(divTask);
input.value = "";
btn.addEventListener('click', removeTask);
function removeTask(){
divTask.remove();
}
btnEdit.addEventListener('click', editTask);
function editTask(){
const endEdit = document.createElement('button');
endEdit.classList.add('end-edit');
endEdit.innerHTML = 'Finalizar'
divTask.appendChild(endEdit);
newTask.contentEditable = true;
newTask.focus();
btnEdit.style.display = 'none'
endEdit.addEventListener('click', endEdition);
function endEdition(){
newTask.contentEditable = false;
endEdit.remove();
btnEdit.style.display = 'block'
}
}
}
I dont think there is a definite option for that, but you can surely use keydowns count.
jQuery
$('div').on('keydown', function(event) {
$('span').text('Total chars:' + $(this).text().length);
if($(this).text().length === 100 && event.keyCode != 8) {
event.preventDefault();
}
});
div {
height: 100px;
width: 300px;
border: 1px solid grey;
outline: 0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div contenteditable="true"></div>
<span></span>
Vanilla JS
let maxChars = 10;
let currentChars = 0;
function checkLength(event) {
if(currentChars >= maxChars) {
alert('reached max chars');
event.preventDefault();
} else {
currentChars++;
}
}
div {
height: 100px;
width: 300px;
border: 1px solid grey;
outline: 0;
}
<div contenteditable="true" onkeypress="checkLength(event)"></div>
<span></span>

Categories