Can I exchange data between view and JsonResult method using ViewBag?

947 views Asked by At

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?

1

There are 1 answers

2
AudioBubble On BEST ANSWER

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.