-4

Example #1: the user clicks #back2Top with focus at "P99" and the desired result is document.getElementById('P1').focus();

Example #2: the user clicks #backtoTop with focus at "P1" and the desired result is document.getElementById('PXX').focus(); when PXX is the first blank "PXX" ID

HTML

<div id = "back2Top" onclick = "togglePX ()">TOP</div>
<input id = "P1">
...
<input id = "P99">

CSS

#back2Top {display: table;  z-index: 999; cursor: pointer;  position: fixed; background-color: transparent;  text-align: center;  text-decoration: none; right:20px; bottom:20px }

JS

function togglePX () {
    if ($('#P1').is(":visible")) {
        for (let i = 1; i < 64; i++) {
            y = document.getElementById("P" +i).value; 
            alert(y)
            if (!y) {
                document.getElementById("P" +i).focus(); 
                break;
            }
        }

    } else {
        document.getElementById("P1").focus()
    }
    }
}
Don't Panic
  • 13,965
  • 5
  • 32
  • 51
verlager
  • 794
  • 5
  • 25
  • 43

6 Answers6

0

I hope that I understand the logic that you want to achieve.

I have made some changes on the code you have wrote and i guess now it works fine, just like the examples you gave.

its not good to use for loop with break in it, so i used the while loop. And I replaced the y with blank where I can reserve the first blank input I find, and if the loop finishes with no blank input, that means we have to go back to the first input #P1

function togglePX () {
  if ($('#P1').is(":visible")) {
    var i = 1;
    var blank;
    while(i<100 && blank == undefined){
      
      if (document.getElementById("P" +i).value.length == 0) {
        blank = document.getElementById("P" +i);
      }
      i++
    }
    if(blank == undefined)
      document.getElementById("P1").focus()
    else
      blank.focus()

  }
}
Ala Mouhamed
  • 302
  • 2
  • 4
0

You can use querySelector to get the first available non-empty value.

let lastFocus = null;

const togglePx = (e) => {
  if (lastFocus && lastFocus.id === 'P1') {
      const result = document.querySelector('input[value=""][id^="P"]');
      if (result) result.focus();
  } else {
      document.getElementById("P1").focus();
  }
};
document.getElementById("back2top").addEventListener('click', togglePx);

for (const e of document.querySelectorAll('input[id^="P"]')) {
    e.addEventListener("focus", (e) => {
        lastFocus = e.target;
    });
}
<input value="full" id="P1"><BR />
<input value="" id="P2"><BR />
<input value="" id="P3"><BR />
<div id="back2top">back to top</div>

This gets the first blank value with an ID that starts with P conditional on the last element that was focused on. If your naming strategy is more complex, I'd recommend using classes, but you can also use regex.

See querySelector, wildcard element match? for further information.

--

As for the other part of your question, it's not totally clear what you're asking for to me, but I'd strongly recommend toggling classes if you want to action against them rather than filtering by visibility. This is more flexible and less error-prone, in case you want to change how it looks/doesn't look later.

If, for example, you want to hide input after it's been entered, you should consider adding an event on focusout that adds a "hidden" class, and make that class do the hiding for you. You can then add that as a condition in querySelector, such as with querySelector('input:not(.hidden)[value=""][id^="P"]')

smcjones
  • 5,490
  • 1
  • 23
  • 39
0
function togglePX () {
  if ($('#P1').is(":visible")) {
    for (let i = 1; i < 64; i++) {
      // check for null
      if ( document.getElementById("P" +i) != null )
      {
        valueInText = document.getElementById("P" +i).value;                   
        if (!valueInText) {
            document.getElementById("P" +i).focus(); 
            break;
        }
      }
    }

} else {
    document.getElementById("P1").focus()
    }

}

Smitha Kalluz
  • 309
  • 5
  • 10
0

None of you followed the spec or gave a plausible answer that worked on my rig. That said, I appreciate (I guess...) the efforts.

I solved the problem which called for two functions based on whether #P1 was visable. I used https://github.com/customd/jquery-visible/blob/master/jquery.visible.min.js

function togglePX () {
if ($('#P1').visible(true)) {

for (let i = 1; i < 64; i++) {
y = document.getElementById("P" +i).value; 
           
if (!y) {
document.getElementById("P" +i).focus(); 
break;}
    
  
}

}

 else {
   document.getElementById("P1").focus();
}   
}
verlager
  • 794
  • 5
  • 25
  • 43
-1

You need to track focused input element. Because when you click on Top button, currently focused input looses its focus.

Demo code:

let focusedInput = null;

$(document).ready(function() {
  let noOfInputs = 99;
  // create input elements for the demo
  for (let count = 1; count <= noOfInputs; count++) {
    let elm = $("<input id='P" + count + "'></input>").val(count);
    $("body").append(elm);
  }
  //make one input empty for the demo
  $('body>input:eq(3)').val('');

  //this is important
  //track the focused element
  $('body>input').focus((event) => focusedInput = $(event.target));
});

function togglePX() {
  if (focusedInput) {
    if (focusedInput.is('body > input:last-of-type')) { //if last input is focused
      $('body > input:first-of-type').focus();

    } else if (focusedInput.is('body > input:first-of-type')) { //if first input is focused
      selectBlank();
    }
  } else { // if no input is selected select first blank
    selectBlank();
  }
}

function selectBlank() {
  //get all the blank elements
  let blanks = $('body > input').filter(function() {
    return this.value == ''
  });

  if (blanks.length > 0)
    blanks.first().focus();
  else //if all inputs are filled select first
    $('body > input:first-of-type').focus();
}
#back2Top {
  display: table;
  z-index: 999;
  cursor: pointer;
  position: fixed;
  background-color: transparent;
  text-align: center;
  text-decoration: none;
  right: 20px;
  bottom: 20px
}

input {
  display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

<div id="back2Top" onclick="togglePX ()">TOP</div>

I've used 'body > input' to select input elements you can use 'yourContainer > input' or '.inputStyleClass' etc.

In above demo :first-of-type and :last-of-type pseudo classes have been used. This way you don't have to hard code #P1 and #P99 to select first and last inputs.

To find blank inputs we can use jQuery .filter API. Then select the first one to focus.



I've added two extra use cases:

  • When the app loads and user hasn't selected any input and clicks on Top button. Then select first blank.
  • When all input are filled and user clicks on Top button. Then select first input.
the Hutt
  • 16,980
  • 2
  • 14
  • 44
-1

You got downvoted because the question is a bit unclear, but hopefully this is something close to what you are after. Your code is a mix of jQuery and plain JS, but you did tag your question with jQuery, so this is a jQuery solution.

The tricky part is finding the focussed input. It's tricky because as soon as you click your TOP div, the input that was previously focussed is suddenly not focussed! At the time of the click, focus is already gone.

So the answer is to track which input is focussed; every time an input becomes focussed, save which one it was in a variable:

let focussed;
$('input').on('focus', function() {
    focussed = $(this).attr('id');
});

Now even after focus has switched away, we still know which one it was.

The rest is relatively simple:

  • If the focussed element is (was) P99, set focus to P1;

  • Otherwise, find the first empty input, and set focus there. Note this is slightly different to what you specified. You said if the focus is P1 when TOP is clicked, focus should shift to the first empty input. In this code, clicking TOP with focus at any input, except P99, will shift focus to the first empty input. I did this because if you only shift focus when at P1, what do you do when focus is in P2 - P98? My guess is you want the same behaviour for those cases.

Here's a working snippet. Some notes:

  • I've only included inputs 1-30 and 99, enough for the page to scroll;

  • I moved the inline onclick() to a separate event handler, as that is considered better practice and separates your HTML from your JS, see eg jQuery.click() vs onClick ;

  • I am not sure what the if ($('#P1').is(":visible")) { test is for, your text does not mention anything about input visibility. I am assuming this was an experiement/attempt and isn't relevant;

  • I am assuming the 64 in your code is just an intermediate experiement/attempt, as your text and HTML specify there should be 99 inputs;

$(document).ready(function() {
    let focussed,
        $inputs = $('input'),
        $back2Top = $('#back2Top'),
        $p1 = $('#P1');

    // The function to set focus
    function togglePX() {

        // First check if we are at P99
        if (focussed == 'P99') {
            $p1.focus();

            // We're done
            return;
        }

        // For focus at any other input, let's find first blank input.
        // Iterate over all inputs, trimming whitespace to find the
        // empty ones, then take the first and focus it.
        $inputs.filter(function (index, element) {
            return $.trim($(element).val()) === '';
        }).first().focus();
    }

    // Handle clicks on TOP 
    $back2Top.on('click', function() {
        togglePX();
    });

    // Every time an input is focussed, store which one it was
    $inputs.on('focus', function() {
        focussed = $(this).attr('id');
        // console.log('Input #' + focussed + ' is focussed')
    });
});
#back2Top {
    display: table;
    z-index: 999;
    cursor: pointer;
    position: fixed;
    background-color: transparent;
    text-align: center;
    text-decoration: none;
    right:20px;
    bottom:20px;
}
input {
    padding: 6px;
    margin: 4px;
    display: block;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

<div id="back2Top">TOP</div>
<input id="P1">
<input id="P2">
<input id="P3">
<input id="P4">
<input id="P5">
<input id="P6">
<input id="P7">
<input id="P8">
<input id="P9">
<input id="P10">
<input id="P11">
<input id="P12">
<input id="P13">
<input id="P14">
<input id="P15">
<input id="P16">
<input id="P17">
<input id="P18">
<input id="P19">
<input id="P20">
<input id="P21">
<input id="P22">
<input id="P23">
<input id="P24">
<input id="P25">
<input id="P26">
<input id="P27">
<input id="P28">
<input id="P29">
<input id="P30">
....
<input id="P99">
Don't Panic
  • 13,965
  • 5
  • 32
  • 51