input in bootstrap 4 popover can't be edited (loses focus)

41 views Asked by At

I am working with Bootstrap 4 and the Bootstrap colorpicker (https://itsjavi.com/bootstrap-colorpicker/) to create a colorpicker in a popup that contains a field in which the color code can be set. However, when the popover is opened, the input (#color-value) seems like it can't be edited. From debugging it's clear that it loses focus as soon as it gains focus (the 'focus' and 'focusout' below are logged right below each other. Research shows that it must have something to do with Bootstrap, but I can't seem to find a workaround. Has anyone got a solution/workaround?

I tried unbinding all the focus, focusout, blur, ... eventhandlers for the input, as well as any combination of preventdefault and stoppropagation for the eventlisteners, but all without success

Here's the relevant code

HTML:

<div class="tag col-md-4" data-tag-id="1">
    <div class="form-group input-group colorpicker-container">
        <input name="section-1-tag-1" type="text" class="form-control language-field" placeholder="Tag">
        <div class="input-group-append"><input name="section-1-tag-1-border-color" type="text" class="form-control language-field border-color no-auto-show colorpicker-element" ><a class="btn btn-icon btn-sm btn-show-colorpicker"><i class="far fa-droplet"></i></a><a class="btn btn-small btn-round btn-icon btn-danger btn-delete-tag" data-button-initiated="true"><i class="now-ui-icons ui-1_simple-remove"></i></a><a class="btn btn-icon btn-sm btn-reset-color"><i class="far fa-refresh"></i></a></div>
    </div>
</div>

JS:

var color = false;
if($('.border-color').val()) {
    color = $('.border-color').val();
}
$('.border-color').colorpicker(
    {
        //container: true, // tried turning this off and on, no success
        useAlpha: true,
        format: "rgba",
        popover: {
            placement: 'top'
        },
        color: color,
        template:
          '<div class="colorpicker">' +
          '<div class="colorpicker-saturation"><i class="colorpicker-guide"></i></div>' +
          '<div class="colorpicker-hue"><i class="colorpicker-guide"></i></div>' +
          '<div class="colorpicker-alpha">' +
          '   <div class="colorpicker-alpha-color"></div>' +
          '   <i class="colorpicker-guide"></i>' +
          "</div>" +
          '<div class="colorpicker-bar has-input">' +
          '   <div class="input-group">' +
          '       <input type="text" id="color-value" class="form-control input-block color-io" />' +
          "   </div>" +
          "</div>" +
          "</div>"
      }
).on("colorpickerShow", function (e) {
    console.log('colorpickerShow');
    var element = e.colorpicker.element;
    var io = $('#' + element.attr('aria-describedby') + ' #color-value');
    var defaultColor = e.color.string();
    if(element.val()) {
        e.colorpicker.setValue(element.val());
        $(element).siblings(".btn-show-colorpicker").find("i").css("color", element.val());
        $(element).siblings(".btn-reset-color").show();
        io.val(element.val());
    } else {
        $(element).siblings(".btn-reset-color").hide();
    }
    
    io.on('focus keydown mousedown active', function(e) {
        e.stopPropagation();
        e.preventDefault();
        console.log(e);
        console.log('focus');
    });
    io.on('focusout blur', function() {
        e.stopPropagation();
        //e.preventDefault();
        console.log(e);
        console.log('focusout');
    });
    element.on("change keyup", function () {
      e.colorpicker.setValue(element.val());
      $(element).siblings(".btn-reset-color").show();
    });
    io.on("change", function () {
        e.colorpicker.setValue(io.val());
        if($(this).val()) {
            e.colorpicker.setValue('');
            $(element).siblings(".btn-reset-color").hide();
        } else {
            e.colorpicker.setValue($(this).val());
            $(element).siblings(".btn-reset-color").show();
        }   
    });
})

What the popover's html actually looks like:

<div class="popover colorpicker-bs-popover fade show bs-popover-bottom" role="tooltip" id="popover467222" style="position: absolute; will-change: transform; top: 0px; left: 0px; transform: translate3d(268px, 159px, 0px);" x-placement="bottom">
  <div class="arrow" style="left: 84px;"></div>
  <h3 class="popover-header"></h3>
  <div class="popover-body">
    <div class="colorpicker colorpicker-with-alpha colorpicker-popup colorpicker-bs-popover-content colorpicker-visible">
      <div class="colorpicker-saturation" style="background-color: rgb(255, 0, 0);"><i class="colorpicker-guide" style="top: 42px; left: 35px;"></i></div>
      <div class="colorpicker-hue"><i class="colorpicker-guide" style="top: 126px;"></i></div>
      <div class="colorpicker-alpha">
        <div class="colorpicker-alpha-color" style="background: linear-gradient(rgb(170, 123, 123) 0%, transparent 100%);"></div>
        <i class="colorpicker-guide" style="top: 0px;"></i></div>
      <div class="colorpicker-bar has-input">
        <div class="input-group">
          <input type="text" id="color-value" class="form-control input-block color-io">
        </div>
      </div>
      <div class="colorpicker-bar colorpicker-preview">
        <div style="background-color: rgb(170, 123, 123); color: black;">rgb(170, 123, 123)</div>
      </div>
    </div>
  </div>
</div>

BELOW YOU CAN FINDE A WORKING SNIPPET

$(document).ready(function() {
  var color = false;
  if($('.border-color').val()) {
      color = $('.border-color').val();
  }
  $('.border-color').colorpicker(
      {
          //container: true, // tried turning this off and on, no success
          useAlpha: true,
          format: "rgba",
          popover: {
              placement: 'top'
          },
          color: color,
          template:
            '<div class="colorpicker">' +
            '<div class="colorpicker-saturation"><i class="colorpicker-guide"></i></div>' +
            '<div class="colorpicker-hue"><i class="colorpicker-guide"></i></div>' +
            '<div class="colorpicker-alpha">' +
            '   <div class="colorpicker-alpha-color"></div>' +
            '   <i class="colorpicker-guide"></i>' +
            "</div>" +
            '<div class="colorpicker-bar has-input">' +
            '   <div class="input-group">' +
            '       <input type="text" id="color-value" class="form-control input-block color-io" />' +
            "   </div>" +
            "</div>" +
            "</div>"
        }
  ).on("colorpickerShow", function (e) {
      console.log('colorpickerShow');
      var element = e.colorpicker.element;
      var io = $('#' + element.attr('aria-describedby') + ' #color-value');
      var defaultColor = e.color.string();
      if(element.val()) {
          e.colorpicker.setValue(element.val());
          $(element).siblings(".btn-show-colorpicker").find("i").css("color", element.val());
          $(element).siblings(".btn-reset-color").show();
          io.val(element.val());
      } else {
          $(element).siblings(".btn-reset-color").hide();
      }

      io.on('focus keydown mousedown active', function(e) {
          e.stopPropagation();
          e.preventDefault();
          console.log(e);
          console.log('focus');
      });
      io.on('focusout blur', function() {
          e.stopPropagation();
          //e.preventDefault();
          console.log(e);
          console.log('focusout');
      });
      element.on("change keyup", function () {
        e.colorpicker.setValue(element.val());
        $(element).siblings(".btn-reset-color").show();
      });
      io.on("change", function () {
          e.colorpicker.setValue(io.val());
          if($(this).val()) {
              e.colorpicker.setValue('');
              $(element).siblings(".btn-reset-color").hide();
          } else {
              e.colorpicker.setValue($(this).val());
              $(element).siblings(".btn-reset-color").show();
          }   
      });
  });
});
body {
  padding: 50px;
  min-height: 500px;
 }
 .colorpicker-container .input-group-append .colorpicker-element {
  position: absolute;
  left: 0;
  top: 0;
  right: auto;
  bottom: 0;
  width: 30px;
  height: 100%;
  opacity: 0;
  z-index: 3;
  cursor: pointer;
  padding: 0;
}
<!doctype html>
<html>
<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
  <script src="https://youreka-virtualtours.be/dashboard/assets/js/core/popper.min.js"></script>
  <script src="https://youreka-virtualtours.be/dashboard/assets/js/core/bootstrap.min.js"></script>
  <script src="https://youreka-virtualtours.be/dashboard/assets/js/plugins/jquery.bootstrap-wizard.js"></script>
  <script src="https://youreka-virtualtours.be/dashboard/assets/js/now-ui-dashboard.js"></script>
  <link href="https://youreka-virtualtours.be/dashboard/assets/css/now-ui-dashboard.css" rel="stylesheet"/>
  <link href="https://youreka-virtualtours.be/dashboard/assets/css/bootstrap.min.css" rel="stylesheet"/>
  <link href="https://youreka-virtualtours.be/libraries/bootstrap-colorpicker/dist/css/bootstrap-colorpicker.css" rel="stylesheet"/>
  <script src="https://youreka-virtualtours.be/libraries/bootstrap-colorpicker/dist/js/bootstrap-colorpicker.js"></script>
  <script src="https://kit.fontawesome.com/eecbfb86a5.js" crossorigin="anonymous"></script>
  <meta charset="utf-8">
  <title>test</title>
</head>

<body>
  <div class="tag col-md-4" data-tag-id="1">
    <div class="form-group input-group colorpicker-container">
        <input name="section-1-tag-1" type="text" class="form-control language-field" placeholder="Tag">
        <div class="input-group-append"><input name="section-1-tag-1-border-color" type="text" class="form-control language-field border-color no-auto-show" ><a class="btn btn-icon btn-sm btn-show-colorpicker"><i class="far fa-droplet"></i></a><a class="btn btn-small btn-round btn-icon btn-danger btn-delete-tag" data-button-initiated="true"><i class="now-ui-icons ui-1_simple-remove"></i></a><a class="btn btn-icon btn-sm btn-reset-color"><i class="far fa-refresh"></i></a></div>
    </div>
  </div>
</body>
</html>

1

There are 1 answers

0
Mark Schultheiss On

This is pretty ugly but I think you can use it as a starting point. I put the template in a template element. I then added a second input group and put a color attribute on each. This is where, when the button is clicked those yellow and blue come from - but shows you how to find them and do that.

I also added a target element so you can see how to apply the colors to another element as border and background - just for an example.

Not super clean but something to build from perhaps.

$(function() {
  const pageBody = document.querySelector("body");
  const template = pageBody.querySelector("#colorpickertemplate");
  // Clone the new template and insert it into the body
  const clone = template.content.cloneNode(true);
  pageBody.appendChild(clone);
  const pickerElement = pageBody.querySelector('.colorpicker');
  const colorValue = pickerElement.querySelector('#color-value');
  const tag = $('.tag-input');
  const borderP = $('.border-color');
  const backgroundP = $('.background-color');
  //commented out since this element is a DIV which has no "value" or .val()
  // if ($('.border-color').val()) {
  //   color = $('.border-color').val();
  // }

  tag
    //   .on('focus keydown mousedown active', function(event) {
    //console.log(event.type);
    //  })
    // .on('focusout blur', function(event) {
    //  console.log('focusout or blur:', event.type);
    // })
    .on("change", function(event) {
      // event.colorpicker.setValue($(colorValue).val());
      console.log('change:', this.value);
      if ($(this).val()) {
        //event.colorpicker.setValue('');
        // $(this).siblings(".btn-reset-color").hide();
      } else {
        // event.colorpicker.setValue($(this).val());
        //  $(this).siblings(".btn-reset-color").show();
      }
    });

  borderP.add(backgroundP)
    .colorpicker({
      useAlpha: true,
      format: "rgba",
      popover: {
        placement: 'top'
      },
      fallbackColor: 'rgb(48, 90, 162)'
    }).on("colorpickerCreate", function(e) {
      const element = e.colorpicker.element;
      const parent = $(element).closest('.colorpicker-container');
      console.log('colorpickerCreate');
      // const io = $(colorValue); // $('#' + element.attr('aria-describedby') + ' #color-value');

    }).on("colorpickerShow", function(event) {
      const element = event.colorpicker.element;
      const parent = $(this).closest('.colorpicker-container')
      if (element.val()) {
        event.colorpicker.setValue(element.val());
        parent.find(".btn-show-colorpicker").find("i").css("color", element.val());
        parent.find(".btn-reset-color").show();
      } else {
        parent.find(".btn-reset-color").hide();
      }
    }).on('colorpickerChange', function(event) {
      const element = event.colorpicker.element;
      event.colorpicker.hide();
      const tag = $(".tag-input").val();
      if ($(this).hasClass('border-color')) {
        $(tag).css('border-color', event.color.toString());
      }
      if ($(this).hasClass('background-color')) {
        $(tag).css('background-color', event.color.toString());
      }
    });
});
  body {
  padding: 50px;
  min-height: 500px;
}

.colorpicker-container .input-group-append .colorpicker-element {
  /*  position: absolute;
  left: 0;
  top: 0;
  right: auto;
  bottom: 0;*/
  width: 30px;
  height: 100%;
  opacity: 0;
  z-index: 3;
  cursor: pointer;
  padding: 0;
}

.i-am-the-target {
  border: solid 2px #00000000;
  )
<!doctype html>
<html>

<head>
  <meta charset="utf-8">
  <title>test</title>
  <link href="https://youreka-virtualtours.be/dashboard/assets/css/now-ui-dashboard.css" rel="stylesheet" />
  <link href="https://youreka-virtualtours.be/dashboard/assets/css/bootstrap.min.css" rel="stylesheet" />
  <link href="https://youreka-virtualtours.be/libraries/bootstrap-colorpicker/dist/css/bootstrap-colorpicker.css" rel="stylesheet" />

  <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.2/jquery.min.js"></script>
  <script src="https://youreka-virtualtours.be/dashboard/assets/js/core/popper.min.js"></script>
  <script src="https://youreka-virtualtours.be/dashboard/assets/js/core/bootstrap.min.js"></script>
  <script src="https://youreka-virtualtours.be/dashboard/assets/js/plugins/jquery.bootstrap-wizard.js"></script>
  <script src="https://youreka-virtualtours.be/dashboard/assets/js/now-ui-dashboard.js"></script>
  <script src="https://youreka-virtualtours.be/libraries/bootstrap-colorpicker/dist/js/bootstrap-colorpicker.js"></script>
  <script src="https://kit.fontawesome.com/eecbfb86a5.js" crossorigin="anonymous"></script>
</head>

<body>
  <div class="tag col-md-4" data-tag-id="1">
    <div class="form-group input-group colorpicker-container">
      <input name="section-1-tag-1" type="text" value=".i-am-the-target" class="form-control language-field tag-input" placeholder="Tag">
      <div class="input-group-append"><input name="section-1-tag-1-border-color" type="text" class="form-control language-field background-color  no-auto-show" data-color="#ffff0040"><a class="btn btn-icon btn-sm btn-show-colorpicker"><i class="far fa-droplet"></i></a><a class="btn btn-small btn-round btn-icon btn-danger btn-delete-tag"
          data-button-initiated="true"><i class="now-ui-icons ui-1_simple-remove"></i></a><a class="btn btn-icon btn-sm btn-reset-color"><i class="far fa-refresh"></i></a></div>
    </div>
  </div>
  <div class="tag col-md-2" data-tag-id="2">
    <div class="form-group input-group colorpicker-container">
      <input name="section-2-tag-2" type="text" value="" class="form-control language-field color-input" placeholder="Color">
      <div class="input-group-append"><input name="section-2-tag-2-border-color" type="text" class="form-control language-field border-color no-auto-show" data-color="#0000ff"><a class="btn btn-icon btn-sm btn-show-colorpicker"><i class="far fa-droplet"></i></a><a class="btn btn-small btn-round btn-icon btn-danger btn-delete-tag"
          data-button-initiated="true"><i class="now-ui-icons ui-1_simple-remove"></i></a><a class="btn btn-icon btn-sm btn-reset-color"><i class="far fa-refresh"></i></a></div>
    </div>
  </div>
  <div class="i-am-the-target">Hi, I am me</div>
  <template id="colorpickertemplate">
    <div class="colorpicker">
      <div class="colorpicker-saturation"><i class="colorpicker-guide"></i></div>
     <div class="colorpicker-hue"><i class="colorpicker-guide"></i></div>
     <div class="colorpicker-alpha">
        <div class="colorpicker-alpha-color"></div>
        <i class="colorpicker-guide"></i>
      </div>
     <div class="colorpicker-bar has-input">
        <div class="input-group">
            <input type="text" id="color-value" class="form-control input-block color-io"  />
         </div>
        </div>
    </div>
 </template>
</body>

</html>