Basically, I have a list, and I wish that the users can add elements to it. It's something basic like this:
Whenever the user clicks on the plus button, a new input shows up, and if the user THEN clicks anywhere else, the input should disappear, and get replaced with a new span element (not at the replacement step yet). My code currently looks like this:
var toggleBtn = `<i class="fas fa-caret-down"></i>`
var newUL = `<ul class='active'></ul>`
//toggle tree view
//for outer layer
$("ul").on("click", ".fa-caret-down", function(){
$(this).parent().toggleClass("caret-down");
$(this).closest("li").find(".active").toggleClass("nested");
})
//for sublayer
$(".active").on("click", ".fa-caret-down", function(){
$(this).parent().toggleClass("caret-down");
$(this).closest("li").find(".active").toggleClass("nested");
})
//add new element
$(".fa-plus-square").on("click", function(){
//if there's no new list, create a new unordered list
if ($(this).closest("li").find("ul").length == 0){
$(this).parents("li").append(newUL);
//and add toggle button
$(this).parent().prepend(toggleBtn);
}
//add the element
addElement($(this));
})
function addElement(a){
a.closest("li").find("ul").append("<li><input id='newInput' value='sub_element'></li>")
$("#newInput").select();
/////problem?/////
$(document).click(function(e) {
//user clicked on something else
if ( e.target.id != 'newInput' ) {
var value = $("#newInput").val();
console.log(value);
$("input").remove();
}
})
/////problem?/////
}
ul, #myUL {
list-style-type: none;
}
#myUL {
margin: 0;
padding: 0;
}
.fa-caret-down,
.fa-plus-square{
cursor: pointer;
user-select: none;
color: grey;
}
.caret-down .fa-caret-down{
transform: rotate(270deg);
}
.active {
display: block;
}
.nested {
display: none;
}
.editor{
display: grid;
grid-template-areas: 'a b b'
'c c c';
}
.triggerDetail{
width: 400px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://kit.fontawesome.com/8b6dca0357.js" crossorigin="anonymous"></script>
<div class="triggerList">
<ul id="myUL">
<li><span class="caret caret-down"><i class="fas fa-caret-down"></i>Parent</span>
<ul class="active">
<li class="addable">
<span>Element <i class="fas fa-plus-square"></i></span>
</li>
<li class="addable"><span>Element <i class="fas fa-plus-square"></i></span></li>
<li class="addable"><span>Element <i class="fas fa-plus-square"></i></span></li>
</ul>
</li>
<li><span class="caret caret-down"><i class="fas fa-caret-down"></i>Parent</span>
<ul class="active">
<li class="addable"><span class="caret caret-down">Element <i class="fas fa-plus-square"></i></span>
</li>
<li class="addable"><span>Element <i class="fas fa-plus-square"></i></span>
</li>
<li class="addable"><span>Element <i class="fas fa-plus-square"></i></span>
</li>
</ul>
</li>
</ul>
</div>
But the problem right now is, I click on the plus button, but the event handler in the addElement() is already executing. The value is logged on to the console. The input is probably created and immediately removed.
I tried the promise().done(function(){}), because I ran into concurrency issues with animation before and that was the solution. And it appears that that only works on animation. I tried the method in this answer and it didn't work (obviously, but thought I'd give it a shot. Maybe I tweaked it wrong?)
Ideal sequence:
First click on plus button -> input created and selected -> wait for user to click on anywhere else -> remove input element.
Current sequence:
First click on the plus button -> executes all the way to the end, input created and removed.