0

I have a list of products, each individual product has a checkbox value with the products id e.g. "321". When the products checkbox is checked (can be more than 1 selected) i require the value to be collected. Each product will also have a input text field for defining the Qty e.g "23" and i also require this Qty value to be collected. The Qty text input should only be collected if the checkbox is checked and the qty text value is greater than 1. The plan is to collect all these objects, put them in to a loop and finally turn them in to a string where i can then display the results.

So far i have managed to collect the checkbox values and put these into a string but i'm not sure how to collect the additional text Qty input values without breaking it. My understanding is that document.getElementsByTagName('input') is capable of collecting both input types as its basically looking for input tags, so i just need to work out how to collect and loop through both the checkboxes and the text inputs.

It was suggested that i use 2 if statements to accomplish this but i'm new to learning javascript so i'm not entirely sure how to go about it. I did try adding the if statement directly below the first (like you would in php) but this just seemed to break it completely so i assume that is wrong.

Here is my working code so far that collects the checkbox values and puts them in a string. If you select the checkbox and press the button the values are returned as a string. Please note nothing is currently appended to qty= because i dont know how to collect and loop the text input (this is what i need help with).

How can i collect the additional qty input value and append this number to qty=

// function will loop through all input tags and create
// url string from checked checkboxes
function checkbox_test() {
    var counter = 0, // counter for checked checkboxes
        i = 0,       // loop variable
        url = '/urlcheckout/add?product=',    // final url string
        // get a collection of objects with the specified 'input' TAGNAME
        input_obj = document.getElementsByTagName('input');
    // loop through all collected objects
    for (i = 0; i < input_obj.length; i++) {
        // if input object is checkbox and checkbox is checked then ...
        if (input_obj[i].type === 'checkbox' && input_obj[i].checked) {
            // ... increase counter and concatenate checkbox value to the url string
            counter++;
            url = url + input_obj[i].value + '&qty=' + '|';
        }
    }
    // display url string or message if there is no checked checkboxes
    if (counter > 0) {
        // remove first "&" from the generated url string
        url = url.substr(1);
        // display final url string
        alert(url);
    }
    else {
        alert('There is no checked checkbox');
    }
}
<ul>
<li>
    <form>
        <input type="checkbox" id="checked-product" name="checked-product" value="311">Add To Cart
        <div class="quantity">
            <input type="text" name="qty" id="qty" maxlength="12" value="1" class="input-text qty"/>
        </div>
    </form>
</li>
<li>
    <form>
        <input type="checkbox" id="checked-product" name="checked-product" value="321">Add To Cart
        <div class="quantity">
            <input type="text" name="qty" id="qty" maxlength="12" value="10" class="input-text qty"/>
        </div>
    </form>
</li>
<li>
    <form>
        <input type="checkbox" id="checked-product" name="checked-product" value="98">Add To Cart
        <div class="quantity">
            <input type="text" name="qty" id="qty" maxlength="12" value="5" class="input-text qty"/>
        </div>
    </form>
</li>
</ul>

    <button type="button" onclick="javascript:checkbox_test()">Add selected to cart</button>
markbarabus
  • 117
  • 1
  • 4
  • 11
  • You aren't adding the quantity in the string here `+ '&qty=' + '|';` right? Maybe that is the issue. – Zack Jun 10 '16 at 15:10
  • Yes that is the issue but i dont know how to collect and count both the checkbox and the text input value without breaking it. – markbarabus Jun 10 '16 at 15:13
  • `input_obj` will contain the `checkbox` and `text` elements, so you could have 2 if statements in your for loop and when it is a `checkbox`, add the `product=`, and when it is a `text` add the `qty=` portion of your URL. – Zack Jun 10 '16 at 15:17
  • I guess that doesn't solve the issue of knowing when you should or should not add the `qty=` based on the checkbox checked or not checked though... – Zack Jun 10 '16 at 15:18
  • Have you looked into a jQuery solution to this problem? – Zack Jun 10 '16 at 15:19
  • Sorry i'm still learning javascript, where would you add the second if statement? And yes it would need to consider whether the checkbox was checked before qty= is added. I was also planning on adding a additional parameter where qty was only added if the text input > 1 – markbarabus Jun 10 '16 at 15:29
  • jQuery is an option but of course its something i'm even less familiar with since i'm still learning. I did briefly look into using jQuery append & prepend but i couldnt find any examples of how to collect and string the objects – markbarabus Jun 10 '16 at 15:30
  • The HTML markup itself has some issues. [You should never use the same id for multiple elements](http://stackoverflow.com/a/5611975/1804496). And I feel like it may be bad design to have multiple forms contributing to one goal (constructing your url). – Zack Jun 10 '16 at 16:23
  • Come to think of it, wouldn't a url like `'/urlcheckout/add?product=311&qty=1&product=321&qty=10&product=98&qty=5'` be messy? You usually wouldn't want to set the same query string parameter multiple times in your url, although it is possible, see this answer http://stackoverflow.com/a/24728298/1804496. – Zack Jun 10 '16 at 16:30

2 Answers2

2

My answer has two parts: Part 1 is a fairly direct answer to your question, and Part 2 is a recommendation for a better way to do this that's maybe more robust and reliable.

Part 1 - Fairly Direct Answer

Instead of a second if to check for the text inputs, you can use a switch, like so:

var boxWasChecked = false;

// loop through all collected objects
for (i = 0; i < input_obj.length; i++) {

    // if input object is checkbox and checkbox is checked then ...
    switch(input_obj[i].type) {

      case 'checkbox':
        if (input_obj[i].checked) {
          // ... increase counter and concatenate checkbox value to the url string
          counter++;
          boxWasChecked = true;
          url = url + input_obj[i].value + ',qty=';
        } else {
          boxWasChecked = false;
        }

        break;

      case 'text':
        if (boxWasChecked) {
          url = url + input_obj[i].value + '|';
          boxWasChecked = false;
        }

        break;
    }
}

Here's a fiddle showing it working that way.

Note that I added variable boxWasChecked so you know whether a Qty textbox's corresponding checkbox has been checked.

Also, I wasn't sure exactly how you wanted the final query string formatted, so I set it up as one parameter named product whose value is a pipe- and comma-separated string that you can parse to extract the values. So the url will look like this:

urlcheckout/add?product=321,qty=10|98,qty=5

That seemed better than having a bunch of parameters with the same names, although you can tweak the string building code as you see fit, obviously.

Part 2 - Recommendation for Better Way

All of that isn't a great way to do this, though, as it's highly dependent on the element positions in the DOM, so adding elements or moving them around could break things. A more robust way would be to establish a definitive link between each checkbox and its corresponding Qty textbox--for example, adding an attribute like data-product-id to each Qty textbox and setting its value to the corresponding checkbox's value.

Here's a fiddle showing that more robust way.

You'll see in there that I used getElementsByName() rather than getElementsByTagName(), using the name attributes that you had already included on the inputs:

checkboxes = document.getElementsByName('checked-product'),
qtyBoxes = document.getElementsByName('qty'),

First, I gather the checkboxes and use an object to keep track of which ones have been checked:

var checkedBoxes = {};

// loop through the checkboxes and find the checked ones
for (i = 0; i < checkboxes.length; i++) {
    if (checkboxes[i].checked) {
      counter++;
      checkedBoxes[checkboxes[i].value] = 1; // update later w/ real qty
    }
}

Then I gather the Qty textboxes and, using the value of each one's data-product-id attribute (which I had to add to the markup), determine if its checkbox is checked:

// now get the entered Qtys for each checked box
for (i = 0; i < qtyBoxes.length; i++) {
  pid = qtyBoxes[i].getAttribute('data-product-id');

  if (checkedBoxes.hasOwnProperty(pid)) {
    checkedBoxes[pid] = qtyBoxes[i].value;
  }
}

Finally, I build the url using the checkedBoxes object:

// now build our url
Object.keys(checkedBoxes).forEach(function(k) {
  url += [
    k,
    ',qty=',
    checkedBoxes[k],
    '|'
  ].join('');
});

(Note that this way does not preserve the order of the items, though, so if your query string needs to list the items in the order in which they're displayed on the page, you'll need to use an array rather than an object.)

There are lots of ways to achieve what you're trying to do. Your original way will work, but hopefully this alternative way gives you an idea of how you might be able to achieve it more cleanly and reliably.

MikeJ
  • 2,179
  • 13
  • 16
0

Check the below simplified version.

document.querySelector("#submitOrder").addEventListener('click', function(){
 var checkStatus = document.querySelectorAll('#basket li'),
    urls = [];
  Array.prototype.forEach.call(checkStatus, function(item){
    var details = item.childNodes,
       urlTemplate = '/urlcheckout/add?product=',
       url = urlTemplate += details[0].value + '&qty=' + details[1].value;
    urls.push(url)
  });
  console.log(urls);
})
ul{ margin:0; padding:0}
<ul id="basket">
  <li class="products"><input type="checkbox" value = "311" name="item"><input type="text"></li>
  <li><input type="checkbox" value = "312" name="item"><input type="text"></li>
  <li><input type="checkbox" value = "313" name="item"><input type="text"></li>
</ul>
<button id="submitOrder">Submit</button>