block14
block14

Reputation: 619

Change input type based on value

I am looking to change the input type of a number selector to a dropdown if the value is less than 10. For values greater than 9 (10+) the input type should change back to a number selector.

Amazon and Sears.com are doing this style of quantity selectors in their shopping carts for some desktop users (subject to AB testing).

If 10+ is selected, you can type a number.

My issue is that it will change input type once, but not back again.

Additionally what is the best practice to retain the value between input types? I've considered either using a variable or copying to a hidden input which is the actual field submitted.

HTML:

<label class="mylabel">Quantity:</label> <input style="display: inline;" maxlength="3" min="1" pattern="\d+" autocomplete="off" name="quantityBox" class="qty-input" aria-label="Quantity" type="number"> <input type="submit" name="btnAddToCart" value="Add To Cart" id="btnAddToCart" class="">

jQuery:

$(".qty-input").change(function(){
     if (parseInt(this.value) < 10){
        $(".qty-input").replaceWith(
          '<select id="txtQuantity" name="txtQuantity" class="qty-input">' +
          '<option value="1">1</option>' +
          '<option value="2">2</option>' +
          '<option value="3">3</option>' +
          '<option value="4">4</option>' +
          '<option value="5">5</option>' +
          '<option value="6">6</option>' +
          '<option value="7">7</option>' +
          '<option value="8">8</option>' +
          '<option value="9">9</option>' +
          '<option value="10">10+</option>' +
          '</select>'
        );
     } 
     if (parseInt(this.value) > 9){
        $(".qty-input").replaceWith(
          '<input style="display: inline;" maxlength="3" min="1" pattern="\d+" autocomplete="off" name="quantityBox" class="qty-input" aria-label="Quantity" type="number">'
        );
     }
});

Upvotes: 1

Views: 1648

Answers (6)

Tamaghna Banerjee
Tamaghna Banerjee

Reputation: 168

check this out what I am telling Fiddle Demo

$(".select").on('click',function(){
if(isNaN($(this).val())){
    $(this).addClass("hide");
  $(".more").removeClass("hide");
  $(this).removeAttr("name","quantity");
  $(".more").attr("name","quantity");
} });

You may refine code to your purpose.

Upvotes: 0

10100111001
10100111001

Reputation: 1832

This will work. Your example doesn't work since when you replace the DOM node/element, it no longer has the change event handled so function is bonded nor executed.

$(".qty-input").change(updateControl);

function updateControl(evt) {
  var template;
  if (parseInt(this.value) < 10 && this.tagName.toLowerCase() === "input") {
    template =
      '<select id="txtQuantity" name="txtQuantity" class="qty-input">' +
      '<option value="1">1</option>' +
      '<option value="2">2</option>' +
      '<option value="3">3</option>' +
      '<option value="4">4</option>' +
      '<option value="5">5</option>' +
      '<option value="6">6</option>' +
      '<option value="7">7</option>' +
      '<option value="8">8</option>' +
      '<option value="9">9</option>' +
      '<option value="10">10+</option>' +
      '</select>';
  } else if (parseInt(this.value) > 9 && this.tagName.toLowerCase() === "select") {
    template =
      '<input style="display: inline;" maxlength="3" min="1" pattern="\d+" autocomplete="off" name="quantityBox" class="qty-input" aria-label="Quantity" type="number" value="'+this.value+'">';
  }

  if (template) {
    $(this).replaceWith(template);
    $('.qty-input option[value='+this.value+']').attr('selected', true);
    $('.qty-input').change(updateControl);
  }

}
<script src="https://code.jquery.com/jquery-3.1.0.min.js"></script>

<select id="txtQuantity" name="txtQuantity" class="qty-input">
  <option value="1">1</option>
  <option value="2">2</option>
  <option value="3">3</option>
  <option value="4">4</option>
  <option value="5">5</option>
  <option value="6">6</option>
  <option value="7">7</option>
  <option value="8">8</option>
  <option value="9">9</option>
  <option value="10">10+</option>
</select>

Upvotes: 0

happymacarts
happymacarts

Reputation: 2604

The problem is this...

once you remove the object from the DOM you are also removing the event handler if you still want to take the replace approach you would have to re-bind the event handler something like

    $(document).ready(function() {
   function test(){
     if (parseInt(this.value) < 10) {
       $(".container ").html(
         '<select id="txtQuantity" name="txtQuantity" class="qty-input">' +
         '<option value="1">1</option>' +
         '<option value="2">2</option>' +
         '<option value="3">3</option>' +
         '<option value="4">4</option>' +
         '<option value="5">5</option>' +
         '<option value="6">6</option>' +
         '<option value="7">7</option>' +
         '<option value="8">8</option>' +
         '<option value="9">9</option>' +
         '<option value="10">10+</option>' +
         '</select>'
       );
     } else {
       $(".container").html(
         '<input style="display: inline;" maxlength="3" min="1" pattern="\d+" autocomplete="off" name="quantityBox" class="qty-input" aria-label="Quantity" type="number">'
       );
     }
      $(".qty-input").on('change', test);
   }
   $(".qty-input").on('change', test);
 });

https://jsfiddle.net/happymacarts/pn1qeyg9/1/

Upvotes: 0

Isabel Inc
Isabel Inc

Reputation: 1899

Although there are better ways of doing this I'm posting this to answer why your version is not working. Basically you're binding to an element that doesn't exist yet i.e. dynamic content.

Jquery handles this using the on method.

You can get it to work by adding a static ancestor and binding to that instead. For a better understanding of how event bubbling and delegation works check out this link. http://api.jquery.com/on/

Something like this

HTML

<label class="mylabel">Quantity:</label>
<div id="staticAncestor">
<input style="display: inline;" maxlength="3" min="1" pattern="\d+" autocomplete="off" name="quantityBox" class="qty-input" aria-label="Quantity" type="number">
</div>

JS

$("#staticAncestor").on("change",'.qty-input',function(){
  if (parseInt(this.value) < 10 && !$( "#txtQuantity" ).length){

        $(".qty-input").replaceWith(
          '<select id="txtQuantity" name="txtQuantity" class="qty-input">' +
          '<option value="1">1</option>' +
          '<option value="2">2</option>' +
          '<option value="3">3</option>' +
          '<option value="4">4</option>' +
          '<option value="5">5</option>' +
          '<option value="6">6</option>' +
          '<option value="7">7</option>' +
          '<option value="8">8</option>' +
          '<option value="9">9</option>' +
          '<option value="10">10+</option>' +
          '</select>'
        );
     } 
     if (parseInt(this.value) > 9){
        $(".qty-input").replaceWith(
          '<input style="display: inline;" maxlength="3" min="1" pattern="\d+" autocomplete="off" name="quantityBox" class="qty-input" aria-label="Quantity" type="number">'
        );
     }
});

Here is the pen http://codepen.io/anon/pen/jAQogj

Cheers and happy coding!

Upvotes: 0

TimoStaudinger
TimoStaudinger

Reputation: 42520

There is no need to render and re-render the fields each time they should switch. It is easier to simply hide them.

A very basic solution, error handling and styling is up to you:

var high = $('#high')
var low = $('#low')

function onChange() {
  if (low.is(':visible')) {
    var value = low.val();
    high.val(value);
    if (parseInt(value) > 9) toggleInputs();
  } else {
    var value = high.val();
    low.val(value);
    if (parseInt(value) <= 9) toggleInputs();
  }
}

function toggleInputs() {
  $('#low').toggle();
  $('#high').toggle();
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

<label>Quantity:</label>
<input onchange='onChange()' id='high' style='display: none' />
<select onchange='onChange()' id='low'>
  <option value='0'>0</option>
  <option value='1'>1</option>
  <option value='2'>2</option>
  <option value='3'>3</option>
  <option value='4'>4</option>
  <option value='5'>5</option>
  <option value='6'>6</option>
  <option value='7'>7</option>
  <option value='8'>8</option>
  <option value='9'>9</option>
  <option value='10'>10+</option>
</select>

Upvotes: 1

Tamaghna Banerjee
Tamaghna Banerjee

Reputation: 168

You can do it with two particular different selectors one for dropdown other for text to take getter than ten.selecting 10+ will change the select control name and it will be point to your textbox name or if want to switch back then restore the old name of select box and remove text box name.

Using jquery toggle method and prop attribute you can handle or modify name prop of the controls you are using.I think you got it.

Your server side code can catch the post data easily with this logic.

If not getting, can ask for sample code i can show you.

Upvotes: 0

Related Questions