8

I'm trying to program an "add" button below an ASP.NET MVC table to dynamically append a blank row, and then have a submit button to save each row to the database with one click.

There are several similar questions on SO but none that I have been able to apply to this. I've been trying to apply this example but the "add" button is not appending new rows.

Model:

public class TableForm
    {
        public int Id { get; set; }
        public List<TableFormData> TableFormDatas { get; set; }
    }

    public class TableFormData
    {
        public int Id { get; set; }
        public string ClientSampleID { get; set; }
        public string AdditionalComments { get; set; }
        public string AcidStables { get; set; }

Razor view:

@model NewTestSix.Models.TableForm

@{
    ViewData["Title"] = "Create";
    Layout = "~/Views/Shared/_Layout.cshtml";
}

@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)

<fieldset>
    <legend>Sample submission</legend>
    <table id="submissionTable" class="table table-bordered">
        <thead>
            <tr>
                <td>Sample ID</td>
                <td>Additional Comments</td>
                <td>Acid-stable amino acids</td>
            </tr>
        </thead>

        <tr id="tablerow0">
            <td>
                <div class="editor-field">
                    <input class="text-box single-line" name="ClientSampleID[0]" type="text" value="" required="required" />
                </div>
            </td>
            <td>
                <div class="editor-field">
                    <input class="text-box single-line" name="AdditionalComments[0]" type="text" value="" required="required" />
                </div>
            </td>
            <td>
                <div class="editor-field">
                    <input class="text-box single-line" name="AcidStables[0]" type="text" value="" />
                </div>
            </td>
            <td>
                <button type="button" class="btn btn-primary" onclick="removeTr(0);">Delete</button>
            </td>
            <td>

            </td>
        </tr>

    </table>
    <p>
        <button id="add" type="submit" class="btn btn-primary">Add</button>
    </p>
    <hr />

    <p>
        <input type="submit" value="Create" class="btn btn-default" />
    </p>
</fieldset>
}

@section Scripts {
    <script src="~/bundles/jqueryval.js" type="text/javascript">
        var counter = 1;
        $(function () {

            $('#add').click(function () {
                $('<tr id="tablerow' + counter + '"><td>' +
                    '<input type="text" class="text-box single-line" name="ClientSampleID[' + counter + ']" value="" required="required" />' +
                    '</td>' +
                    '<td>' +
                    '<input type="text" class="text-box single-line" name="AdditionalComments[' + counter + ']" value="" required="required" />' +
                    '</td>' +
                    '<td>' +
                    '<input type="text" class="text-box single-line" name="AcidStables[' + counter + ']" value="" required="required" />' +
                    '</td>' +
                    '<td>' +
                    '<button type="button" class="btn btn-primary" onclick="removeTr(' + counter + ');">Delete</button>' +
                    '</td>' +
                    '</tr>').appendTo('#submissionTable');
                counter++;
                return false;
            });
        });
        function removeTr(index) {
            if (counter > 1) {
                $('#tablerow' + index).remove();
                counter--;
            }
            return false;
        }
    </script>

I'm not too fussed about model binding with the controller at this stage, I just want to get this add button working. example controller:

  [HttpPost]
        public ActionResult Index(string any = "")
        {
            IList<TableForm> _TableForm = new List<TableForm>();

            //Loop through the forms
            for (int i = 0; i <= Request.Form.Count; i++)
            {
                var ClientSampleID = Request.Form["ClientSampleID[" + i + "]"];
                var additionalComments = Request.Form["AdditionalComments[" + i + "]"];
                var acidStables = Request.Form["AcidStables[" + i + "]"];

                if (!String.IsNullOrEmpty(ClientSampleID))
                {
                    _TableForm.Add(new TableForm { ClientSampleID = ClientSampleID, AcidStables = acidStables, AdditionalComments = additionalComments });
                }
            }

            return View();
        }

Thanks for any insights.

Current: current

Desired after clicking "add" button: enter image description here

heds1
  • 3,203
  • 2
  • 17
  • 32

3 Answers3

14

Change your

<button id="add" type="submit" class="btn btn-primary">Add</button>

into

<button id="add" type="button" class="btn btn-primary">Add</button>

...as I don't think the "Add" button should ever make the browser do a form submission when clicked, it should only invoke your button's client-side 'click' event-handler.

Then remove src="~/bundles/jqueryval.js" part from your script element's opening tag: inline scripts cannot have a src="" attribute.

Like this:

<script type="text/javascript">
    var counter = 1;
    //... the rest of your code is here...
</script>

If you actually have a jqueryval.js file, put it in another <script> tag.

Here is the result you are expecting if I'm not mistaken.

var counter = 1;
        $(function () {
            $('#add').click(function () {
                $('<tr id="tablerow' + counter + '"><td>' +
                    '<input type="text" class="text-box single-line" name="ClientSampleID[' + counter + ']" value="" required="required" />' +
                    '</td>' +
                    '<td>' +
                    '<input type="text" class="text-box single-line" name="AdditionalComments[' + counter + ']" value="" required="required" />' +
                    '</td>' +
                    '<td>' +
                    '<input type="text" class="text-box single-line" name="AcidStables[' + counter + ']" value="" required="required" />' +
                    '</td>' +
                    '<td>' +
                    '<button type="button" class="btn btn-primary" onclick="removeTr(' + counter + ');">Delete</button>' +
                    '</td>' +
                    '</tr>').appendTo('#submissionTable');
                counter++;
                return false;
            });
        });
        function removeTr(index) {
            if (counter > 1) {
                $('#tablerow' + index).remove();
                counter--;
            }
            return false;
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<fieldset>
        <legend>Sample submission</legend>
        <table id="submissionTable" class="table table-bordered">
            <thead>
                <tr>
                    <td>Sample ID</td>
                    <td>Additional Comments</td>
                    <td>Acid-stable amino acids</td>
                </tr>
            </thead>

            <tr id="tablerow0">
                <td>
                    <div class="editor-field">
                        <input class="text-box single-line" name="ClientSampleID[0]" type="text" value="" required="required" />
                    </div>
                </td>
                <td>
                    <div class="editor-field">
                        <input class="text-box single-line" name="AdditionalComments[0]" type="text" value="" required="required" />
                    </div>
                </td>
                <td>
                    <div class="editor-field">
                        <input class="text-box single-line" name="AcidStables[0]" type="text" value="" />
                    </div>
                </td>
                <td>
                    <button type="button" class="btn btn-primary" onclick="removeTr(0);">Delete</button>
                </td>
                <td></td>
            </tr>

        </table>
        <p>
            <button id="add" type="button" class="btn btn-primary">Add</button>
        </p>
        <hr />

        <p>
            <input type="submit" value="Create" class="btn btn-default" />
        </p>
    </fieldset>

Let me know if it helps.

Dai
  • 141,631
  • 28
  • 261
  • 374
Nam Le
  • 568
  • 5
  • 12
  • 1
    Have been looking for something similar to this, as it's basically the approach I've used historically, but is there really no better way to do this than to encode the entire table row you want to add as a string and then add it to the DOM? It just doesn't feel very clean / maintainable for even moderately complex tables vs things like HTML Helper functions. The only other option I could think of is using a partial-view and AJAX, but it feels like a waste to go all the way to the server and back for a handful of table rows. – Lovethenakedgun May 07 '20 at 04:58
  • 1
    If complex DOM manipulation is needed, I think we need frontend libraries. It doesn't have to be fullblown framework like Angular. Something lightweight like Vue, or even templating library like Mustache will do the trick. – Nam Le May 07 '20 at 14:21
2

You can used jQuery jqGrid

It is jquery plugin which is free and open source. This is completely Ajax enabled to display tabular data and to manipulate. Additionally, we can apply different Jquery UI theme, see the demo.

Action Method: There is nothing here since we will be getting product details using Ajax in json format.

    public ActionResult GetProducts(string sidx, string sord, int page, int rows)
{
  var products = Product.GetSampleProducts();
  int pageIndex = Convert.ToInt32(page) - 1;
  int pageSize = rows;
  int totalRecords = products.Count();
  int totalPages = (int)Math.Ceiling((float)totalRecords / (float)pageSize);

  var data = products.OrderBy(x => x.Id)
                .Skip(pageSize * (page - 1))
                .Take(pageSize).ToList();

  var jsonData = new
  {
      total = totalPages,
      page = page,
      records = totalRecords,
      rows = data
  };

  return Json(jsonData, JsonRequestBehavior.AllowGet);
}

And add this tag to target page

<table id="jqGrid"></table>
<div id="jqGridPager"></div>

After that in script section add this:

<script>
var myGrid = $('#jqGrid');
myGrid.jqGrid({
      url: '/Home/GetProducts/',
      datatype: "json",
      contentType: "application/json; charset-utf-8",
      mtype: 'GET',
      colNames: ['ProductID', 'Name', 'Price', 'Department', 'Action'],
      colModel: [
          { name: 'Id', key: true, width: 75 },
          { name: 'Name', key: true, width: 200 },
          { name: 'Price', key: true, width: 75 },
          { name: 'Department', key: true, width: 200 },
          { name: 'Edit', key: true, width: 100, editable: true, formatter: editButton }
      ],
      rowNum: 4,
      pager: '#jqGridPager',
      gridview: true,
      rownumbers: true,
      pagerpos: 'center'
});
</script>

Original post is here

Feri
  • 105
  • 1
  • 10
0

var counter = 2;
        $(function () {
            $('#add').click(function () {
                $('<tr id="tablerow' + counter + '"><td>' +
                    '<input type="text" class="text-box single-line" name="ClientSampleID[' + counter + ']" value="" required="required" />' +
                    '</td>' +
                    '<td>' +
                    '<input type="text" class="text-box single-line" name="AdditionalComments[' + counter + ']" value="" required="required" />' +
                    '</td>' +
                    '<td>' +
                    '<input type="text" class="text-box single-line" name="AcidStables[' + counter + ']" value="" required="required" />' +
                    '</td>' +
                    '<td>' +
                    '<button type="button" class="btn btn-primary" onclick="removeTr(' + counter + ');">Delete</button>' +
                    '</td>' +
                    '</tr>').appendTo('#submissionTable');
                counter++;
                return false;
            });
        });
        function removeTr(index) {
            if (counter > 1) {
                $('#tablerow' + index).remove();
                counter--;
            }
            return false;
        }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<fieldset>
        <legend>Sample submission</legend>
        <table id="submissionTable" class="table table-bordered">
            <thead>
                <tr>
                    <td>Sample ID</td>
                    <td>Additional Comments</td>
                    <td>Acid-stable amino acids</td>
                </tr>
            </thead>

            <tr id="tablerow0">
                <td>
                    <div class="editor-field">
                        <input class="text-box single-line" name="ClientSampleID[0]" type="text" value="" required="required" />
                    </div>
                </td>
                <td>
                    <div class="editor-field">
                        <input class="text-box single-line" name="AdditionalComments[0]" type="text" value="" required="required" />
                    </div>
                </td>
                <td>
                    <div class="editor-field">
                        <input class="text-box single-line" name="AcidStables[0]" type="text" value="" />
                    </div>
                </td>
                <td>
                    <button type="button" class="btn btn-primary" onclick="removeTr(0);">Delete</button>
                </td>
                <td></td>
            </tr>

        </table>
        <p>
            <button id="add" type="button" class="btn btn-primary">Add</button>
        </p>
        <hr />

        <p>
            <input type="submit" value="Create" class="btn btn-default" />
        </p>
    </fieldset>
  • 1
    Please add some kind of description to your solution – vahid tajari May 07 '22 at 11:14
  • 1
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 07 '22 at 11:14