Show a Message in MVC using TempData - asp.net-mvc

i want to show a message in asp.net mvc. for this, i create a partial view. name of this partial view is _feedback. in body of this partial view i write this codes.
#model MyProject.SharedTools.OperationStatus
#if (Model != null)
{
if (Model.IsSuccess)
{
#:Model.Message;
}
else
{
#:Model.Message;
}
}
i put this code in _layout file:
#Html.Partial("_feedback")
and when i want to see a message from controller, using this code:
operationStatus = _provinceRepository.Save();
if (operationStatus.IsSuccess)
{
TempData["OperationStatus"] = operationStatus;
return RedirectToAction("Index");
}
but i give this error:
The model item passed into the dictionary is of type 'MyProject.Models.ProvinceModel', but this dictionary requires a model item of type 'MyProject.SharedTools.OperationStatus'.

Make sure that you have passed the correct model that your partial is expecting:
#Html.Partial("_feedback", Model.SomePropertyOfTypeOperationStatus)
If you do not specify a model as second argument to the Html.Partial helper, then it will automatically pass the model of the current view (which in your case is of type MyProject.Models.ProvinceModel) and that's why you are getting the error : your partial expects a model of type MyProject.SharedTools.OperationStatus.
Also it is not quite clear where you are using the TempData value that you stored in your controller inside your partial. Maybe it should be something like this:
#model MyProject.SharedTools.OperationStatus
#if (Model != null)
{
#TempData["OperationStatus"]
}
or didn't you just mean to display directly the value you stored in TempData in your partial without using a model?
#TempData["OperationStatus"]

Related

How can I send a parameter to partial view without the need of a model?

I have a partial view in my MVC app which I load into a container dom element. I do this by first calling the controller, like so:
$(container).load('/xxx/GetPartialView');
In the controller I return the partial view:
public PartialViewResult GetPartialView()
{
return PartialView("SomePartial", null);
}
This works just fine. However, I would like to send a parameter (just a simple string value) along from the controller to the partial view I'm creating. This I understand, can be done by the use of a model, like for example:
public PartialViewResult GetPartialView(string someValue)
{
return PartialView("SomePartial", new SomeDummyModel(someValue));
}
But I would like to avoid the model instance if possible, as it seems like a lot of overhead. I want to just send the string value as a parameter. Is that possible?
Instead of passing a custom class such as SomeDummyModel you can simply pass someValue. Assuming that someValue is string from your explanation, that would mean you would accept string in the #model of your partialView.
controller
public PartialViewResult GetPartialView(string someValue)
{
return PartialView("SomePartial", someValue);
}
partial
#model string
<div>Hello, #Model :)</div>
You can also use the ViewData object to pass simple items like that.
public PartialViewResult GetPartialView()
{
ViewData["someValue"] = "hello";
return PartialView("SomePartial", null);
}
And then in the view access it:
<div>#ViewData["someValue"].ToString() :)</div>
This works without a model.
You can put pretty much anything into the ViewData object, you just need to cast it out

ViewBag In ASP.NET MVC

I am passing my model errors via the ViewBag. In my controller I am passing a List<string> that does contain values (_modelErrors) to the ViewBag and then I am trying to display this in my view. When I debug in the view, my ViewBag does contain a _modelErrors dictionary with values, but my errors are not being rendered.
From my controller:
ViewBag._modelErrors = _modelErrors;
In my view I have tried all of these methods and yet no markup is rendered.
#try
{
foreach (string er in ViewBag._modelErrors)
{
Response.Write(er.ToString());
#Html.DisplayText(er)
#Html.DisplayText(er.ToString())
#er.GetType()
#er.ToString();
er.ToString();
}
}
catch(Exception e){}
That's a dirty code, dude! Take a look at #Html.ValidationSummary and #Html.ValidationMessageFor
Well, some codes here to clarify stuff:
[HttpPost]
public ActionResult MyAction(ModelClass inputModel)
{
if (ModelState.IsValid)
{
//for example we're trying to save our data to db
var result = _myRepository.saveStuff(inputModel);
if (result)
return RedirectToAction("someAction");
ModelState.AddModelError(string.Empty, "An error occured, check input data");
}
return View(inputModel);
}
Also you can specify key (which is your model field name) instead of string.Empty -> so you'l see error message under specified field (as default), but basically what people do is exluding property errors from validation summary (#Html.ValidationSummary(true)) - so you get just general errors in that field. Hope it'l help
Use this:
(string er in (List<string>)(ViewBag._modelErrors))
But was said this is bad practice. Also catching exceptions this way is so wrong...

Partialview result returns null

Partial view does not return any data.When i check with debug tool on PartialView page(_ContentBlock.cshtml), model seem to null.
Controller
public ActionResult Module()
{
int RouteDataValue = default(int);
if (RouteData.Values["id"] != null)
{
RouteDataValue = int.Parse(RouteData.Values["id"].ToString());
}
using (Models.ContentModel db = new Models.ContentModel())
{
var Query = from n in db.PageModule
join m in db.Module on n.ModuleId equals m.ModuleId
where n.PageId == RouteDataValue
select m.PhysicalPath;
return PartialView(Query.Single()); //returns PartialView such as ~/Modules/Content/_ContentBlock.cshtml
}
}
public PartialViewResult ContentBlock()
{
using (Models.ContentModel db = new Models.ContentModel())
{
return PartialView("~/Modules/Content/_ContentBlock.cshtml", db.ContentBlock.Where(n => n.PageId == 2).Single());
}
}
Page.cshtml
#Html.Action("Module")
_ContentBlock.cshtml
#model IEnumerable<Models.ContentBlock>
#foreach (var item in Model)
{
#Html.DisplayFor(n => item.Content)
}
You seem to have used the Html.Partial helper instead of Html.Action. So you were basically only rendering the partial without ever hitting the controller action that is supposed to populate and the model to the partial.
Your page Page.cshtml is calling the partial view action Module using:
#Html.Action("Module")
The action called Module is being executed. In that action, your query results in a path to your view, such as:
"~/Modules/Content/_ContentBlock.cshtml"
That action is returning the single result of that query using:
return PartialView(Query.Single());
What this is doing is passing the name of the view to the PartialView method to return which view is going to be used to display data from the action. In addition, no model data is included in this return.
That's where your problem is. When you return the path to the partial view, you are simply telling the MVC system what view to use to display the data from Module. It won't actually call another partial view. That's not how it works. So your model is null because, you didn't pass any data in your PartialView(...) call.
You have another action called ContentBlock. But that action is not being called because nothing is calling it.
Edit:
Another problem you have is that _ContentBlock.cshtml uses a model of IEnumerable<ContentBlock>, but you're only passing it a .Single() from your ContentBlock action.

Why does creating a new ViewModel return the same data as the old ViewModel?

I'm just learning MVC3 now and this is really confusing me.
I have a ViewModel that contains some child ViewModels. Each of the ChildViewModels get rendered with a different Partial View, and when submitting execute a different action on the Controller. All the ChildViewModels should perform some custom validation on their data, and if successful it should move on to the next page. If the validation fails, it should simply return to the ParentView and display the errors.
[HandleError]
public class MyController: Controller
{
public ActionResult Index()
{
var viewModel = new ParentViewModel();
return View("ParentView", viewModel);
}
[HttpPost]
public ActionResult ChildViewModelB_Action(ChildViewModelB viewModel)
{
if (ModelState.IsValid)
{
return View("ChildViewModelB_Page2", viewModel);
}
else
{
// I'm having trouble returning to the ParentView and
// simply displaying the ChildViewModel's errors, however
// discovered that creating a new copy of the VM and displaying
// the ParentView again shows the existing data and any errors
// But why??
var vm = new ParentViewModel();
return View("ParentView", vm);
}
}
}
For example,
The page loads with 3 options.
User selects option B and fills out a form.
Upon submit, the child ViewModel B gets validated and fails.
Page returns to ParentView, with ChildB all filled out, however ChildB errors are now also showing.
Why does creating a new copy of the ParentViewModel display the ParentView with the same data as the original ParentViewModel?
And is there a different way I should be returning to the ParentView after doing server-side validation?
You need to clear the modelstate if you intend to modify values in your POST action
else
{
ModelState.Clear();
var vm = new ParentViewModel();
return View("ParentView", vm);
}
The reason for that is because Html helper such as TextBoxFor will first look in the modelstate when binding their values and after that in the model. And since the modelstate already contains the POSTed values, that's what's used => the model is ignored. This is by design.
This being said the correct thing to do in your case is to simply redirect to the GET action which already blanks the model and respect the Redirect-After-Post pattern:
else
{
return RedirectToAction("Index");
}
Why does creating a new copy of the ParentViewModel display the
ParentView with the same data as the original ParentViewModel?
Because the values of the fields are retrieved from the POSTed form and not from the model. That makes sense right? We don't want the user to show a form filled with different values from what they submitted.

Can I add a ModelState.AddModelError from a Model class (rather than the controller)?

I want to display an error to the user in an ASP.MVC 3 input form using ModelState.AddModelError() so that it automatically highlights the right field and puts the error next to the particular field.
In most examples, I see ModelState.AddModelError() and if(ModelState.IsValid) placed right in the Controller. However, I would like to move/centralize that validation logic to the model class. Can I have the model class check for model errors and populate ModelState.AddModelError()?
Current Code:
// Controller
[HttpPost]
public ActionResult Foo(Bar bar)
{
// This model check is run here inside the controller.
if (bar.isOutsideServiceArea())
ModelState.AddModelError("Address", "Unfortunately, we cannot serve your address.");
// This is another model check run here inside the controller.
if (bar.isDuplicate())
ModelState.AddModelError("OrderNumber", "This appears to be a duplicate order");
if (ModelState.IsValid)
{
bar.Save();
return RedirectToAction("Index");
}
else
return View(bar)
}
Desired Code:
// Controller
[HttpPost]
public ActionResult Foo(Bar bar)
{
// something here to invoke all tests on bar within the model class
if (ModelState.IsValid)
{
bar.Save();
return RedirectToAction("Index");
}
else
return View(bar)
}
...
// Inside the relevant Model class
if (bar.isOutsideServiceArea())
ModelState.AddModelError("Address", "Unfortunately, we cannot serve your address.");
if (bar.isDuplicate())
ModelState.AddModelError("OrderNumber", "This appears to be a duplicate order");
If you are using MVC 3, you should checkout IValidatableObject, it's what you're after.
Scott Gu mentions it in his MVC3 Intro blog posting.
You can do something like this using custom data annotations or using RuleViolations like what they did in the NerdDinner example.
Perhaps you could create an error interface like IErrorHandler and pass that into a public method called Validate on you model class assuming its a partial class and you can seperate your data model from your rules.
With the interface you could create a class in your contoller that wraps the ModelState error handler. So the inteface might have AddError and in that metghod tou just delegate to your local modelstate.
So your method might be something like:
IErrorHandler errorHandler = CreateErrorHandler();
model.Validate(errorHandler);
if(errorHandler.IsValid())
... do something
You would use custom validation via the IValidatableObject interface on your model.
Custom validation example
If you're after least amount of code, a hacky way of doing it is to stuff that message into the Session from your View Model, then add that message from your Controller, for example:
// In Model (or elsewhere deep inside your app):
string propertyName = "Email";
string errorMessage = "This is the error message, you should fix it";
Session["DeepModelError"] = new KeyValuePair<string, string>(propertyName, errorMessage);
// In Controller
var model = new LoginModel();
if (Session["DeepModelError"] != null)
{
var deepError = (KeyValuePair<string, string>)Session["DeepModelError"];
if (deepError.Key == "Email" || deepError.Key == "Password")
{
ModelState.AddModelError(deepError.Key, deepError.Value);
Session["DeepModelError"] = null;
}
}
Let me reiterate that I realize that this is kind of hacky, but it's simple and it gets the job done...

Resources