Sercan Aslan
Sercan Aslan

Reputation: 273

Collecting input data and showing it in div

I have some quantity inputs. I want to collect the data in "inputs" and show them in "#yolcudropdown". But I just can't pull the data. Inputs must be disabled. There should be no manual entry. I did something at the bottom of the "javascript" section. But I couldn't run it.

(function( $ ) {
    $.fn.number = function(customOptions) {
        var options = {
            'containerClass' : 'number-style',
            'minus' : 'number-minus',
            'plus' : 'number-plus',
            'containerTag' : 'div',
            'btnTag' : 'span'
        };
        options = $.extend(true, options, customOptions);
        var input = this;
        input.wrap('<' + options.containerTag + ' class="' + options.containerClass + '">');
        var wrapper = input.parent();
        wrapper.prepend('<' + options.btnTag + ' class="' + options.minus + '"></' + options.btnTag + '>');
        var minus = wrapper.find('.' + options.minus);
        wrapper.append('<' + options.btnTag + ' class="' + options.plus + '"></' + options.btnTag + '>');
        var plus = wrapper.find('.' + options.plus);
        var min = input.attr('min');
        var max = input.attr('max');
        if(input.attr('step')){
            var step = +input.attr('step');
        } else {
            var step = 1;
        }
        if(+input.val() <= +min){
            minus.addClass('disabled');
        }
        if(+input.val() >= +max){
            plus.addClass('disabled');
        }
        minus.click(function () {
            var input = $(this).parent().find('input');
            var value = input.val();
            if(+value > +min){
                input.val(+value - step);
                if(+input.val() === +min){
                    input.prev('.' + options.minus).addClass('disabled');
                }
                if(input.next('.' + options.plus).hasClass('disabled')){
                    input.next('.' + options.plus).removeClass('disabled')
                }
            } else if(!min){
                input.val(+value - step);
            }
        });
        plus.click(function () {
            var input = $(this).parent().find('input');
            var value = input.val();
            if(+value < +max){
                input.val(+value + step);
                if(+input.val() === +max){
                    input.next('.' + options.plus).addClass('disabled');
                }
                if(input.prev('.' + options.minus).hasClass('disabled')){
                    input.prev('.' + options.minus).removeClass('disabled')
                }
            } else if(!max){
                input.val(+value + step);
            }
        });
    };
})(jQuery);

$('.quntity-input').each(function () {
  $(this).number();
});




/* THIS IS IMPORTANT */
$(document).ready(function() {
  $(document).on('change', '.btw', function() {
    $('#yolcudropdown').text($(this).val());
  });
});
.number-style {
  display: -ms-flexbox;
  display: flex;
  -ms-flex-wrap: wrap;
  flex-wrap: wrap;
  -ms-flex-pack: start !important;
  justify-content: flex-start !important;
  -ms-flex-align: center !important;
  align-items: center !important;
}
.number-style .number-minus,
.number-style .number-plus {
  height: 28px;
  background: #ffffff;
  border: 2px solid #e2e2e2 !important;
  width: 28px;
  -webkit-border-radius: 100%;
  -moz-border-radius: 100%;
  -ms-border-radius: 100%;
  border-radius: 100%;
  line-height: 23px;
  font-size: 19px;
  font-weight: 700;
  text-align: Center;
  border: none;
  display: block;
  cursor: pointer;
}
.number-style .number-minus:active,
.number-style .number-plus:active {
  background: #e2e2e2;
}
.number-style .number-minus {
  line-height: 20px;
}
.number-style .number-minus::after {
  content: "-";
  font-size: 10px;
}
.number-style .number-plus {
  line-height: 18px;
}
.number-style .number-plus::after {
  content: "+";
  font-size: 10px;
}
.number-style .quntity-input {
  width: 28px;
  background: #e00f23;
  -webkit-border-radius: 100%;
  -moz-border-radius: 100%;
  -ms-border-radius: 100%;
  border-radius: 100%;
  line-height: 21px;
  font-size: 14px;
  color: #ffffff;
  font-weight: 700;
  text-align: Center;
  margin: 0 5px;
  display: block;
  cursor: pointer;
  text-align: center;
  border: none;
  height: 28px;
  font-weight: 600;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input class="quntity-input btw" type="text" value="0" step="1" min="0" max="10">
<input class="quntity-input btw" type="text" value="0" step="1" min="0" max="10">

<div id="yolcudropdown">İnput quantity show this div</div>

"class" names of "input" elements are the same. I need to collect inputs with the same value and display them in the div instantly

Upvotes: 2

Views: 331

Answers (1)

Roko C. Buljan
Roko C. Buljan

Reputation: 206121

HTMLInputElement

Input type "text" has no min max or step attributes, so your HTML is absolutely invalid. Try not to write It-works, I'm a framework -code. Respect the W3C standards. Use type="number" (CSS pseudos can help you remove default spinner arrows from such elements)

Also step could be floats. Respect that and use parseFloat() in JS

CSS Flex to align stuff

Seems you know about CSS-flex, use it! Height, therefore- line-height... 19? 20? 23px? No. Just use flex.

CSS !important

!important is sign of poor coding style and should be left to Bootstrap only. Or to hopefully override Bootstrap styles - or in that cases when developers actually know what they are doing.

jQuery Plugins

jQuery plugins, I suggest to read the DOCS and get a deeper knowledge on how plugins work. Almost every jQuery method is a plugin. .hide() , .addClass()... I won't count them all. Plugins are chainable .removeClass("foo").stop().fadeTo(1), and so should be your .number() plugin.
To achieve chain-ability you simply return the bound this. PS: that's not jQuery... that's how JS works.

jQuery Plugins are not meant to be called inside a $.each() loop. $() is already a collection of DOM Nodes wrapped in a jQuery Object. No need to .each(). Same like: you would rather use $('a').css({color:'blue'}) instead of $('a').each(){ $(this).css({color: 'blue'}); });. Same effect, less code. Plugins.

jQuery DOM ready

jQuery(function($) { }); // DOM ready and $ alias in scope

Or if you don't care about ±IE, or you use ES6 syntax and a toolchain like Babel than: jQuery($ => { }) will suffice.

jQuery $ Object Constructor

jQuery allows you to define an HTMLElement that will eventually become a new DOM element wrapped with all the jQuery powers, Methods. Meaning that, if instead of passing a selector, you pass a more complex Tag-alike string (say: $("<span/>", {}); - jQuery will create an inMemory SPAN element and allow you to use the second parameter {} for most of the available jQuery Methods for that $Element. Let's use this!

jQuery plugin callbacks

If you want to provide a callback after a user changes the input value, provide a callback method. Don't force a programmer to write new spaghetti code, stick to the scope of your available Plugin internal Methods.

Sum Elements values

To sum Elements values you can use Array.prototype.reduce, just make sure to use an initialValue to prevent possible TypeErrors.


Example

Finally, here's the simplified CSS and improved JS:

(function($) {
  $.fn.number = function(customOptions) {

    const options = $.extend(true, {
      containerTag: "div",
      containerClass: "number-style",
      minusClass: "number-minus", // consistency in wording!
      minusText: "-", // Give power to the user!
      plusClass: "number-plus",
      plusText: "+",
      btnTag: "button",
      onChange() {}, // Provide a nifty callback!
    }, customOptions);

    this.each(function() { // Use .each() here!

      const $input = $(this);
      let val = parseFloat($input.value || 0); // floats! 
      const min = parseFloat($input.attr("min"));
      const max = parseFloat($input.attr("max"));
      const step = parseFloat($input.is("[step]") ? $input.attr("step") : 1);

      const handleStyles = () => {
        $minus.toggleClass('disabled', val <= min);
        $plus.toggleClass('disabled', val >= max);
      };
      
      const change = () => {
        val = Math.max(min, Math.min(max, val)); // Keep val in range.
        $input.val(val); // Update input value
        handleStyles();  // Update styles
        options.onChange.call($input[0], val); // Trigger a public callback
      }

      const decrement = () => {
        val -= step;
        change();
      };

      const increment = () => {
        val += step;
        change();
      };

      const $minus = $(`<${options.btnTag}>`, {
        type: "button",
        title: "Decrement",
        class: options.minusClass,
        text: options.minusText,
        on: {
          click: decrement
        }
      });

      const $plus = $(`<${options.btnTag}>`, {
        class: options.plusClass,
        title: "Increment",
        text: options.plusText,
        on: {
          click: increment
        }
      });

      const $wrapper = $(`<${options.containerTag}>`, {
        class: options.containerClass,
      });

      $input.after($wrapper);
      $wrapper.append($minus, $input.detach(), $plus); // Append all
      handleStyles(); // handle initial styles

    });

    return this; // make your plugin chainable!

  };
})(jQuery);



jQuery(function($) { // DOM ready and $ alias in scope

  const $quantityInp = $('.quantity-input'); // Cache your elements!
  const $dropdown = $('#yolcudropdown'); // Cache your elements!

  $quantityInp.number({
    onChange(val) { // our custom onChange callback!
      const tot = $quantityInp.get().reduce((acc, el) => {
        acc += parseFloat(el.value);
        return acc;
      }, 0);
      $dropdown.text(tot);
    }
  });

});
/* QuickReset */ * { margin:0; box-sizing:border-box; }

.number-style input::-webkit-outer-spin-button,
.number-style input::-webkit-inner-spin-button {
  -webkit-appearance: none;
}

.number-style {
  display: flex;
}

.number-style > * {
  height: 2em;
  min-width: 2em;
  border-radius: 2em;
  display: flex;            /* Use flex. */
  justify-content: center;
  text-align: center;
  border: 0;
  background: #ddd;
}

.number-style button {
  background: #fff;
  box-shadow: inset 0 0 0 2px #ccc;
  cursor: pointer;
  user-select: none;
  /* no highlight, please! */
}

.number-style button:active {
  background: #0bf;
}

.number-style input {
  background: #e00f23;
  color: #fff;
  margin: 0 5px;
}

.number-style .disabled {
  opacity: 0.2;
  cursor: default;
}


/* Custom overrides: */

.number-style>* {
  width: 2em;
  /* just for roundness */
}
<input class="quantity-input" type="number" value="0" step="1" min="0" max="10">
<input class="quantity-input" type="number" value="0" step="1" min="0" max="10">

<div id="yolcudropdown">0</div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

Additional reading:

And PS: it's "quantity", not "quntity"

Upvotes: 3

Related Questions