Shaun
Shaun

Reputation: 93

C# MVC Textbox on the specific table row (disable) when the button is clicked

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

Upvotes: 1

Views: 2440

Answers (4)

Tetsuya Yamamoto
Tetsuya Yamamoto

Reputation: 24957

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

Upvotes: 2

Mark Schultheiss
Mark Schultheiss

Reputation: 34196

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>

Upvotes: 0

Mashhad Saleem
Mashhad Saleem

Reputation: 177

You just need to add bellow code at button click event

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

Upvotes: 0

A. Hasemeyer
A. Hasemeyer

Reputation: 1734

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.

Upvotes: 0

Related Questions