jQuery - two linked events that disable self and enable the other

Viewed 51

I need that once event1 triggers, it activates event2 and disable self, and vice versa. I'm having trouble with the last step, because when I focus out, the input only briefly disappears.

/**
 * Actions to be done once one of the div is clicked. 
 * It should hide the span, fade in the input, focus it, disable the self event and enable the input event.
 */
$('.range-wrapper').click(e => rangeClickEvent(e.target));

/**
 * Actions to be done once one of the input loses focus or the enter key is pressed. 
 * It should hide the input, fade in the span, reenable the click event on the wrapper and disable self.
 */
$('.range-wrapper input').on('focusout keyup', e => {
    if (e.type == 'keyup' && e.keyCode != 13) {
        return;
    }
    rangeFocusOutEvent(e.target);
    $('.range-wrapper input').off('focusout keyup');
});

function rangeClickEvent(rangeElement) {
    $(rangeElement).children('span').hide();
    $(rangeElement).children('input').fadeIn(300).focus();
    $(rangeElement).off('click').removeClass('clickable');
}

function rangeFocusOutEvent(inputElement) {
    const parentDiv = $(inputElement).parent();
    $(inputElement).hide();
    $(parentDiv).children('span').fadeIn(300);
    setClickEventBack(parentDiv);
}

function setClickEventBack(rangeElement) {
    $(rangeElement).addClass('clickable');
    //line below - re-adding the click event causes trouble
    $(rangeElement).on('click', rangeClickEvent(rangeElement));
}

Here's what I have so far: https://jsfiddle.net/1j7fby49/12/

So basically clicking on the div hides the span and shows the input. Once I'm done with the input (focusout or enter key), it should hide the input and show the span again.

How can I achieve that?

2 Answers

I believe that you're looking for sort of placeholder mechanizm. If so, allow me to simplify your code. As I see it, you don't need to on and off events. I used toggle to show / hide elements but you can also use fadeToggle.

/**
 * Actions to be done once one of the div is clicked. 
 * It should hide the span, fade in the input, focus it, disable the self event and enable the input event.
 */
const rangeElement = $('.range-wrapper');
const input = rangeElement.find('input');
const span = rangeElement.find('span');

function toggle() {
  input.toggle().focus();
  span.toggle();
}

rangeElement.on('click', toggle);

/**
 * Actions to be done once one of the input loses focus or the enter key is pressed. 
 * It should hide the input, fade in the span, reenable the click event on the wrapper and disable self.
 */
$('.range-wrapper input')
  .on('keyup', function(e) {
    e.stopPropagation();
    if (e.type == 'keyup' && e.keyCode === 13) {
      $(this).blur();
    }
  })
  .on('focusout', function() {
    toggle();
    span.text(input.val() || 'Some Value')
  });

/* function rangeClickEvent(rangeElement) {
    $(rangeElement).children('span').hide();
    $(rangeElement).children('input').fadeIn(300).focus();
    $(rangeElement).off('click').removeClass('clickable');
}

function rangeFocusOutEvent(inputElement) {
    const parentDiv = $(inputElement).parent();
    $(inputElement).hide();
    $(parentDiv).children('span').fadeIn(300);
    setClickEventBack(parentDiv);
}

function setClickEventBack(rangeElement) {
    $(rangeElement).addClass('clickable');
    //line below - re-adding the click event causes trouble
    $(rangeElement).on('click', rangeClickEvent(rangeElement));
} */
body {
  background: #20262E;
  padding: 20px;
  font-family: Helvetica;
  color: #eee;
}

.range-wrapper {
  display: flex;
  flex-direction: column;
  border: 1px solid white;
  border-radius: 5px;
  width: 10vw;
  min-width: 150px;
  height: 2rem;
}

.range-wrapper>label,
.range-wrapper>span {
  pointer-events: none;
}

.range-wrapper>label {
  text-align: left;
  font-size: x-small;
  font-weight: bold;
}

.range-wrapper>span {
  font-size: medium;
  font-weight: bold;
}

.clickable {
  cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="range-wrapper clickable">
  <label for="value">VALUE</label>
  <span>Some Value</span>
  <input type="text" name="value" id="value" hidden>
</div>

https://jsfiddle.net/moshfeu/19zde3my/17/

BTW, you can do almost all of it (except having the updated text in the span) using only css. Something like this: https://jsfiddle.net/moshfeu/6h12qcwz/18/

You call the function at the definition of the click handler rather than in its callback. Fix:

$(rangeElement).on('click', function() {rangeClickEvent(rangeElement)});
Related