Мне нужна помощь, чтобы найти решение с конфликтом событий focusout
и click
.
Я делаю проект dropdownlist
, поэтому у нас есть две части раскрывающегося списка:
Если click
на кнопке со стрелкой, это открывает список. Но, когда вы click
на кнопке со стрелкой, это должно закрыть список.
Если click
в текстовом поле, это открывает список. Но когда вы click
в текстовом поле, это должно закрыть список.
Проблема, которая у меня есть, это событие focusout
текстового поля при попытке закрыть список, нажав кнопку со стрелкой. Он открывается, закрывается и снова открывается.
Таким образом, он должен закрываться сразу, когда это необходимо, и когда происходит фокусировка, если список открыт.
PS: кнопка удаления не работает еще.
Что делать?
"use strict";
// LISTA DE INICIALIZACIÓN DE VARIABLES
// Se obtiene los ID de los elementos principales.
const tagSys = document.getElementById('tag-sys');
const tagInput = document.getElementById('input-section');
const textInput = document.getElementById('text-input');
const arrowButton = document.getElementById('btn-arrow');
var displayToggle = false;
// Se crea un arreglo por default.
var data = [
'The Shawshank Redemption',
'The Godfather',
'The Godfather: Part II',
'The Dark Knight',
'12 Angry Men',
"Schindler's List",
'Pulp Fiction',
'The Lord of the Rings: The Return of the King',
'The Good, the Bad and the Ugly',
'Fight Club'
];
// LISTA DE EVENTOS ACONTINUACIÓN
/*
El siguiente addEventListener se aplica sobre textInput.
Su función hace mostrar el listado de data segun las palabras
ingresadas.
*/
textInput.addEventListener('keyup', function (e) {
console.log('keyup');
let hasData = DropdownFilter(e.target.value);
DropdownDisplay(hasData);
});
/*
El siguiente addEventListener se aplica sobre textInput.
Su función hace mostrar el listado de la data.
*/
textInput.addEventListener('click', function () {
DisplayToggle();
});
/*
El siguiente addEventListener se aplica sobre textInput.
Su función hace cerrar el listado de la data.
*/
textInput.addEventListener('focusout', function () {
if (displayToggle == true) {
let hasData = false;
DropdownDisplay(hasData);
displayToggle = false;
}
});
/*
El siguiente addEventListener se aplica sobre arrowButton.
Su función hace enviar el focus al textInput y mostrar
el listado de la data.
*/
arrowButton.addEventListener('click', function () {
textInput.focus();
DisplayToggle();
});
// LISTA DE MÉTODOS ACONTINUACIÓN
function DisplayToggle() {
if (displayToggle == false) {
let hasData = DropdownList(data);
DropdownDisplay(hasData);
displayToggle = true;
} else {
let hasData = false;
DropdownDisplay(hasData);
displayToggle = false;
}
}
/*
El siguiente método DropdrowFilter, recibe como parametro
una palabra que se encarga de buscar dentro del arreglo,
para luego enviar al metodo DropdownList.
*/
function DropdownFilter(params) {
let dataFilter = data.filter(function (e) {
return e.toLowerCase().includes(params.toLowerCase());
});
return DropdownList(dataFilter);
}
/*
El siguiente método DropdrowList, recibe como parametro
una lista de datos que usara para mostrar.
*/
function DropdownList(dataList) {
RemoveList();
if (dataList.length != 0) {
let objList = {
div: document.createElement('div'),
ul: document.createElement('ul'),
li: ''
};
objList.div.setAttribute("id", "tag-list");
objList.div.classList.add('tag-list');
tagInput.appendChild(objList.div);
objList.div.appendChild(objList.ul);
dataList.forEach(element => {
objList.li = document.createElement('li');
objList.li.textContent = element;
objList.ul.appendChild(objList.li);
});
} else {
let objList = {
div: document.createElement('div'),
ul: document.createElement('ul'),
li: document.createElement('li')
};
objList.div.setAttribute("id", "tag-list");
objList.div.classList.add('tag-list');
tagInput.appendChild(objList.div);
objList.div.appendChild(objList.ul);
dataList[0] = 'No options';
objList.li.textContent = dataList[0];
objList.ul.appendChild(objList.li);
}
return true; // Retornamos True porque ya retorna data para mostrar.
}
/*
El siguiente método RemoveList, cumple como función
eliminar la etiqueta con ID 'tag-list'.
*/
function RemoveList() {
if (document.getElementById('tag-list')) {
let div = document.getElementById('tag-list');
tagInput.removeChild(div);
}
}
/*
El siguiente metodo DropdownDisplay, cumple como función
agregar la clase 'tag-list-show' para que sea visible la data,
y la posición de la flecha.
*/
function DropdownDisplay(params) {
let div = document.getElementById('tag-list');
if (params == true) {
div.classList.add('tag-list-show');
arrowButton.classList.replace('fa-chevron-down', 'fa-chevron-up');
} else {
div.classList.remove('tag-list-show');
arrowButton.classList.replace('fa-chevron-up', 'fa-chevron-down');
}
}
body {
margin: 0;
background-color: #f39c12;
font-family: 'Poppins', sans-serif;
}
main {
align-items: center;
display: flex;
height: 100vh;
justify-content: center;
}
.tag-sys {
border: 1px solid #000000;
border-radius: 2px;
cursor: text;
display: flex;
font-size: 13px;
max-width: 200px;
min-height: 20px;
position: relative;
}
.input-section {
display: flex;
flex-wrap: wrap;
width: 80%;
}
.text-input {
border: none;
border-right: 1px solid #000000;
border-bottom-left-radius: 2px;
border-top-left-radius: 2px;
font-size: 1em;
flex: 1;
margin: 0;
min-width: 20px;
padding: 0;
padding-left: 2px;
}
.text-input::placeholder {
color: #bdc3c7;
}
.text-input:focus {
outline: none;
}
.control-section {
align-items: center;
background-color: #bdc3c7;
display: flex;
justify-content: space-around;
width: 20%;
}
.control-section-icon {
align-items: center;
border-radius: 3px;
cursor: pointer;
display: flex;
height: 16px;
justify-content: center;
width: 16px;
}
.control-section-icon i {
font-size: 14px;
}
.tag-list {
background-color: #ffffff;
border: 1px solid #000000;
border-radius: 2px;
position: absolute;
font-size: 14px;
height: 100px;
overflow-y: scroll;
left: -1px;
top: 22px;
width: 100%;
display: none;
}
.tag-list-show {
display: block !important;
}
.tag-list ul {
list-style-type: none;
margin: 0;
padding: 0;
}
.tag-list ul li {
padding: 5px;
}
.tag-list ul li:hover {
cursor: pointer;
background-color: #bdc3c7;
}
<link rel="stylesheet" type="text/css" href="style.css">
<link href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
<script src="https://kit.fontawesome.com/1001c03ba9.js" crossorigin="anonymous"></script>
<main>
<div id="tag-sys" class="tag-sys">
<div id="input-section" class="input-section">
<input id="text-input" class="text-input" type="text">
</div>
<div class="control-section">
<span class="control-section-icon">
<i id="btn-delete" class="fas fa-times"></i>
</span>
<span class="control-section-icon">
<i id="btn-arrow" class="fas fa-chevron-down"></i>
</span>
</div>
</div>
</main>
<script src="app.js"></script>