dgarbacz dgarbacz - 15 days ago 4
C# Question

Toast notifications in ASP.NET MVC

I'm using the Toastr notification plugin in my MVC application to display status messages (successful edit, update, delete, etc), and I'm wondering if there is an easy way to put some logic in a Partial view and have it on my Layout or in each individual view where needed.

Partial



<script type="text/javascript">
$(document).ready(function () {
@if (ViewBag.Success == true) {
@:toastr.success("@ViewBag.Message");
} else if (ViewBag.Success == false) {
@:toastr.error("@ViewBag.Message");
}
});
</script>


View



//Doesn't work
@Html.Partial("_ToastPartial")

//Tried this directly in the view instead of using the partial, didn't work
@if (ViewBag.Success == true) {
@:toastr.success("@ViewBag.Message");
} else if (ViewBag.Success == false) {
@:toastr.error("@ViewBag.Message");
}


Controller



public ActionResult SomethingAwesome(MyViewModel model)
{
ViewBag.Success = true;
ViewBag.Message = "Employee successfully added";

return RedirectToAction("Index");
}


This doesn't work. Is it possible to wrap something like this in a partial or does MVC strip out the
<script>
tags? Can I render the partial within a script block on the View?

I even tried to move the code within the script tags directly to the View and then setting the values on the Controller and it seems like nothing is happening.

Any help? Is the ViewBag cleared by the time the view is rendered again? Should I use TempData? Can I move a
Success
and
Message
property into my ViewModel and just pass that into my View like this?

public ActionResult Index(MyViewModel model)
{
//Do something with model.Success
}


My Solution



I used a couple of answers to come to a final conclusion for this section of my site, and will most likely use the method for the accepted answer in other parts.

I went and added the following to my ViewModel

public bool Success { get; set; }
public string Message { get; set; }


I have the Action return the Index view with the ViewModel, after properties have all been set

//fetch the updated data and shove into ViewModel here
viewModel.Success = true;
viewModel.Message = "Employee successfully checked in";

return View("Index", viewModel);


And then just use the Razor syntax in my View

@if (Model.Success) {
@:toastr.success("@Model.Message");
} else if (!Model.Success && !String.IsNullOrWhiteSpace(Model.Message)) {
@:toastr.error("@Model.Message");
}


Also as a bonus (although implementation seems sloppy), render the Partial in my document.Ready block

@Html.Partial("_ToastPartial", Model)


and move the Toastr notification code to the partial

@if (Model.Success) {
@:toastr.success("@Model.Message");
} else if (!Model.Success && !String.IsNullOrWhiteSpace(Model.Message)) {
@:toastr.error("@Model.Message");
}


Most likely I would set up an interface with the
Message
and
Success
properties and make any ViewModels that will use the partial implement that interface

Answer

Your controller is performing a RedirectToAction. The ViewBag and ViewData only survives the current request. TempData is the thing to use when you use redirects (and only then):

http://rachelappel.com/when-to-use-viewbag-viewdata-or-tempdata-in-asp.net-mvc-3-applications states this clearly:

[...] the TempData object works well in one basic scenario:

  • Passing data between the current and next HTTP requests