2

I have been trying to make this thing that focuses an input inside it when its outer div is clicked. I really hope this is not a duplicate as I have searched everywhere and not found an answer to this. I am at risk of being blocked so I hope no one flags this as a duplicate.

Here is the code below, it works with focusing the input, but when it has to unfocus it does not seem to work.

window.onload = function() {
  var drop = document.getElementsByClassName("datadrop");
  var drops = document.getElementsByClassName("datadrop").length;

  for (x = 0; x < drops; x++) {
    var input = document.getElementById(drop[x].getAttribute("input"));
    drop[x].onclick = function(e) {
      e.preventDefault();
      clicked = 0
      if (this == document.activeElement) {
        input.blur();
      } else {
        input.focus();
      }
    }
  }
}
.datadrop {
  padding: 7.5px;
  width: 85px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
}

.datadrop .drop {
  width: 150px;
  position: fixed;
  display: none;
}

.datadrop .item {
  padding: 10px;
}

.datadrop .item:hover {
  background-color: #F1F3F4;
}

.datadrop .divider {
  padding: 5px;
  color: grey;
}

.datadrop .divider:hover {
  background-color: #ffffff;
}

.datadrop input {
  width: 60px;
  color: black;
}

.datadrop:hover {
  background-color: #F1F3F4;
  color: #5F6368;
}

.datadrop .click {
  color: #5F6368;
}

.datadrop input {
  background-color: transparent;
  border: 1px solid transparent;
  outline: none;
  padding: 5px;
}

.datadrop input:focus {
  background-color: white;
  border: 1px solid black;
  border-radius: 2.5px;
}
<div datadrop="scale" input="scales" class="datadrop">
  <input type="text" id="scales" value="100%"> &nbsp;&nbsp;|&nbsp; <i class="fa-solid fa-caret-down click"></i>
  <div class="drop" id="scale">
    <div class="item">Fit</div>
    <div class="item divider">
      <hr>
    </div>
    <div class="item">Fit</div>
    <div class="item">Fit</div>
    <div class="item">Fit</div>
  </div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer" />

I hope someone has an answer to this using only JavaScript, and I hope no one flags this as a duplicate, as I am trying to not do duplicates.

topsoftwarepro
  • 773
  • 5
  • 19
  • It looks like the code works as it is? What exactly are you expecting the code to do? Notice that focus is not the same as hover. – Teemu Apr 14 '22 at 10:03
  • I am expecting it to unfocus as soon as I re-click it, I have looked up toggling focus but all of the other answers require me to use jQuery. – topsoftwarepro Apr 14 '22 at 10:06
  • There's a lot going on in the script. Whenever it creates more than a single event listener, `input` variable goes to haywire. See https://stackoverflow.com/q/750486/1169519 – Teemu Apr 14 '22 at 10:16
  • Do you by any chance know how I can resolve this? I would greatly appreciate it. – topsoftwarepro Apr 14 '22 at 10:28
  • @topsoftwarepro check my answer, I have commented out my changes in it. – Shoyeb Sheikh Apr 14 '22 at 10:51
  • @ShoyebSheikh thanks so much for your answer it works as well, but I found that one of the other answers addressed my problem the best, this is because I forgot to mention that I was going to use multiple of these, and your code only works for one of them. Still I appreciate your help and I have upvoted your answer as well! – topsoftwarepro Apr 17 '22 at 03:26

3 Answers3

3

I edited your snippet. you used a loop so i supposed that you want to have multiple inputs. By the way, be careful the element does't have a "input" attribute. I tried to follow the logic of your code so i replaced the "input" -wrong- attribute with a data-input attribute.

I used two flags to check if the input is selected: "inputIsSelected" and "selectedDrop"

if inputIsSelected and clicked on same parent blur if inputnotSelected and same parent focus if parent changes then set the inputIsSelected to false

window.onload = function() {
  var drop = document.getElementsByClassName("datadrop");
  var drops = document.getElementsByClassName("datadrop").length;
  let selectedDrop = null // a flag the clicked drop
  let inputIsSelected = false;
  console.log({drops})
  var x;  

  
  for (x = 0; x < drops; x++) {
    //var input = document.getElementById(drop[x].getAttribute("input"));
    
    let inputId = drop[x].dataset.input; //select inputId using a data-* attribute
 
    let input = document.getElementById(inputId);
    
    drop[x].onclick = function(e) {
       
      e.preventDefault();
      clicked = 0
      
      if(this!==selectedDrop){
       selectedDrop = this;
       inputIsSelected = false;
      }
      
      if(!inputIsSelected){
      input.focus();
      inputIsSelected=true;
      }else{
      inputIsSelected=false;
      input.blur()
      }
      
       
      
      
     
    }
  }
}
.datadrop {
  padding: 7.5px;
  width: 85px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
}

.datadrop .drop {
  width: 150px;
  position: fixed;
  display: none;
}

.datadrop .item {
  padding: 10px;
}

.datadrop .item:hover {
  background-color: #F1F3F4;
}

.datadrop .divider {
  padding: 5px;
  color: grey;
}

.datadrop .divider:hover {
  background-color: #ffffff;
}

.datadrop input {
  width: 60px;
  color: black;
}

.datadrop:hover {
  background-color: #F1F3F4;
  color: #5F6368;
}

.datadrop .click {
  color: #5F6368;
}

.datadrop input {
  background-color: transparent;
  border: 1px solid transparent;
  outline: none;
  padding: 5px;
}

.datadrop input:focus {
  background-color: white;
  border: 1px solid black;
  border-radius: 2.5px;
}
<div datadrop="scale" data-input="scales-1" class="datadrop">
  <input type="text" id="scales-1" value="100%"> &nbsp;&nbsp;|&nbsp; <i class="fa-solid fa-caret-down click"></i>
  <div class="drop" id="scale">
    <div class="item">Fit</div>
    <div class="item divider">
      <hr>
    </div>
    <div class="item">Fit</div>
    <div class="item">Fit</div>
    <div class="item">Fit</div>
  </div>
</div>
<div datadrop="scale" data-input="scales-2" class="datadrop">
  <input type="text" id="scales-2" value="100%"> &nbsp;&nbsp;|&nbsp; <i class="fa-solid fa-caret-down click"></i>
  <div class="drop" id="scale">
    <div class="item">Fit</div>
    <div class="item divider">
      <hr>
    </div>
    <div class="item">Fit</div>
    <div class="item">Fit</div>
    <div class="item">Fit</div>
  </div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
2

Try this,

window.onload = function() {
  var drop = document.getElementsByClassName("datadrop");
  var drops = document.getElementsByClassName("datadrop").length;
  var focus_array = []; // lets log each focus and blur in this array
  
  for (x = 0; x < drops; x++) {
    var input = document.getElementById(drop[x].getAttribute("input"));
    drop[x].onclick = function(e) {
      e.preventDefault();
      clicked = 0
      if (focus_array[x]) { // just check focus array 
        input.blur();
        focus_array[x]=0; //update focus array for blur
      } else {
        input.focus();
        focus_array[x]=1; //update focus array for focus
      }
    }
  }
}
.datadrop {
  padding: 7.5px;
  width: 85px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: white;
}

.datadrop .drop {
  width: 150px;
  position: fixed;
  display: none;
}

.datadrop .item {
  padding: 10px;
}

.datadrop .item:hover {
  background-color: #F1F3F4;
}

.datadrop .divider {
  padding: 5px;
  color: grey;
}

.datadrop .divider:hover {
  background-color: #ffffff;
}

.datadrop input {
  width: 60px;
  color: black;
}

.datadrop:hover {
  background-color: #F1F3F4;
  color: #5F6368;
}

.datadrop .click {
  color: #5F6368;
}

.datadrop input {
  background-color: transparent;
  border: 1px solid transparent;
  outline: none;
  padding: 5px;
}

.datadrop input:focus {
  background-color: white;
  border: 1px solid black;
  border-radius: 2.5px;
}
<div datadrop="scale" input="scales" class="datadrop">
  <input type="text" id="scales" value="100%"> &nbsp;&nbsp;|&nbsp; <i class="fa-solid fa-caret-down click"></i>
  <div class="drop" id="scale">
    <div class="item">Fit</div>
    <div class="item divider">
      <hr>
    </div>
    <div class="item">Fit</div>
    <div class="item">Fit</div>
    <div class="item">Fit</div>
  </div>
</div>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css" integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g==" crossorigin="anonymous" referrerpolicy="no-referrer" />
Shoyeb Sheikh
  • 2,659
  • 2
  • 10
  • 19
0

If you want to change the value of the input based on the value of the keyboard input without giving the input focus, you can do this.

let element = document.getElementById("scales");

window.addEventListener("keydown", function () {

     element.value = String.fromCharCode(event.keyCode);

})
Jin Liu
  • 73
  • 6