0

I'm implementing sorting for a table in my view, where it gets populated through ajax calling JsonResult method this is the header link I use for ordering:

<a style="cursor: pointer" onclick="getData('@Html.Raw(ViewBag.Sort == "asc" ? "desc" : "asc")')" id="sort">Title</a>

the JsonResult method:

public JsonResult BooksData(string sort)
{
    ViewBag.Sort = ViewBag.Sort == "desc" ? "asc" : "desc";
    var books = new List<Book>();
    if (sort == "asc")
    {
        books = db.Books.Include(b => b.Author).OrderBy(b => b.Title).ToList();
        ViewBag.Sort = "desc";

    }
    else
    {
        books = db.Books.Include(b => b.Author).OrderByDescending(b => b.Title).ToList();
        ViewBag.Sort = "asc";

    }
    return Json(books, JsonRequestBehavior.AllowGet);
}

the getsData function:

function getData(sort) {
            var srt = sort;
            $('#tbl>tbody').empty();

            $.ajax({
                type: 'GET',
                url: '/Book/BooksData?sort=' + srt,
                dataTtype: 'json',
                success: function (data) {
                    $.each(data, function (index, val) {
                        $('#tbl>tbody').append('<tr><td>' + val.Title + '</td><td>' + val.Author.Name + '</td></tr>')
                    });
                }
            });
        }

but the value of ViewBag.Sort is always asc?

mshwf
  • 7,009
  • 12
  • 59
  • 133
  • `ViewBag.Sort = sort == "desc" ? "asc" : "desc";` –  Dec 15 '16 at 23:47
  • The first line of code - the value of the RHS `ViewBag.Sort` is always `null` (you have not set it yet) so the value of the LHS `ViewBag.Sort` is always `desc` and then your `else` block sets it to `asc` –  Dec 15 '16 at 23:51
  • This sounds correct and logical, but it still always `asc`, doesn't change! – mshwf Dec 15 '16 at 23:52
  • Why are you also reversing it again in the `onclick()` in your view. Bit hard to understand what your wanting to do here –  Dec 15 '16 at 23:54
  • I removed this part to be `getData('@ViewBag.Sort')` but when I click the link the `sort` value becomes empty `""` – mshwf Dec 15 '16 at 23:58
  • Am I correct in assuming you want to click on a link and reverse the order of the rows in a table (i.e. sorted by `Title`) aach time you click the link? And why call a server to do this as opposed to just using client side code (all the data is already in the view) –  Dec 16 '16 at 00:04
  • I'm coding as much I know now, with little knowledge of JS so I used `ViewBag` – mshwf Dec 16 '16 at 00:09
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/130743/discussion-between-stephen-muecke-and-mohamed-ahmed). –  Dec 16 '16 at 00:09

1 Answers1

1

There are numerous issues with your code. First @Html.Raw(ViewBag.Sort == ...) is razor code and is evaluated on the server before the view is sent to the client so your generating

<a style="cursor: pointer" onclick="getData("asc")" id="sort">Title</a>

or getData("desc") depending on the value of ViewBag.Sort in the GET method that initially generated the view. No where do you ever change it so you ajax call always submits the same value for the parameter sort.

Then in the BooksData() method, you have logic errors (although they ultimately do not matter). Because you have not previous set a value for ViewBag.Sort, then

ViewBag.Sort = ViewBag.Sort == "desc" ? "asc" : "desc";

evaluates to

ViewBag.Sort = null == "desc" ? "asc" : "desc";

so the value of ViewBag.Sort is always "desc" which your else block then resets to "asc".

But your method returns a JsonResult, not a view, so the ViewBag value is then lost and its value is never returned to the client.

Change your code in the view to

<a href="#" style="cursor: pointer" id="sort">Title</a>

and assign the initial value of ViewBag.Sort to a javascript variable so it can be toggled each time you click the link

var currentSort = '@Html.Raw(ViewBag.Sort)'
var url = '@Url.Action("BooksData", "Book")';
// handle the click event of the link
$('#sort').click(function() {
    // toggle the value
    currentSort  = currentSort == 'acs' ? 'desc' : 'asc';
    $('#tbl>tbody').empty();
    $.getJSON(url, { sort: currentSort }, function(data) {
        $.each(data, function (index, val) {
            .... // append table rows
        });
    });
});

and the controller method is then

public JsonResult BooksData(string sort)
{
    if (sort == "asc")
    {
        var books = db.Books.Include(b => b.Author).OrderBy(b => b.Title); // no need for .ToList()`
        return Json(books, JsonRequestBehavior.AllowGet);
    }
    else
    {
        var books = db.Books.Include(b => b.Author).OrderByDescending(b => b.Title);
        return Json(books, JsonRequestBehavior.AllowGet);
    }
}

Note that you can do the 'sorting' on the client without the extra overhead of making call to the server by simply re-ordering the rows in the table using javascript/jquery - refer Invert table rows for an example, although that means that any new records added to the database by other users after the view is first generated would not be updated in the view.

Community
  • 1
  • 1
  • But can multiple columns be ordered using jQuery too, as the answer you referred to just reverse the rows? – mshwf Dec 16 '16 at 10:45
  • 1
    Yes, but its gets a bit more complex and you need to use the `.sort()` function. The answers to [How to sort an array of objects by multiple fields?](http://stackoverflow.com/questions/6913512/how-to-sort-an-array-of-objects-by-multiple-fields) will give you a starting point. –  Dec 16 '16 at 10:50