3

I want to implement a live search on a web grid table which has pagination. However, my search only shows elements which are present in the actual page. I want my search function to do a search on all the element present in the table. Not only the ones actually displayed. Below is my search script:

<script type="text/javascript">
$(document).ready(function () {
    $("#filter").keyup(function () {

        // Retrieve the input field text and reset the count to zero
        var filter = $(this).val(), count = 0;
        console.log(filter);

        // Loop through each row of the table
        $("table tr").each(function () {

            // If the list item does not contain the text phrase fade it out
            if ($(this).text().search(new RegExp(filter, "i")) < 0) {
                $(this).fadeOut();

                // Show the list item if the phrase matches and increase the count by 1
            } else {
                $(this).show();
                count++;
            }
        });
        /* var numberItems = count;
        $("#filter-count").text("Number of Comments = "+count);*/
    });
});

my html page:

<div>
<div id="homeMessage">
    Please see below the list of books available.
</div>
<br />
<div id="divCurrentRented">
    <form id="live-search" action="" class="styled" method="post">
        <fieldset>
            <input type="text" class="form-control" id="filter" value="" placeholder="Search by title or author..."/>
            <span id="filter-count"></span>
        </fieldset>
    </form>
</div>
<br />
<div id="divCurrentRented">
@{
    WebGrid obj = new WebGrid(Model, rowsPerPage: 5);
}
@obj.Table(htmlAttributes: new
{
    id="tableCurrentRented",
    @class = "table"
},
headerStyle: "webgrid-header",
footerStyle: "webgrid-footer",
alternatingRowStyle: "webgrid-alternating-row",
rowStyle: "webgrid-row-style",
columns: obj.Columns(
    obj.Column("Title", header: "Title"),
    obj.Column("Author", header: "Author"),
    obj.Column("Avaible", header: "Available", canSort:false),
    obj.Column(header: "Rent", format:@<button type="button" class="btn btn-default">Rent it</button>)
))
</div>

<div style="text-align:right">
    @obj.Pager(mode: WebGridPagerModes.All)
</div>
<br />

Any idea of how to do this?

The HTML:

<table id="tableCurrentRented" class="table">
<thead>
    <tr class="webgrid-header">
        <th scope="col">
<a href="/AuthenticatedUser/SearchBooks?sort=Title&amp;sortdir=ASC">Title</a>            </th>
            <th scope="col">
<a href="/AuthenticatedUser/SearchBooks?sort=Author&amp;sortdir=ASC">Author</a>            </th>
            <th scope="col">
Available            </th>
            <th scope="col">
Rent            </th>
        </tr>
    </thead>
    <tbody>
        <tr class="webgrid-row-style">
            <td>Le Bossu de Notre Dame</td>
            <td>Victor Hugo</td>
            <td>Yes</td>
            <td><button type="button" class="btn btn-default" data-toggle="modal" data-target="#myModal" data-id="9" data-title="Le Bossu de Notre Dame">Yes</button></td>
        </tr>
        <tr class="webgrid-alternating-row">
            <td>Oliver Twist</td>
            <td>Charles Dickens</td>
            <td>Yes</td>
            <td><button type="button" class="btn btn-default" data-toggle="modal" data-target="#myModal" data-id="1" data-title="Oliver Twist">Yes</button></td>
        </tr>
        <tr class="webgrid-row-style">
            <td>Pride and Prejudice</td>
            <td>Jane Austen</td>
            <td>Yes</td>
            <td><button type="button" class="btn btn-default" data-toggle="modal" data-target="#myModal" data-id="5" data-title="Pride and Prejudice">Yes</button></td>
        </tr>
        <tr class="webgrid-alternating-row">
            <td>Sense and Sensibility</td>
            <td>Jane Austen</td>
            <td>Yes</td>
            <td><button type="button" class="btn btn-default" data-toggle="modal" data-target="#myModal" data-id="6" data-title="Sense and Sensibility">Yes</button></td>
        </tr>
        <tr class="webgrid-row-style">
            <td>The Mayor of Casterbridge</td>
            <td>Thomas Hardy</td>
            <td>Yes</td>
            <td><button type="button" class="btn btn-default" data-toggle="modal" data-target="#myModal" data-id="3" data-title="The Mayor of Casterbridge">Yes</button></td>
        </tr>
    </tbody>
    </table>

My controller method:

       public ActionResult SearchBooks()
    {
        var listBook = datamanager.GetAllBooks();
        List<ViewBook> listViewBook = new List<ViewBook>();
        foreach (Book b in listBook)
        {
            ViewBook viewBook = new ViewBook();
            viewBook.BookID = b.BookId;
            viewBook.Title = b.Title;
            viewBook.Author = b.Author;
            if (b.Rented ?? true)
            {
                viewBook.Avaible = "No";
            }
            else
            {
                viewBook.Avaible = "Yes";
            }
            listViewBook.Add(viewBook);
        }
        return View(listViewBook);
    }

I have succeeded in passing all the models of my list to the javascript:

var data = @Html.Raw(Json.Encode(Model));

However, when I do this:

$(data).each(function () {

to loop through each element of data, I get this error:

Cannot use 'in' operator to search for 'opacity' in undefined

Any idea how I can solve this?

refresh
  • 1,319
  • 2
  • 20
  • 71
  • can you provide rendered html? – Rakin Oct 28 '15 at 14:23
  • @Rakin: Just added it – refresh Oct 29 '15 at 04:41
  • from the rendered html is looks like it shows only paged data. so when a filter applied in client side reflects only with data available in client . Just Call a ajax function to retrieve filtered data – Rakin Oct 29 '15 at 09:50
  • @Rakin: How can I do that? I have added my controller method in the question. – refresh Oct 29 '15 at 10:28
  • please see my answer – Rakin Oct 29 '15 at 11:51
  • I will try your answer. However, I think I have found another way. But an error is blocking me. Can you please see through it? I have added the updates in the question. – refresh Oct 29 '15 at 11:55
  • $.each(data,function (index, item) { }); try this – Rakin Oct 29 '15 at 11:57
  • I have tried your solution, but when I get to the line: if ($(item).text().search(new RegExp(filter, "i")) < 0), I get this error: Uncaught TypeError: Cannot use 'in' operator to search for 'opacity' in undefined. – refresh Oct 30 '15 at 05:20

2 Answers2

1

It seems you have a "Model" variable holding the data. Perhaps you should consider filtering the data in this Model directly and passing the filtered Model to the webgrid. The problem, how I understand it, is that you're trying to fetch already rendered values rather than considering the entire collection of data before rendering the filtered data.

Armin Taheri
  • 72
  • 1
  • 8
1

Javascript

       $("#filter").keyup(function () {  
    $.ajax({
        type: "GET",
        contentType: "application/json; charset=utf-8",
        dataType: "json",            
        url: 'Search?q='+$("#filter").val(),
        success:
            function (result) {                  
                $("#tableCurrentRented tbody").empty();
                $.each(result.Books, function (index, item) {
                    var cls=(index%2==0)?"webgrid-row-style":"webgrid-alternating-row";
                    var html = ' <tr class="'+cls+'">'+
        '<td>'+item.Title  +'</td>'+
        '<td>'+item.Author  +'</td>'+
        '<td>'+item.Avaible  +'</td>'+
       ' <td><button type="button" class="btn btn-default" data-toggle="modal" data-target="#myModal" data-id="'+item.BookID +'" data-title="'+item.Title+'">'+item. +'</button></td></tr>';
                    $("#tableCurrentRented tbody").append(html);
                });                   
            },
        error: function (xhr, status, err) {          
        }
    });
});

Add new method for searching in controller

public ActionResult Search(string q)
    {
        var listBook = datamanager.GetAllBooks().Where(X=> X.Title.Contains(q)).ToList();
        List<ViewBook> listViewBook = new List<ViewBook>();
        foreach (Book b in listBook)
        {
            ViewBook viewBook = new ViewBook();
            viewBook.BookID = b.BookId;
            viewBook.Title = b.Title;
            viewBook.Author = b.Author;
            if (b.Rented ?? true)
            {
                viewBook.Avaible = "No";
            }
            else
            {
                viewBook.Avaible = "Yes";
            }
            listViewBook.Add(viewBook);
        }
        return Json(new { Books = listViewBook }, JsonRequestBehavior.AllowGet);
    }
Rakin
  • 1,271
  • 14
  • 30
  • No, this does not work either. It actually searches all elements which contains the first alphabet entered. – refresh Oct 30 '15 at 05:31
  • datamanager.GetAllBooks().Where(X=> X.Title.Contains(q)).ToList() to datamanager.GetAllBooks().Where(X=> X.Title.StartWith (q)).ToList() Or datamanager.GetAllBooks().Where(X=> X.Title.EndWith(q)).ToList() – Rakin Oct 30 '15 at 05:53
  • No this does not work. If I search for example 'Tom', it will not give me the book Tom Sawyer. What I want to do is a live search, without going in the controller, on a paginated table. – refresh Oct 30 '15 at 07:28
  • merge your thoughts and my thoughts ... then it will lead you to solution – Rakin Oct 30 '15 at 07:30
  • The part you are doing in the controller, I want to do it in javascript. – refresh Oct 30 '15 at 07:34