How to return a partial view in a controller in ASP.NET MVC3? - asp.net-mvc-3

I have a controller and one of its methods (actions) access my database of items. That method checks the item type. How do I show my partial view only if the item retrieved from my database is of a specific type?
Controller Action example:
public ActionResult CheckItem(Koko model)
{
var item = db.Items.Where(item => item.Number == model.Number).First();
if(item.Type=="EXPENSIVE")
{
//show partial view (enable my partial view in one of my Views)
}
}

You could return a PartialView action result:
public ActionResult CheckItem(Koko model)
{
var item = db.Items.Where(item => item.Number == model.Number).First();
if (item.Type=="EXPENSIVE")
{
return PartialView("name of the partial", someViewModel);
}
...
}
Now the controller action will return partial HTML. This obviously means that you might need to use AJAX in order to invoke this controller action otherwise you will get the partial view replace the current browser window. In the AJAX success callback you could reinject the partial HTML in the DOM to see the update.

Related

Partial View HttpPost invoked instead of HttpGet

I'm working on the admin part of an MVC webapp. I had the idea to use "widgets" for a single Admin panel. I'll explain my intentions first.
I have a languages table, and for that I'd like to create a partial view with a dropdownlist for those languages and a single button "Edit", that would take the user to a non-partial view to edit the language. After clicking save, the users would be redirected to the Index view, which would just show the dropdownlist again.
So I have a "Index.cshmtl", and an "EditLanguage.cshtml" as non-partial views, and a "LanguageWidget.cshtml" as a partial view.
First the user sees the Index view.
public ViewResult Index()
{
return View();
}
This view has the following code in it:
#using CodeBox.Domain.Concrete.ORM
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Administration</h2>
#Html.Action("LanguageWidget")
The Partial view "LanguageWidget" just contains the following code, and when the user submits it posts to the HttpPost annotated method in my controller:
#using (Html.BeginForm("LanguageWidget", "Admin"))
{
#Html.DropDownListFor(model => model.SelectedItem, Model.Languages)
<input type="submit" value="Edit"/>
}
This is the HttpPost method for the widget:
[HttpPost]
public ActionResult LanguageWidget(LanguageWidgetModel model)
{
var lang = langRepo.Languages.FirstOrDefault(l => l.LanguageId == model.SelectedItem);
return View("EditLanguage", lang);
}
This takes the user to the language edit page, which works fine.
But then! The user edits the language and submits the page, which invokes the "EditLanguage" HttpPost method, so the language is saved properly.
[HttpPost]
public ViewResult EditLanguage(Language model)
{
if (ModelState.IsValid)
{
langRepo.SaveLanguage(model);
TempData["message"] = string.Format("{0} has been saved!", model.Name);
return View("Index");
}
else
{
return View(model);
}
}
So, when I return the "Index" view - which seems logical I guess - the controller still assumes this is a HttpPost request, and when it renders the Index view, it invokes the "LanguageWidget" method, assuming it has to render the HttpPost method.
This leads to the LanguageWidget HttpPost method, which returns a full view with layout, returning just that, so I have my layout, with view, containing a layout, with the editview.
I don't really see how I could fix this?
I'm pretty sure it's a design flaw from my part, but I can't figure it out.
Thanks in advance!!
Consider using:
return RedirectToAction("Index")
instead of:
return View("Index");
It might seem more logical if the user is actually redirected to Index instead of
remaining at the EditLanguage. And if the user hits the refresh button no data will be resent using this approach.

How to pass the full Model from view to controller via jquery in a MVC c# application

I have a list of checkbox's and textbox's. I want to let the user add items to the list via a partial view modal popup.
After the user adds an item to the list, if any items on the original view have values in them, I want them preserved, and the page refreshed with the added items.
I want to send the full model back to the controller from the original view, I can then just add the new items to that model and pass the model back to the original page and have all my values preserved.
I could grab all the values and pass them via loops and such in javascript (very tedious), but I think the full model would be the easiest way.
I sawe a link from Laviak on a post from here..., but I can't get it to work.
it states....
If you need to send the FULL model to the controller, you first need the model to be available to your javascript code.
In our app, we do this with an extension method:
public static class JsonExtensions
{
public static string ToJson(this Object obj)
{
return new JavaScriptSerializer().Serialize(obj);
}
}
On the view, we use it to render the model:
<script type="javascript">
var model = <%= Model.ToJson() %>
</script>
You can then pass the model variable into your $.ajax call.
Has anyone got this to work???
Thanks
Bill
you can do something like this:
<script type="text/javascript">
var dataViewModel = #Html.Raw(Json.Encode(Model)); //Make sure you send the proper model to your view
function MethodPost(param1, param2, etc...) {
dataviewModel.Param1 = param1; //Or load a value from jQuery
dataviewModel.Param2 = $("#param2").val();
}
//Pass it to a controller method
$.post("#Url.Action(MVC.Home.PostMethodInController())", { viewModel: JSON.stringify(dataViewModel)} , function(data) {
//Do something with the data returned.
}
</script>
In the controller you get your class/model using Json.Net which is available on nuget.
public virtual ActionResult Index()
{
return View(new MyModelToView());//Send at least an empty model
}
[HttpPost]
public virtual JsonResult PostMethodInController(string viewModel)
{
var entity = JsonConvert.DeserializeObject<MyObject>(viewModel);
//Do Something with your entity/class
return Json(entity, JsonRequestBehavior.AllowGet);
}
Hope this helps.

MVC3/Razor to Controller Ajax call

I have a Razor view with a couple of dropdown lists. If the value of one of the dropdown's is changed I want to clear the values in the other drop down and put new ones in. What values I put in depends on the values in the model that the view uses and that is why I need to send the model back from the view to the controller. The controller will then also need to be able to modify the dropdown by sending back data to the view. Note, that I am not saying that I want to go back to the controller from a form submit using Ajax. I am going back to the controller using a form submit, but not using Ajax.
Please can someone give me some simple code or some pointers to show how this might be done.
Thanks
I personally use ViewBag & ViewData to solve this condition.
Controller:
public ActionResult Index()
{
ViewBag.dd1value = default_value;
ViewBag.dd1 = DropDownlist1();
ViewBag.dd2 = DropDownlist2(dd1value);
Return View();
}
View:
In the first dropdownlist add an onchange javascript.
<select onchange="javascript:this.form.submit();">
#foreach (var item in ViewBag.dd1) {
if (ViewBag.dd1value = item.dd1value)
{
<option selected value="#item.dd1value">#item.dd1text</option>
}
else
{
<option value="#item.dd1value">#item.dd1text</option>
}
}
Then, on submit button give it a name.
<input type="submit" name="Genereate" value="Generate" />
In the controller, create 2 ActionResult to receive data.
For dropdownlist:
[HttpPost]
public ActionResult Index(int dd1value)
{
ViewBag.dd1value = dd1value;
ViewBag.dd1 = DropDownlist1();
ViewBag.dd2 = DropDownlist2(dd1value);
Return View();
}
For submit button:
[HttpPost]
public ActionResult Index(int dd1value, int dd2value, FormCollection collection)
{
ViewBag.dd1value = dd1value;
ViewBag.dd2value = dd2value;
ViewBag.dd1 = DropDownlist1();
ViewBag.dd2 = DropDownlist2(dd1value);
ViewBag.result = Result(dd1value, dd2value);
Return View();
}
If you don't need button:
[HttpPost]
public ActionResult Index(int dd1value, int dd2value)
{
ViewBag.dd1value = dd1value;
ViewBag.dd2value = dd2value;
ViewBag.dd1 = DropDownlist1();
ViewBag.dd2 = DropDownlist2(dd1value);
ViewBag.result = Result(dd1value, dd2value);
Return View();
}
Please note that if you use ViewBag / ViewData, all the help you get from the compiler is disabled and runtime errors/bugs will occur more likely than if the property has been on a "normal" object and typos would be catched by the compiler.
I would implement a different solution from DragonZelda.
I would create a ViewModel object containing the data that you need on the page, that the View binds to.
Then, I would create controls that bind to that Model, like:
#Html.DropDownListFor(x => x.SomeDDLSelected, ......)
x.SomeDDLSelected would be a property in your ViewModel object that would automatically get the selected value in the dropdownlist when the automatic model binder gets in action.
Then, to finalize it, the Controller action would receive your ViewModel object as a parameter:
public ActionResult MyAction(MyViewModelObject obj)
{...}
And you get all your data nice and tidy, all strong typing.

Refreshing parent view when a partial view's form is submitted

I'm looking into using partial views in MVC3 using Razor, and I get my partial view to render and it works fine.
What I'd like to do, though, is refresh the parent view when the partial view is submitted.
Code in my parent view to render partial view
<div id="mydiv">
#{ Html.RenderAction("Add", "Request"); }
</div>
Action for parent view is simple,
public ActionResult Index()
{
List<obj> reqs = //some query
return View(reqs);
}
In my partial view's get action I have:
public ActionResult Add()
{
AddRequestViewModel vm = new AddRequestViewModel();
//set some stuff on the VM here
return PartialView(vm);
}
In the post action called by the partial view, if modelstate isn't valid, return PartialView(vm)
If it is valid, I'd like the parent and partial views to refresh.
I tried RedirectToAction, but this can't be called in an action called by a partial, apparently, and I tried return Index();, but this causes an issue with the code used to render the partial view,
Exception Details: System.InvalidOperationException: The model item passed into the dictionary is of type 'System.Collections.Generic.List'1[DatRequests.Models.ReqRequest]', but this dictionary requires a model item of type 'DatRequests.ViewModels.AddRequestViewModel'.
Any suggestions on how to do this would be appreciated. The purpose of the page is to show a list of elements, and the partial contains a form to add a new element to the list.
Edit: The partial's model is different, as it contains data for selection, which is from a db, which is why I tried RenderAction, but I'm not sure if there are other ways of doing this.
When the partial view is submitted normally you submit it to some controller action. You could either submit it using a normal request or an AJAX request. If you use a normal request you could perform a standard redirect to the Index inside the POST controller action that will handle the form submission. If you use AJAX, you could return a JSON result pointing to the url that you want to redirect:
[HttpPost]
public ActionResult Foo(MyViewModel model)
{
if (!ModelState.IsValid)
{
return PartialView(model);
}
return Json(new { url = Url.Action("Index") });
}
and inside your AJAX success callback:
success: function(result) {
if (result.url) {
// we have a success
window.location.href = result.url;
} else {
// invalid modelstate => refresh the partial
$('#mydiv').html(result);
}
}
Probably RenderAction should not be used this way.
When using Html.RenderAction, a new/seperate request would be sent to the server. And you got another chance to load some data from db or somewhere else to display to the client. Also, you could apply OutputCache to this action. this is usually the way doing global cache.
Here you are doing a POST to the server. Either directly put a element here or using a partial view to do the Post. And in the corresponding action, do a RedirectToAction.
Do it with ajax or not isn't the point. my opinion is more about the right way using RenderAction

Calling another Controller post method

I am using ASP.NET MVC 3 for my website.
I have created a partial view that has "Previous, Next and Save" buttons. I am calling this partial view on my master page.
My requirement is that on what ever View I am I must be able to call different Save methods in different controllers by passing respective Model data to controller actions.
Example
I have 4 step data input, I have a different controller for each step.
If i am on step 1 and i click Save the form Values should go to Step1Controller's action method,
If I am on step 2 then post should call Step2Controller
Something like this this:
public ActionResult Save(GenericModel model)
{
//use reflection to find out model type
//call appropriate controller action with model
return RedirectToAction("Create", new { Controller = "Conference", Action = "Create" });
}
This save method will be called for Save button on the Master page. How can I achieve this?
Are the forms on separate actions on the controllers?
If so, just set the form action on each page to point to the relevant controller. So form 1 is
<form method="post" action="/step1controller/action">
Form 2 is:
<form method="post" action="/step2controller/action">
Does that solve your problem?
I would create a private method in the controller and call in every part of the first steps.
private bool Save(GenericModel model)
{
......
}
[HttpPost]
public bool SaveStep1(GenericModel model)
{
this.Save(model);
}
[HttpPost]
public bool SaveStep2(GenericModel model)
{
this.Save(model);
}

Resources