简体   繁体   中英

How to target the focused input dynamically

I have a Jquery code that will pop-up with a box saying "Today" only when a user focuses on an input field. When the user clicks on the box, this will populate the targeted input field with the current date. Currently my code is working but the problem is as follows:

Problem: When someone clicks on the Today button, it populates all the input fields on the page instead of the input being focused on.

I created a JSFiddle to give you the best representation of my site's structure and will give you an idea of what's happening. Im still learning a lot in with Jquery lately but this has stumped me. I tried to target the input itself by using $("input[id*=Next_Update]").val(now); but that just breaks the code.

Here is a quick sample of my code with the JSfiddle JSFiddle: https://jsfiddle.net/s68zhLxn/26/

$(document).ready(function() {
    $(".im_whiteboard [id*=Next_Update]").on('focusin', function() {
        var div = $('#now');
        var top = $('input').offset().top + $('input').height() + 5;
        var left = $('input').offset().left;
        $(div).css('top', top);
        $(div).css('left', left);
        $(div).fadeIn();
    });
    $('input').on('focusout', function() {
        $('#now').fadeOut();
    });
    $('#now').on('click', function() {
        var today = new Date();
        var dd = today.getDate();
        var mm = today.getMonth()+1; //January is 0!
        var yyyy = today.getFullYear();

        if(dd<10) {
            dd='0'+dd
        } 

        if(mm<10) {
            mm='0'+mm
        } 

        today = mm+'/'+dd+'/'+yyyy;
       $('input').val(today); 
    });
});

I would appreciate any support on this.

Few highlights:

  • Your code wont work as the $('input') selector will find and modify all the existing DOM inputs. Also, a click event on overlay <div> would result in current input losing focus.

  • Also You have multiple elements with same ID as now . Change it to class.

  • And as each of your <td> has an input + now , siblings() , next()/prev() would help you get current input element.


<td id="customEdit2_1_Next_Update_1c">
     <input id="customEditInput_1_Next_Update_1" type='text'/>
     <div class='now'>Today</div>    
     <!--here siblings will help you get the required `input`-->
</td>

Use

var div = $(this).siblings('.now');  //or if you have multiple inputs under one <tr> use $(this).closest('td').find('.now');

And while assigning values use,

$(this).siblings('input').val(today); 

Updated Fiddle

Run the live snippet below.

 $(document).ready(function() { $(".im_whiteboard [id*=Next_Update]").on('focusin', function() { var div = $(this).siblings('.now'); var top = $('input').offset().top + $('input').height() + 5; var left = $('input').offset().left; $(div).css('top', top); $(div).css('left', left); $(div).fadeIn(); }); $('input').on('focusout', function() { $('.now').fadeOut(); }); $('.now').on('click', function() { var today = new Date(); var dd = today.getDate(); var mm = today.getMonth()+1; //January is 0! var yyyy = today.getFullYear(); if(dd<10) { dd='0'+dd } if(mm<10) { mm='0'+mm } today = mm+'/'+dd+'/'+yyyy; $(this).siblings('input').val(today); }); }); 
 .now { top: 0; left: 0; display: none; position: absolute; background: #eee; color: tomato; border-radius: 2px; padding: 10px 20px; } .now:hover { cursor: pointer; background: #ccc; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script> <table class="im_whiteboard"> <tr> <td id="customEdit2_1_Next_Update_1c"> <input id="customEditInput_1_Next_Update_1" type='text'/> <div class='now'>Today</div> </td> </tr> <tr> <td id="customEdit2_1_Next_Update_2"> <input id="customEditInput_1_Next_Update_2" type='text'/> <div class='now'>Today</div> </td> </tr> <tr> <td id="customEdit2_1_Next_Update_3"> <input id="customEditInput_1_Next_Update_3" type='text'/> <div class='now'>Today</div> </td> </tr> </table> 

I have updated your fiddle: https://jsfiddle.net/seadonk/s68zhLxn/27/

apply the click function within your focus event handler function. Within this function you have access to 'this' ex: var self = $(this), which you can use to set the value.

$(document).ready(function () {
    $(".im_whiteboard [id*=Next_Update]").on('focusin', function () {
        var self = $(this);
        var div = $('#now');
        var top = $('input').offset().top + $('input').height() + 5;
        var left = $('input').offset().left;
        $(div).css('top', top);
        $(div).css('left', left);
        $(div).fadeIn().click(function(){
            self.val(getToday());
        });
    });

    function getToday(){
         var today = new Date();
        var dd = today.getDate();
        var mm = today.getMonth() + 1; //January is 0!
        var yyyy = today.getFullYear();

        if (dd < 10) {
            dd = '0' + dd
       }

        if (mm < 10) {
            mm = '0' + mm
        }

        today = mm + '/' + dd + '/' + yyyy;
        return today;
    }
    $('input').on('focusout', function () {
        $('#now').fadeOut();
    });   
});

You should use a class rather than id for the now element, because IDs have to be unique. Then you can use DOM traversal methods to find the related input element.

 $(document).ready(function() { $(".im_whiteboard [id*=Next_Update]").on('focusin', function() { var div = $(this).closest("tr").find('.now'); var top = $(this).offset().top + $('input').height() + 5; var left = $(this).offset().left; $(div).css('top', top); $(div).css('left', left); $(div).fadeIn(); }); $('input').on('focusout', function() { $('.now').fadeOut(); }); $('.now').on('click', function() { var today = new Date(); var dd = today.getDate(); var mm = today.getMonth() + 1; //January is 0! var yyyy = today.getFullYear(); if (dd < 10) { dd = '0' + dd } if (mm < 10) { mm = '0' + mm } today = mm + '/' + dd + '/' + yyyy; $(this).closest("tr").find('input').val(today); }); }); 
 .now { top: 0; left: 0; display: none; position: absolute; background: #eee; color: tomato; border-radius: 2px; padding: 10px 20px; } .now:hover { cursor: pointer; background: #ccc; } 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <table class="im_whiteboard"> <tr> <td id="customEdit2_1_Next_Update_1c"> <input id="customEditInput_1_Next_Update_1" type='text' /> <div class='now'>Today</div> </td> </tr> <tr> <td id="customEdit2_1_Next_Update_2"> <input id="customEditInput_1_Next_Update_2" type='text' /> <div class='now'>Today</div> </td> </tr> <tr> <td id="customEdit2_1_Next_Update_3"> <input id="customEditInput_1_Next_Update_3" type='text' /> <div class='now'>Today</div> </td> </tr> </table> 

$(something) - in JQuery always presents collection of all elements suitable for that something, which is called selector. In your case $('input') - presents all the inputs and method .val(val) get applied to all of them, you can reduce collections by some methods like .eq(index) or .first() or .last() etc. for ex: `$('input').eq(0).val('val')

But better to be more precise there are css selectors very usable and also bunch of special JQuery selectors.

$(document).ready(function() {
    var input;
    $(".im_whiteboard [id*=Next_Update]").on('focusin', function() {
        var div = $('#now');
        var top = $(this).offset().top + $('input').height() + 5;
        var left = $(this).offset().left;
        input = $(this).find('input');
        $(div).css('top', top);
        $(div).css('left', left);
        $(div).fadeIn();
    });
    $('input').on('focusout', function() {
        $('#now').fadeOut();
    });
    $('#now').on('click', function() {
        var today = new Date();
        var dd = today.getDate();
        var mm = today.getMonth()+1; //January is 0!
        var yyyy = today.getFullYear();

        if(dd<10) {
            dd='0'+dd
        } 

        if(mm<10) {
            mm='0'+mm
        } 

        today = mm+'/'+dd+'/'+yyyy;
        console.log(input);
        input.val(today); 
    });
});

in focusin handler replace $('input') by $(this) - represents element trigered event and keep input contained there in global scope (or any storage you prefer) then in onclick handler assign value to that stored element

I rewrote a bunch of it to get rid of your multiple Ids and streamlined your code a bit. https://jsfiddle.net/s68zhLxn/32/

$(document).ready(function() {
    $(".im_whiteboard [id*=Next_Update]").on('focusin', function() {
        var self = $(this);
        var div = self.siblings('.now');
        var top = self.offset().top + self.height() + 5;
        var left = self.offset().left;
        div.css('top', top);
        div.css('left', left);
        div.fadeIn();
    });
    $('input').on('focusout', function() {
        $('.now').fadeOut();
    });
    $('.now').on('click', function() {
        var today = new Date();
        var dd = today.getDate();
        var mm = today.getMonth()+1; //January is 0!
        var yyyy = today.getFullYear();

        if(dd<10) {
            dd='0'+dd
        } 

        if(mm<10) {
            mm='0'+mm
        } 

        today = mm+'/'+dd+'/'+yyyy;
       $(this).siblings('input').val(today); 
    });
});

I'm a fan of applying classes: JsFiddle .

Update this part:

$('input').on('focusout', function() {
    $('.js-input-last-focused').removeClass('js-input-last-focused');
    $(this).addClass('js-input-last-focused');
    $('#now').fadeOut();
});

and instead of

$('input').val(today); 

use:

$('.js-input-last-focused').val(today); 

Yeah, the problem comes from the way you call div/input element, it show call $(this) scope, not all input or div element. You can keep #now id with my trick also. No need to change it to .now, but for good practice, you should

$(document).ready(function() {
$(".im_whiteboard [id*=Next_Update]").on('focusin', function() {
    var div = $('#now'), $this = $(this);
    var top = $this.offset().top + $('input').height() + 5;
    var left = $this.offset().left;
    $this.next().css({'top':top, 'left': left});
    $this.next().fadeIn();
});
$('input').on('focusout', function() {
    $(this).parent().find('#now').fadeOut();
});
$(document).on('click','#now', function() {
    var today = new Date();
    var dd = today.getDate();
    var mm = today.getMonth()+1; //January is 0!
    var yyyy = today.getFullYear();

    if(dd<10) {
        dd='0'+dd
    } 

    if(mm<10) {
        mm='0'+mm
    } 

    today = mm+'/'+dd+'/'+yyyy;
   $(this).parent().find('input').val(today); 
  });
});

$('input') will select all inputs on the page. To select only the input just before your 'now' div, change this:

$('input').val(today);

to this:

$(this).prev('input').val(today); 

Edit. This will actually only work on the first input, because the focusin handler is always selecting the first Today div (and as other answers have noted, those Today divs should really be class="now", as ids should be unique. This fiddle covers changes that will fix.

  • html: change all id="now" to class="now" ,
  • css: change the #now style selector to .now ,
  • js: change var div = $('#now'); to var div = $(this).next('.now'); in focusin handler, and $('input').val(today); to $(this).prev('input').val(today); as above.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM