Search code examples
c#jquerywebgrid

Cannot update database entry and refresh dynamic WebGrid using jQuery - ASP.Net MVC


I am successfully dynamically displaying a WebGrid based on selected item of a DropDownList. If I select another item in the DropDownList, I will see a different WebGrid. Before stating what I am trying to do next, here is how I have achieved the above (with plenty of help from people like you).

Here is my Index view:

@model BarClients.Models.BarClientsViewModel

@{
    ViewBag.Title = "Index";
}

<h2>Enter Client Information</h2>
<br />
<table>
    <tr>
        <th align="left">
            @Html.DisplayNameFor(model => model.BAR_Clients.ClientId)
        </th>
    </tr>
    <tr>
        <th valign="top">
            <div id="MeditechDropDown">
                @Html.DropDownListFor(model => model.BAR_Clients.ClientId, Model.MeditechClientID, "-- Select --", new { style = "width:170px" })
            </div>
        </th>
        <th>
            @{Html.RenderAction("EmailAddressGrid", "Home");}
        </th>
    </tr>
</table>

Here is my EmailAddressGrid view:

@model BarClients.Models.BarClientsViewModel

@{
    WebGrid grid = null;
    if (Model.EmailAddressesOfChosenClient.Count<string>() != 0)
    {
        grid = new WebGrid(Model.EmailAddressesOfChosenClient, ajaxUpdateContainerId: "gridContent");
    }
}

<div id="gridContent">
@{ if (grid != null)
   {
       <table>
           <tr>
               <td>
               @grid.GetHtml(           
                columns: grid.Columns(
                grid.Column("Email Addresses", format: item => item)))
               </td>
               <td valign="top">
                   @Html.DisplayFor(model => model.InvoiceMode)
               </td>
           </tr>
       </table>     
   }
}
</div>

Here is the jQuery I am using to dynamically display a WebGrid based on selection of the DropDownList (clientID):

jQuery(document).ready(function () {
    $("#MeditechDropDown").change(function () {
        var id = $(this).find(":selected").val()
        var clientID = { "clientID": id }
        $.ajax({
            url: "/Home/PopulateEmailAddressUI",
            data: JSON.stringify(clientID), // Send value of the drop down change of option
            type: 'POST',
            datatype: 'html',
            contentType: 'application/json; charset=utf-8',
            success: function (response) {
                $('#gridContent').html(response)
            }
        });
    });
});

Here is the controller action PopulateEmailAddressUI that returns the asynchronous WebGrid:

[HttpPost]
public PartialViewResult PopulateEmailAddressUI(string clientID)
{
    _clientModel = InitialiseBarClientsModel();

    _clientModel.FindEmailAddresses(from client in eFormsDB.BAR_Clients where client.ClientId == clientID select client);

    return PartialView("~/Views/Home/EmailAddressGrid.cshtml", _clientModel);
}

So far so good. My next task is to be able to enter a new email address on an Editor. I would then hit an "Add Email" button which would then add it to a database table record identified by the currently selected item of the DropDownList mentioned above. To accomplish this, I have an extra table inside the "gridContent" div ID where the code for the WebGrid resides:

<table>
    <tr>
        <th align="left">
            @Html.EditorFor(model => model.NewEmailAddress)
        </th>
        <th>
            @Html.DropDownListFor(model => model.BAR_Clients.InvoiceMode, Model.InvoiceOptions, new { style = "width:70px" })
        </th>
        <th>
            <div id="AddEmail">
                <button>Add Email</button>
            </div>
        </th>
    </tr>
    <tr>
        <th align="left">
            @Html.Raw("Enter New Email Address")
        </th>
    </tr>
</table>

I (unsuccessful) attempt at having the email address added and the WebGrid reloaded through jQuery is as follows:

jQuery(document).ready(function () {
    var addEmail = $('#AddEmail');
    addEmail.on('click', function () {
        var id = $("#MeditechDropDown").find(":selected").val()
        var clientID = { "clientID": id }
        $.ajax({
            url: "/Home/AddEmailAddress",
            data: JSON.stringify(clientID), // Send value of the drop down change of option
            type: 'POST',
            datatype: 'html',
            contentType: 'application/json; charset=utf-8',
            success: function (response) {
                $('#gridContent').html(response)
            }
        });
    });
});

My controller action AddEmailAddress looks like:

[HttpPost]
public PartialViewResult AddEmailAddress(string clientID)
{
    // Code to update database omitted

    return PartialView("~/Views/Home/EmailAddressGrid.cshtml", _clientModel);
}

Basically after entering a new email address and clicking on the "Add Email" button, nothing is happening (controller action AddEmailAddress never gets called). What am I doing wrong? Things that could be getting in the way are the fact that AddEmail div ID is inside the gridContent div ID. Many thanks for any pointers.


Solution

  • For things to work the way I intended to, I needed to have one jQuery function that looked like this:

    jQuery(document).ready(function () {
        $("#MeditechDropDown").change(function () {
            var id = $(this).find(":selected").val()
            var clientID = { "clientID": id }
            $.ajax({
                url: "/Home/PopulateEmailAddressUI",
                data: JSON.stringify(clientID), // Send value of the drop down change of option
                type: 'POST',
                datatype: 'html',
                contentType: 'application/json; charset=utf-8',
                success: function (response) {
                    $('#gridContent').html(response)
                    $('button').click(function () {
                        var email = $("#NewEmailAddress").val()
                        var invoice = $("#InvoiceDropDown").find(":selected").val()
                        var emailInfo =
                        {
                            "clientID": id,
                            "emailAddress": email,
                            "invoiceMode": invoice
                        };
                        $.ajax({
                            url: "/Home/AddEmailAddress",
                            data: JSON.stringify(emailInfo),
                            type: 'POST',
                            contentType: 'application/json; charset=utf-8',
                            success: function (response) {
                                $('#gridContent').html(response)
                            }
                        });
                    })
                }
            });
        })
    });
    

    And my EmailAddressGrid view looks like:

    @model BarClients.Models.BarClientsViewModel
    
    @{
        WebGrid grid = null;
        if (Model.EmailAddressesOfChosenClient.Count<string>() != 0)
        {
            grid = new WebGrid(Model.EmailAddressesOfChosenClient, ajaxUpdateContainerId: "gridContent");
        }
    }
    
    <div id="gridContent">
    @{ if (grid != null)
       {
           <table>
               <tr>
                   <td>
                       @grid.GetHtml(
                tableStyle: "webgrid-table",
                headerStyle: "webgrid-header",
                footerStyle: "webgrid-footer",
                alternatingRowStyle: "webgrid-alternating-row",
                selectedRowStyle: "webgrid-selected-row",
                rowStyle: "webgrid-row-style",
                mode: WebGridPagerModes.All,
    
                columns: grid.Columns(
                grid.Column("Email Addresses", format: item => item)))
                   </td>
                   <td valign="top">
                       @Html.DisplayFor(model => model.InvoiceMode)
                   </td>
               </tr>
           </table>
    
          <br />
          <table>
              <tr>
                  <th align="left">
                      @Html.TextBoxFor(model => model.NewEmailAddress)
                  </th>
                  <th>
                      <div id="InvoiceDropDown">
                          @Html.DropDownListFor(model => model.BAR_Clients.InvoiceMode, Model.InvoiceOptions, new { style = "width:70px" })
                      </div>
                  </th>
                  <th>
                      <button>Add Email</button>
                  </th>
              </tr>
              <tr>
                  <th align="left">
                      @Html.Raw("Enter New Email Address")
                  </th>
              </tr>
          </table>     
       }
    }
    </div>
    

    And My Model class looks like:

    public class BarClientsViewModel
    {
        private List<string> _clientID;
        private List<string> _emailAddresses;
    
        public BAR_Clients BAR_Clients;
        public veForms_BAR_Clients veForms_BAR_Clients;
        public string InvoiceMode;
    
        [EmailFormatVerification]
        public string NewEmailAddress;
    
        public Exceptions Exceptions;
    
        public BarClientsViewModel(IEnumerable<veForms_BAR_Clients> meditechClients)
        {
            _clientID = new List<string>();
            foreach(veForms_BAR_Clients client in meditechClients)
            {
                _clientID.Add(client.Number);
            }
    
            _emailAddresses = new List<string>();
        }
    
        public void FindEmailAddresses(IEnumerable<BAR_Clients> barClients)
        {
            string emailAddressLine = "";
            foreach(BAR_Clients client in barClients)   // There will only be one client here
            {
                emailAddressLine = client.EmailAddress;
                InvoiceMode = client.InvoiceMode;
            }          
    
            string[] temp = emailAddressLine.Split(';');
            _emailAddresses = new List<string>();
            _emailAddresses = temp.ToList();
        }
    
        public string AddEmail(IEnumerable<BAR_Clients> barClients, string emailAddress)
        {
            string emailAddressLine = "";
            foreach (BAR_Clients client in barClients)   // There will only be one client here
            {
                emailAddressLine = client.EmailAddress;
                emailAddressLine = String.Format("{0};{1}", emailAddressLine, emailAddress);
            }
    
            return emailAddressLine;
        }
    
        public IEnumerable<SelectListItem> MeditechClientID
        {
            get { return new SelectList(_clientID); }
        }
    
        public IEnumerable<String> EmailAddressesOfChosenClient
        {
            get { return _emailAddresses; }
        }
    
        public IEnumerable<SelectListItem> InvoiceOptions
        {
            get { return new SelectList(new List<string>() { "PRINT", "EMAIL", "BOTH" }); }
        }
    }
    

    My two EF generated classes are as follows:

    public partial class BAR_Clients
    {
        public string ClientId { get; set; }
        public string EmailAddress { get; set; }
        public string InvoiceMode { get; set; }
    }
    

    And

    public partial class veForms_BAR_Clients
    {
        public string SourceID { get; set; }
        public string ClientID { get; set; }
        public string Number { get; set; }
        public string Name { get; set; }
    }
    

    My relevant controller action methods are as follows:

    public ViewResult Index()
    {
        _clientModel = InitialiseBarClientsModel();
        return View(_clientModel);
    }
    
    [HttpPost]
    public PartialViewResult PopulateEmailAddressUI(string clientID)
    {
        _clientModel = InitialiseBarClientsModel();
    
        _clientModel.FindEmailAddresses(from client in eFormsDB.BAR_Clients where client.ClientId == clientID select client);
    
        return PartialView("~/Views/Home/EmailAddressGrid.cshtml", _clientModel);
    }
    
    public PartialViewResult EmailAddressGrid()
    {
        _clientModel = InitialiseBarClientsModel();
        return PartialView("~/Views/Home/EmailAddressGrid.cshtml", _clientModel);
    }
    
    [HttpPost]
    public PartialViewResult AddEmailAddress(EmailInfo emailInfo)
    {
        _clientModel = InitialiseBarClientsModel();
    
        string updatedEmail = _clientModel.AddEmail(from client in eFormsDB.BAR_Clients where client.ClientId == emailInfo.clientID select client, emailInfo.emailAddress);
    
        var clientToUpdate = eFormsDB.BAR_Clients.Find(emailInfo.clientID);
    
        try
        {
            eFormsDB.Entry(clientToUpdate).Member("EmailAddress").CurrentValue = updatedEmail;
            eFormsDB.Entry(clientToUpdate).Member("InvoiceMode").CurrentValue = emailInfo.invoiceMode;
    
            eFormsDB.SaveChanges();
        }
        catch (Exception)
        {
            throw new Exception("General Exception occurred while saving to database");
        }
    
        _clientModel.FindEmailAddresses(from client in eFormsDB.BAR_Clients where client.ClientId == emailInfo.clientID select client);
    
        return PartialView("~/Views/Home/EmailAddressGrid.cshtml", _clientModel);
    }
    
    private BarClientsViewModel InitialiseBarClientsModel()
    {
        BarClientsViewModel clientModel = new BarClientsViewModel(from meditech in meditechDB.veForms_BAR_Clients select meditech);
    
        return clientModel;
    }