1

I have a table whose values are looped with my product list and I have a textbox for 'Quantity' and a button for 'Add to Cart'. I am trying to do when I click on 'Add to Cart' button, it will check the Quantity value if it has value or not then the 'Quantity' textbox will get disabled for that specific row only.

Product.cshtml

<table id ="productList" class="table table-dark">
    <tr>
        <th>Product ID</th>
        <th>Title</th>
        <th>Description</th>
        <th>Quantity</th>
        <th>Add to cart</th>
    </tr>
    @foreach (var item in Model)
        {
            <tr class="active">
                <td>@item.Id</td>
                <td>@item.Title</td>
                <td>@item.Description</td>
                <td>@Html.TextBox("Quantity", "0", new { @class = "form-control" })</td>
                <td><button class="btn btn-default pull-left" onclick="disableText(Quantity);" id="btn-addToCart">Add To Cart</button></td>
            </tr>
        }
</table>

javascript

function disableText(QtyVal) {
    if(QtyVal.value == '')
    {
        document.getElementById("Quantity").value = 1;
    }
}

Currently the output of my project is everytime I click any submit button, it will always update the first row (which is incorrect).

The goal is it will update the Quantity and disable it for that specific row

3
  • 1
    Your HTML is invalid. id="btn-addToCart" inserts a duplicate ID into each row of the table. HTML id attributes MUST be unique on the page. developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/id Commented Oct 4, 2018 at 20:01
  • Hi @MarkSchultheiss, thank you for that. How can I pass a unique id to the button itself? Add an integer after the btn-addToCart[i]? Am I correct? Commented Oct 4, 2018 at 20:59
  • I posted an answer that should show how to use the buttons on each row, not requiring an id, using classes instead. Commented Oct 5, 2018 at 11:12

4 Answers 4

2

Your problem lies in this button definition:

<button class="btn btn-default pull-left" onclick="disableText(Quantity);" id="btn-addToCart">Add To Cart</button>

The foreach loop generates duplicate id attribute values for all buttons, which builds invalid HTML and causing undesired behavior. Since your table also contains <input> tag, you should use for loop instead of foreach and put distinct class name to the button, e.g. buttonadd:

<!-- assumed that @model List<Product> is used -->
<table id ="productList" class="table table-dark">
    <tr>
        <th>Product ID</th>
        <th>Title</th>
        <th>Description</th>
        <th>Quantity</th>
        <th>Add to cart</th>
    </tr>
    @for (int i = 0; i < Model.Count; i++)
    {
       <tr class="active">
           <td>@Model[i].Id</td>
           <td>@Model[i].Title</td>
           <td>@Model[i].Description</td>
           <td>@Html.TextBox("Quantity", "0", new { @class = "form-control" })</td>
           <td><button type="button" class="btn btn-default pull-left buttonadd">Add To Cart</button></td>
       </tr>
    }
</table>

Then you can reference buttonadd class as selector to find out which row the button contained, and setting <input> state to readonly (not disabled because you want to send quantity values on form submit; all inputs with disabled attribute are not included during submit) as in example below:

$(document).on('click', '#productList .buttonadd', function () {
    var row = $(this).closest('tr');

    // find quantity text box in the same row as clicked button
    var qty = row.find('input');

    // set quantity value and prevent user input
    qty.val(parseInt(qty.val()) + 1);
    qty.attr('readonly', 'readonly');
});

Note: If you want to use strongly-typed helper, use @Html.TextBoxFor:

@Html.TextBoxFor(m => m[i].Quantity, new { @class = "form-control" })

Live example: .NET Fiddle

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

2 Comments

This solution still produces invalid HTML with the duplicate ID on the button.
Ah, my mistake by not removing id part after testing. But the solution should work with removed id attribute.
0

Since all of your textboxes have the same Id you cannot specify which one you are trying to update in your js. Try giving a unique ID to your TextBox then when you getElementById("UniqueID") you can ensure you are selecting the correct text box.

1 Comment

So I need to add an unique number after the id for my textbox and button? Sorry fairly new to this.
0

You just need to add bellow code at button click event

(this).prev('input').attr("disabled", "disabled")

Comments

0

Use a partial view, save some headache.

<table id ="productList" class="table table-dark">
    <tr>
        <th>Product ID</th>
        <th>Title</th>
        <th>Description</th>
        <th>Quantity</th>
        <th>Add to cart</th>
    </tr>
    @foreach (var item in Model)
    {
        @Html.Partial("~/Views/_OrderRowPartial.cshtml", item)
    }
</table>

_OrderRowPartial.cshtml:

@model item
<tr class="active">
    <td>@item.Id</td>
    <td>@item.Title</td>
    <td>@item.Description</td>
    <td>@Html.TextBoxFor(m => m.Quantity,  new { @class = "form-control quantity" })</td>
    <td><button class="btn btn-default pull-left" onclick="disableText();">Add To Cart</button></td>
</tr>

Javascript:

function disableText(t, el) {
  var qty = el.parentElement.previousElementSibling.getElementsByTagName('input')[0];
  mytd.style.border = "1px solid #00FF00";
  console.log(qty.value);
  if (qty.value == '') {
    qty.value = 1;
  }
}

Here is an example where I set borders on stuff to make it obvious what is going on. Unclear if you want to disable input or button so I did both.

function disableText(t, el) {
  el.style.border = "2px solid #FF0000";
  var mytd = el.parentElement;
  mytd.style.border = "1px solid #00FF00";
  var mytr = mytd.parentElement;
  var qtytd = mytd.previousElementSibling;
  var qty = qtytd.getElementsByTagName('input')[0];
  qtytd.style.border = "2px solid orange";
  qty.style.border = "2px solid cyan";
  console.log(qty.value);
  if (qty.value == '') {
    qty.value = 1;
  }
  // disable button
  el.setAttribute("disabled", "disabled");
  qty.setAttribute("disabled", "disabled");
}
<table id="productList" class="table table-dark">
  <tr>
    <th>Product ID</th>
    <th>Title</th>
    <th>Description</th>
    <th>Quantity</th>
    <th>Add to cart</th>
  </tr>
  <tr class="active">
    <td>1234d</td>
    <td>Cherry Pie</td>
    <td>Gooey cherry pie</td>
    <td><input type="text" class="form-control quantity" value="2" .>
      <td><button class="btn btn-default pull-left" onclick="disableText('',this);">Add To Cart</button></td>
  </tr>
  <tr class="active">
    <td>1234hd</td>
    <td>Hot Dog</td>
    <td>Dog, With mustard</td>
    <td><input type="text" class="form-control quantity" /></td>
    <td><button class="btn btn-default pull-left" onclick="disableText('',this);">Add To Cart</button></td>
  </tr>
</table>

3 Comments

Thanks for this, Mark! Appreciated it!
I disagree with qty.setAttribute("disabled", "disabled"); => this will not posting the quantity data as intended on form submit. Using readonly can still post the data while preventing user input.
@TetsuyaYamamoto but the OP asked for disabled so that is it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.