Avatar of jwebster77
jwebster77
 asked on

jQuery Javascript adds an extra row to the table in MVC

Hi,
I have a main view which has a "Comments" link on each row that when clicked it opens up a partial view. The partial view displays a table and textboxes, and an "Add" button that when clicked it adds the data entered in the textboxes to the table.

The first time I click on comments, I add data to the textboxes and hit the Add button and everything works.

The problem is:  when I open the partial view from another record(by clicking on Comments) and add data to the textboxes, after I click on add it adds an extra blank row.  It is as if the add button is clicked twice.  Could you please help me solve this issue?  The code I am using is below.
Thank you very much.

**PARTIAL VIEW:**
        @model IEnumerable<HelpDeskSupport.Models.Comment>

        <html>
        <body>
    <table class="table table-striped table-bordered" cellpadding="0" cellspacing="0" border="0" width="1500" id="tblComments">
        <thead>
            <tr>
                <th>
                    @Html.DisplayNameFor(model => model.TicketNumber)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Comment1)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.AssignedTo)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.CreatedBy)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Date)
                </th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model)
            {
                <tr>
                    <td>
                        @Html.DisplayFor(modelItem => item.TicketNumber)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.Comment1)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.AssignedTo)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.CreatedBy)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.Date)
                    </td>
                </tr>
            }
            
        </tbody>
        <tfoot>
            <tr>
                <td><input type="text" id="txtTicketNumber" value=@ViewData["NumberFromViewAll"] readonly /></td>
                <td><input type="text" id="txtComment" /></td>
                <td><input type="text" id="txtAssignedTo" /></td>
                <td><input type="text" id="txtCreatedBy" /></td>
                <td><input type="text" id="txtDate" /></td>
                <td><input type="button" id="btnAddComment" value="Add" /></td>
            </tr>
        </tfoot>
    </table>
    <br />
    <input type="button" id="btnSave" value="Save All" />

    @*<script type="text/javascript" src="http://ajax.cdnjs.com/ajax/libs/json2/20110223/json2.js"></script>*@
    <script src="~/Scripts/json2.js"></script>
    <script type="text/javascript">
        $("body").on("click", "#btnAddComment", function () {
            //Reference the TextBoxes
            var txtTicketNumber = $("#txtTicketNumber");
            var txtComment = $("#txtComment");
            var txtAssignedTo = $("#txtAssignedTo");
            var txtCreatedBy = $("#txtCreatedBy");
            var txtDate = $("#txtDate");

            //Get the reference of the Table's TBODY element
            var tableBody = $("#tblComments > TBODY")[0];
            //Add Row
            var row = tableBody.insertRow(-1);

            //Add TicketNumber cell          
            var cell = $(row.insertCell(-1));
            cell.html(txtTicketNumber.val());

            //Add Comment cell
            cell = $(row.insertCell(-1));
            cell.html(txtComment.val());

            //Add AssignedTo cell
            cell = $(row.insertCell(-1));
            cell.html(txtAssignedTo.val());

            //Add CreatedBy cell
            cell = $(row.insertCell(-1));
            cell.html(txtCreatedBy.val());

            //Add Date cell
            cell = $(row.insertCell(-1));
            cell.html(txtDate.val());           

            //Clear the TextBoxes
            txtComment.val("");
            txtAssignedTo.val("");
            txtCreatedBy.val("");
            txtDate.val("");
        });

        $("body").on("click", "#btnSave", function () {
            //Loop through the Table rows and build a JSON array
            var commentsArray = new Array();
            $("#tblComments TBODY TR").each(function () {
                var row = $(this);
                var commentLine = {};
                commentLine.TicketNumber = row.find("TD").eq(0).html();
                commentLine.Comment1 = row.find("TD").eq(1).html();
                commentLine.AssignedTo = row.find("TD").eq(2).html();
                commentLine.CreatedBy = row.find("TD").eq(3).html();
                commentLine.Date = row.find("TD").eq(4).html();
                commentsArray.push(commentLine);
            });

            //Send the JSON array to Controller using AJAX
            $.ajax({
                type: "POST",
                url: "/Tickets/InsertComments",
                data: JSON.stringify(commentsArray),
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function () {
                    alert("Comment(s) inserted.");
                }
            });
        });
    </script>
</body>
</html>

Open in new window



**CONTROLLER:**
         //VIEW ALL COMMENTS AND DISPLAY IN PARTIAL
        [HttpPost]
        public ActionResult ViewComments(int ticketNum)
        {
            List<Comment> AllComments = new List<Comment>();
            using (DBModel db = new DBModel())
                AllComments = db.Comments.Where(x => x.TicketNumber == ticketNum).ToList();

            //get iNumber from ViewAll to display in the ticket number textbox of the comments partial view
            ViewData["NumberFromViewAll"] = ticketNum;

            return PartialView("ViewComments", AllComments);
        }

        public JsonResult InsertComments(List<Comment> commentsArray)
        {
            using (DBModel db = new DBModel())
            {
                if (commentsArray != null)
                {
                    var lastColumnComments = commentsArray.Last();
                    var ticketNumberToDelete = lastColumnComments.TicketNumber;
                    var sqlQuery = "Delete [Comments] where TicketNumber = " + ticketNumberToDelete;
                    //Delete all comments from comments table. Previous comments are copied in javascript and re-populated
                    db.Database.ExecuteSqlCommand(sqlQuery);
                }

                //Check for NULL
                //if (commentsArray == null)
                //{
                //    commentsArray = new List<Comment>();
                //}

                foreach (Comment c in commentsArray)
                {
                    db.Comments.Add(c);
                }               
                int insertedRecords = db.SaveChanges();
                return Json(insertedRecords);
            }
        }

Open in new window



**IN CASE YOU WANT TO SEE HOW THE VIEWCOMMENTS IS DISPLAYED FROM THE MAIN VIEW:**
      @section modalComments
    {
    <script type="text/javascript">
        function showComments() {
            $("#dialog").dialog({
                autoOpen: false,
                modal: true,
                title: "View Details"
            });
            $("#ticketTable .details").click(function () {
                var ticketNum = $(this).closest("tr").find("td").eq(0).html();
                $.ajax({
                    type: "POST",
                    url: "/Tickets/ViewComments",
                    data: '{ticketNum: "' + ticketNum + '" }',
                    contentType: "application/json; charset=utf-8",
                    dataType: "html",
                    success: function (response) {
                        $('#dialog').html(response);
                        $('#dialog').dialog('open');
                    },
                    failure: function (response) {
                        alert(response.responseText);
                    },
                    error: function (response) {
                        alert(response.responseText);
                    }
                });
            });
        };

        $(function () {
            showComments();
        });   

Open in new window

.NET MVCHTMLJavaScriptjQuery

Avatar of undefined
Last Comment
jwebster77

8/22/2022 - Mon
leakim971

remove the javascript from your partial view and add it to your main page AT LEAST to test
jwebster77

ASKER
I tried that and the page does not work as the javascript calls for buttons and textboxes that are on the partial view.
The functionality works and it adds rows and then save them to the database.  The problem comes when you hit on another comments link(so the second time I hit a Comments link) and try to add something:  it adds extra rows when clicking on the add button.  Then if you go again to another "Comments" link and click on Add it adds that extra row and another one, and so on every time I click on Add.
jwebster77

ASKER
By debugging it, it looks like the add button runs twice, but that happens not the first time around instead when I click on another Comments link and try to add.  So it is for the save all button as it saves the same thing to the database twice.  Could anyone suggest what code changes I should make?  I cannot seem to see the error.  Thank you very much.
This is the best money I have ever spent. I cannot not tell you how many times these folks have saved my bacon. I learn so much from the contributors.
rwheeler23
ASKER CERTIFIED SOLUTION
leakim971

THIS SOLUTION ONLY AVAILABLE TO MEMBERS.
View this solution by signing up for a free trial.
Members can start a 7-Day free trial and enjoy unlimited access to the platform.
See Pricing Options
Start Free Trial
GET A PERSONALIZED SOLUTION
Ask your own question & get feedback from real experts
Find out why thousands trust the EE community with their toughest problems.
leakim971

By debugging it, it looks like the add button runs twice

this is my point asking you to put it in the main page, else you declare everytime you call the partial view new events thresholds (add and save)
jwebster77

ASKER
I did what you suggested ("replace add the whole code in a $(document).ready(function()")  and now the Add button is not being fired at all.  Here is the code I have now for the main view and the partial view.  I did not change anything in the controller.

MAIN VIEW:

@model IEnumerable<HelpDeskSupport.Models.Ticket>

@{
    ViewBag.Title = "ViewAll";
    //Layout = null;
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.0/themes/smoothness/jquery-ui.css">                @*for the visual style of the datepicker of the dtLastUpdated column*@


@section modalComments
    {
    <script type="text/javascript">
        function showComments() {
            $("#dialog").dialog({
                autoOpen: false,
                modal: true,
                title: "View Details"
            });
            debugger;
            $("#ticketTable .details").click(function () {
                var ticketNum = $(this).closest("tr").find("td").eq(0).html();
                $.ajax({
                    type: "POST",
                    url: "/Tickets/ViewComments",
                    data: '{ticketNum: "' + ticketNum + '" }',
                    contentType: "application/json; charset=utf-8",
                    dataType: "html",
                    success: function (response) {
                        $('#dialog').html(response);
                        $('#dialog').dialog('open');
                    },
                    failure: function (response) {
                        alert(response.responseText);
                    },
                    error: function (response) {
                        alert(response.responseText);
                    }
                });
            });
        };

        $(function () {
            showComments();
        });
    </script>
}

<head>
<script src="~/Scripts/json2.js"></script>
<script type="text/javascript">
    jQuery(function ($) {                                           // SHORTCUT OF $(document).ready(function($) {
            $(document).on("click", "#btnAddComment", function () {
                debugger;
                //Reference the TextBoxes
                var txtTicketNumber = $("#txtTicketNumber");
                var txtComment = $("#txtComment");
                var txtAssignedTo = $("#txtAssignedTo");
                var txtCreatedBy = $("#txtCreatedBy");
                var txtDate = $("#txtDate");

                //Get the reference of the Table's TBODY element
                var tableBody = $("#tblComments > TBODY")[0];
                //var tBody = $("#tblComments")[0];

                //Add Row
                var row = tableBody.insertRow(-1);

                //Add TicketNumber cell
                var cell = $(row.insertCell(-1));
                cell.html(txtTicketNumber.val());

                //Add Comment cell
                cell = $(row.insertCell(-1));
                cell.html(txtComment.val());

                //Add AssignedTo cell
                cell = $(row.insertCell(-1));
                cell.html(txtAssignedTo.val());

                //Add CreatedBy cell
                cell = $(row.insertCell(-1));
                cell.html(txtCreatedBy.val());

                //Add Date cell
                cell = $(row.insertCell(-1));
                cell.html(txtDate.val());

                 //Clear the TextBoxes
                txtComment.val("");
                txtAssignedTo.val("");
                txtCreatedBy.val("");
                txtDate.val("");
            });

                $(document).on("click", "#btnSave", function () {
                //Loop through the Table rows and build a JSON array
                    var commentsArray = new Array();
                    $("#tblComments TBODY TR").each(function () {
                        //$("#tblComments TBODY TR").last(function () {
                        var row = $(this);
                        var commentLine = {};
                        commentLine.TicketNumber = row.find("TD").eq(0).html();
                        commentLine.Comment1 = row.find("TD").eq(1).html();
                        commentLine.AssignedTo = row.find("TD").eq(2).html();
                        commentLine.CreatedBy = row.find("TD").eq(3).html();
                        commentLine.Date = row.find("TD").eq(4).html();
                        commentsArray.push(commentLine);
                    });
                debugger;
                //Send the JSON array to Controller using AJAX
                    $.ajax({
                        type: "POST",
                        url: "/Tickets/InsertComments",
                        data: JSON.stringify(commentsArray),
                        contentType: "application/json; charset=utf-8",
                        dataType: "json",
                        success: function () {
                            alert("Comment(s) inserted.");
                        }
                    });
                });
    });
</script>
</head>


<button type="button" onclick="cleanFilters()" value="Clear Filters" id="filterBtn" class="btn btn-primary btn-sm">Clear Filters / Reset</button>


@*jQuery Datatable (and could also be for ThemeRoller*@
<table class="display table table-striped table-bordered" id="ticketTable" style="width:100%">
    <thead>
        <tr id="filters">
            <th>
                @Html.DisplayNameFor(model => model.iNumber)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.dtLastUpdated)
                <input type="text" id="datepicker" class="datepicker">    @*readonly="readonly"*@
            </th>
            <th>
                @Html.DisplayNameFor(model => model.vcSubject)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.vcFrom)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.vcPriority)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.vcAssignedTo)
            <th>
                @Html.DisplayNameFor(model => model.vcStatus)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.vcRequestType)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.vcLocation)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.vcCategory)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.dtAnticipatedCompletion)
            </th>
            <th></th>
        </tr>
    </thead>

    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.iNumber)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.dtLastUpdated)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.vcSubject)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.vcFrom)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.vcPriority)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.vcAssignedTo)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.vcStatus)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.vcRequestType)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.vcLocation)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.vcCategory)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.dtAnticipatedCompletion)
                </td>
                <td>

                    <a class="btn btn-primary btn-sm" onclick="Edit('@Url.Action("EditOneRecord", "Tickets", new { id = item.iNumber })')"><i class="fa fa-pencil fa-lg"></i></a>
                    <a class="btn btn-danger btn-sm" onclick="Delete('@Url.Action("Delete", "Tickets", new { id = item.iNumber })')"><i class="fa fa-trash fa-lg"></i></a>
                    <a class="details" href="javascript:;">Comments</a>
                </td>
            </tr>
        }
    </tbody>
</table>


<div id="dialog" style="display: none">
</div>

Open in new window



PARTIAL VIEW:

@model IEnumerable<HelpDeskSupport.Models.Comment>

<html>
<body>
    <table class="table table-striped table-bordered" cellpadding="0" cellspacing="0" border="0" width="1500" id="tblComments">
        <thead>
            <tr>
                <th>
                    @Html.DisplayNameFor(model => model.TicketNumber)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Comment1)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.AssignedTo)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.CreatedBy)
                </th>
                <th>
                    @Html.DisplayNameFor(model => model.Date)
                </th>
            </tr>
        </thead>
        <tbody>
            @foreach (var item in Model)
            {
                <tr>
                    <td>
                        @Html.DisplayFor(modelItem => item.TicketNumber)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.Comment1)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.AssignedTo)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.CreatedBy)
                    </td>
                    <td>
                        @Html.DisplayFor(modelItem => item.Date)
                    </td>
                </tr>
            }
        </tbody>
        <tfoot>
            <tr>
                <td><input type="text" id="txtTicketNumber" value=@ViewData["NumberFromViewAll"] readonly /></td>
                <td><input type="text" id="txtComment" /></td>
                <td><input type="text" id="txtAssignedTo" /></td>
                <td><input type="text" id="txtCreatedBy" /></td>
                <td><input type="text" id="txtDate" /></td>
                <td><input type="button" id="btnAddComment" value="Add" /></td>
            </tr>
        </tfoot>
    </table>
    <br />
    <input type="button" id="btnSave" value="Save All" />

</body>
</html>

Open in new window

leakim971

do a right click on the add button when you've the partial view loaded in the browser/page
and check the ID attribute
it should match to "btnAddComment" else let me know
⚡ FREE TRIAL OFFER
Try out a week of full access for free.
Find out why thousands trust the EE community with their toughest problems.
leakim971

you need to put this script after the declaration(script tag) of the jQuery plugin
jwebster77

ASKER
Hi, I think it is working now.  Does that mean that I have to leave your code in the main view and not the partial view? Why would that be?

Anyway, after adding your code I forgot to check the console where I noticed it was missing a jQuery library.  I added that and now it seems to work.  Thank you so much!  I will make sure tomorrow still works fine as I am leaving now and then if it is I will mark this as the solution.  Thanks again
leakim971

Does that mean that I have to leave your code in the main view and not the partial view? Why would that be?

You should until you've good reason to not put it there
Your help has saved me hundreds of hours of internet surfing.
fblack61
jwebster77

ASKER
Thank you very much!