1

I currently have an array that is populated by changing the value/option of many select fields. E.g. If two select fields are in the dom and the options selected are 2 & 3 then the array would look like this - Array [ "2", "3" ]

Each select has a data attribute data-ticketprice which I would like to bind to each of the option values. So I can get the sum of both of the numbers e.g.

data attribute = 100
Select option value = 5
Sum = 100 x 5;

HTML -

<select class="ticket-qty" data-ticketprice="280.88" name="34">
    <option value="0">0 Tickets</option>
    <option value="1">1 Ticket</option>
    <option value="2">2 Tickets</option>
    <option value="3">3 Tickets</option>
    <option value="4">4 Tickets</option>
    <option value="5">5 Tickets</option>
</select>

<select class="ticket-qty" data-ticketprice="390" name="39">
    <option value="0">0 Tickets</option>
    <option value="1">1 Ticket</option>
    <option value="2">2 Tickets</option>
    <option value="3">3 Tickets</option>
    <option value="4">4 Tickets</option>
    <option value="5">5 Tickets</option>
</select>

Current jQuery -

//When select is changed update value to array
$('select.ticket-qty').on('change', function (e) {
    //Map the values for the array
    var arr = $('select.ticket-qty').map(function(){
        return this.value
    }).get()

    //This sums the all the select options (not what I want)
    var total = 0;
    for (var i = 0; i < arr.length; i++) {
        total += arr[i] << 0;
    }
    console.log(total);
});
4
  • Please consider using an MVC framework for this type of project. Vue JS is easy to get started with if you haven't done so before. Commented Feb 21, 2018 at 16:29
  • 2
    You don't need a big framework for every little problem. Commented Feb 21, 2018 at 16:34
  • If this is a school project, probably not. If he is really selling tickets to something, this will outgrow jQuery within a day. Commented Feb 21, 2018 at 16:44
  • @AdamLeggett I'm already using an MVC framework such as Laravel. I don't like VueJS because you end up with around 100 libraries. It's never just vue, its axios, vue routing etc.. This is a really basic application with almost no JS requirements. Commented Feb 21, 2018 at 17:16

4 Answers 4

2

You need to fill the array you build with map() with the selected quantity multiplied by the cost per item, which you can retrieve from the data attribute. From there you can use reduce() to sum up all values in the array. Something like this:

$('select.ticket-qty').on('change', function(e) {
  var arr = $('select.ticket-qty').map(function() {
    var cost = $(this).data('ticketprice');
    var qty = $(this).val();
    return cost * qty;
  }).get();
  
  var total = arr.reduce((a, b) => a + b, 0);
  console.log(total);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select class="ticket-qty" data-ticketprice="280.88" name="34">
    <option value="0">0 Tickets</option>
    <option value="1">1 Ticket</option>
    <option value="2">2 Tickets</option>
    <option value="3">3 Tickets</option>
    <option value="4">4 Tickets</option>
    <option value="5">5 Tickets</option>
</select>

<select class="ticket-qty" data-ticketprice="390" name="39">
    <option value="0">0 Tickets</option>
    <option value="1">1 Ticket</option>
    <option value="2">2 Tickets</option>
    <option value="3">3 Tickets</option>
    <option value="4">4 Tickets</option>
    <option value="5">5 Tickets</option>
</select>

You should note that this can all be done in a single loop, however I am assuming you're building the array of individual totals for use elsewhere in your UI.

Sign up to request clarification or add additional context in comments.

9 Comments

He will need a polyfill for reduce if he wishes to support IE9.
Unfortunately so. We can dream of a world without IE and Edge... one day.
Edge isn't that bad.
It's better than IE admittedly, but it's still a long way from where it should be. It's standards compliance is rather lacking. It'll be the new IE6 in 3-4 years time.
@AdamLeggett: IE9 supports most of ECMAScript 5, including .reduce().
|
0

So how far I understand is, you want to multiply the selected value with the given data attribute on Select?

Here is sample code for getting Array of All selected values. And how to calculate the value you posted.

var array = [];
var i =0;
$('select.ticket-qty').on('change', function (e) {
    // Get value of all selects in array.
    $('select.ticket-qty').each(function(){
       array[i] = $(this).val();
       i++;
    });
    //calculate Sum ?
    var data_attribute = $(this).data("ticketprice");
    SelectedOptionValue = = $(this).val();
    Sum = parseFloat(data_attribute)* parseInt(SelectedOptionValue);
});

Comments

0

Vanilla JS

const SELECTS = document.querySelectorAll('select.ticket-qty')

const LOG_SUM = e => {
  const ticketPrice = e.target.getAttribute('data-ticketPrice')
  const multiplier = e.target.value
  const SUM = (+ticketPrice * +multiplier)
  
  console.log(SUM)
}

SELECTS.forEach(select => {
  select.addEventListener('change', e => {
    LOG_SUM(e)
  })
})

jQuery

$('select.ticket-qty').on('change', e => {
  const ticketPrice = $(e.target).attr('data-ticketPrice')
  const multiplier = e.target.value
  const SUM = (+ticketPrice * +multiplier)
  
  console.log(SUM)
});

Notice how i prepend the + operator to the ticketPrice & multiplier constants... this is because attr && value are returning Strings and the + operator converts numbers of type String into numbers of type Number

Comments

0

You can use some jQuery plugins to populate and reduce the select boxes.

(function($) {
  $.reduce = function(arr, fn, initial) {
    initial = typeof initial === 'undefined' ? 0 : initial;
    $.each(arr, function(i, v) {
      initial = fn(initial, v, i);
    });
    return initial;
  };
  $.fn.reduce = function(fn, initial) {
    return $.reduce(this, fn, initial);
  };
  $.fn.populateCombo = function(opts) {
    let data = opts.data || Array.apply(null, {length: opts.range || 0}).map(Number.call, Number);
    return this.append(data.map(x => $('<option>')
      .text(opts.textFn ? opts.textFn(x) : x)
      .val(opts.valFn ? opts.valFn(x) : x)));
  };
})(jQuery);

$('.ticket-qty').each((i, combo) => $(combo).populateCombo({
  range : 6, textFn: v => v + ' Tickets'
}));

$('select.ticket-qty').on('change', function(e) {
  var total = $('select.ticket-qty').reduce(function(result, item) {
    return result + $(item).data('ticketprice') * $(item).val();
  }, 0);
  console.log('$' + total.toFixed(2));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select class="ticket-qty" data-ticketprice="280.88" name="34"></select>
<select class="ticket-qty" data-ticketprice="390" name="39"></select>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.