0

So i am trying to achieve the best (most user friendly and performant) way of having a html table updated with data that is queried for in a searchbox.

The user can search for something by typing in a searchbox, i want to reload that html table with no (visible) postbacks/reloads (if possible) and have it behave like it is dynamically refreshing the data.

What i have and what i am currently doing is the following: A Razor Html.TextBox(...) and a Javascript function that looks like this:

  $(function () {
        $('#txtSearchString').keyup(function () {
                  //Content to send
                  var searchvalue = $(this).val();
                  $.get('@Url.Action("Customers", "Home")', { "SearchValue": searchvalue });
                });
            });

Where 'txtSearchString' is the name/id of the Html.TextBox. When i type something in this txtbox, it goes to a HttpGet Action where i receive the 'searchvalue' and i query my database and return results matching my requirements. NOTE that this Action is the same action as the initial one that is loaded.

I than return my model (where this updated data resides), i can also clearly see when debugging that i have update results in my controller as well in my view when iterating over the list of results (ex, initial list contains 100 items, updated list contains 20) but still when the view is loaded, i am seeing the same results as initially loaded, it doesn't seem to upload the view in the browser.

I have no idea why this is so. I don't know if this is the best way of doing what i want to, i have no experience in Partial views and don't know if i better use that instead, but still whatever i end up using, i want to understand whats happening behind and resulting in this behavior.

If you have any question, need more clarification on anything, please ask me. Kind regards!

UPDATE:

This is how i populate/update my html table with the values from my model:

<table class="table table-hover trCursor">
<thead>
    <tr>
        <th scope="col">
            @Html.ActionLink("Id", "Customers", new { sortOrder = ViewBag.DateSortParm })
        </th>
        <th scope="col">
            @Html.ActionLink("Name", "Customers", new { sortOrder = ViewBag.NameSortParm })
        </th>      
        <th>...</th>

    </tr>
</thead>
@foreach (var customer in Model.Customers)
{
    <tr onclick="location.href='@(Url.Action("CustomerDetail", "Customer", new { Id = customer.ID }))'">

        @Html.HiddenFor(c => customer.ID)

        <td scope="row">@customer.ID</td>
        <td>@customer.CustomerName</td>
        <td>...</td>

    </tr>
}

Where i can see that "Model.Customers" has the updated values when iterating over it.

8
  • 1
    Your making an ajax call, but not doing anything with the data you return. You need to update the DOM in the success callback Commented Aug 27, 2018 at 8:13
  • 1
    Just do little modification after providing the data like this: $.get('@Url.Action("Customers", "Home")', { "SearchValue": searchvalue }, function(result) { // update DOM here }). Commented Aug 27, 2018 at 8:14
  • 1
    Note also that you will need to call a different method that returns just a partial view of what your want to update in the current view Commented Aug 27, 2018 at 8:16
  • 1
    If the action method simply has return PartialView(...), then using $('#targetElementId').html(result) will update previous DOM elements to new ones. Note that action methods for initial page load and to get search keyword should be separated. Commented Aug 27, 2018 at 8:21
  • 1
    Surround you @foreach in a <tbody id="xxx"> and then have a method that just returns your <tr> elements, and then $.get('@Url.Action(...)', { "SearchValue": searchvalue }, function(result) { $('#xxx').html(result); }) (and then you can also replace the @foreach with @Html.Partial("yourPartial", Model.Customers)) Commented Aug 27, 2018 at 9:11

1 Answer 1

1

When you use ajax (your $.get() function, you are making a call to a server method which in you case returns html, but you then need to do something with it - in your case, add it to the DOM in the `success callback.

Because you are only interested in updating the <tbody> in your view to display the filtered rows, your method should return a partial view of only that, so start by creating a partial, say _Customers.cshtl

@model IEnumerable<Customer>
@foreach(var customer in Model)
{
    <tr>
        ... // add <td> elements
    </tr>
}

and delete the @foreach (var customer in Model.Customers){ ... } code in the main view and replace with

<tbody id="customers">
    @{ Html.RenderPartial("_Customers", Model.Customers); }
</tbody>

Now create a separate controller method, say

public PartialViewResult FetchCustomers(string search)
{
    var customers = ... // your code to get Customers based on the search string
    return PartialView("_Customers", customers);
}

and modify the ajax call to update the table body in the success callback

var customers = $('#customers');
var url = '@Url.Action("Customers", "Home"';
$('#txtSearchString').keyup(function () {
    var searchValue = $(this).val();
    $.get(url, { search : searchvalue }, function(response) {
        customers.html(response);
    });
});

However, since you are initially displaying all Customers in the view, there is no need to make an ajax call in this case (and doing on each .keyup event will affect performance), since the data is already in the DOM. Instead you can just use javaScript to loop each row in the table body, and show or hide roes based on the search string. For a simple example, refer Filter table rows based on select value.

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

1 Comment

Again, thank you so much for this detailed, well explained solution and relevant information, you rock ;)

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.