Partial view returns the Model with empty fields - asp.net-mvc-3

In a web application using ASP.NET MVC 3, I pass from the controller a model with initialized properties as parameter to a partial view.
The view displays a dialog with a single textbox and on submit an action in the starting controller is fired (the action takes the same model type as parameter). The problem is that at this point only the property relative to the textbox field has a value, the one inserted by the user, while all the others are null, even if in the view they had a proper value.
How can I do in order to keep the properties from the view to controller once the submit button is clicked?
EDIT (added code):
//---------- This method in the controller call the Partial View and pass the model --------
[HttpPost]
public PartialViewResult GetAddCustomFormerClubDialog()
{
var order = GetCurrentOrder();
//Order has here all properties initialized
var dialogModel = new dialogModel<Order> { Entity = order, ControllerAddEntityActionName = "SelectOrder"};
return PartialView("Dialogs/AddOrder", dialogModel);
}
//----------------- Here the Partial View -----------------------------------
#model FifaTMS.TMS.Presentation.Model.Wizard.WizardDialogModel<Club>
<div>
#using (Ajax.BeginForm(Model.ControllerAddEntityActionName, "Orders", new AjaxOptions { HttpMethod = "POST"}))
{
#Html.LabelFor(a => a.Entity.Name)
#Html.TextBoxFor(a => a.Entity.Name, new { #class = "isrequired", style="width: 250px;" })
}
</div>
//-------- Here the method from the view (in the same controller as the first code portion) -----
[HttpPost]
public JsonResult SelectOrder(dialogModel<Order> OrderModel)
{
var order= OrderModel.Entity;
// But order has only the property Name set (in the view)
...
}

I was able to solve the issue simply by adding an hidden field for each needed property, like:
#Html.HiddenFor(p => p.Entity.OrderId, new { id = "OrderId" })
This is because from the PartialView a new instance of the Model is created and sent to the controller. Therefore only the properties set in the form are taken (in my case the only field was the OrderName related to the TextBox in the PartialView).

Related

MVC Razor View update Form on SelectedIndexChange

I have a form in a View that brings together a number of pieces of information (address, telephone etc). All these elements are wrapped up in a view model. There is one section that asks the user to select a county. On selection, I want to be able to show a price based on the county selected.
I came across the following SO question which is close to what I want, but it looks like the action submits the form to a 'change controller'. I naively need to be able to basically call two controllers - one onSelectedChange and the other onSubmit. I'm pretty sure ya can't do this!
Here' what I'm after:
#model ViewOrder
#using (Html.BeginForm("Order", "Home"))
{
#* - textboxes et al - *#
<p>
#Html.DropDownListFor(x => x.Counties,
new SelectList(Model.Counties, "CountyId", "County"),
new { #class = "form-control input-sm" })
</p>
<p>
#* - £Price result of dropdown list selection and
add to View Model to add to sub total - *#
</p>
<input type="submit" text = "submit"/>
}
I'm very new to MVC - Could do this easily in webforms (but I'm sticking with MVC!) There must be some form of Ajax action that would allow this. Any suggestions?
First you have a problem with you #Html.DropDownListFor() method. Model.Counties is a complex object (with properties CountyId and County) but you cannot bind a <select> (or any control) to a complex object, only a value type. Your model needs a property (say) public int SelectedCountry { get; set; } and then #Html.DropDownListFor(x => x.SelectedCountry, new SelectList(Model.Counties, "CountyId", "County"), ...)
To display the price, you need to handle the .change event of the dropdown, pass the selected value to a controller method, and update the DOM.
Script (based on the property being SelectedCountry)
var url = '#Url.Action("GetPrice", "yourControllerName")';
$('#SelectedCountry').change(function() {
$.getJSON(url, { ID: $(this).val() }, function(data) {
// do something with the data returned by the method, for example
$('#someElement').text(data);
});
});
Controller
public JsonResult GetPrice(int ID)
{
// ID contains the value of the selected country
var data = "some price to return";
return Json(data, JsonRequestBehavior.AllowGet);
}

passing vars from Index View to Create View

I have 2 dropdownlists on the Index page, and I wish to pass the id's of the selected items to the Create Page, so that I can populate the 2 dropdownlists on the Create page the same as the Index page.
Can you please suggest how I can do this?
At the moment I have this in the Index View :-
#Html.ActionLink("Create New", "Create", new { LeagueId = "ddlLeagues" }, new { ClubId = "ddlClubs" })
And then in the Controller :-
public ActionResult Create(int LeagueId, int ClubId)
{
var _LeagueID = LeagueId;
var _ClubID = ClubId;
Any help is very much appreciated!
Thanks
You can do it as described in this post:
ActionLink routeValue from a TextBox
you basically need to wrap your dropdowns with a form that routes to the create function, and the submit will take care of passing those values to your controller because they will be in the form data:
#using(Html.BeginForm("Create", "Footballer", FormMethod.Get))
{
#Html.DropDownList("LeagueId", Model.Leagues)
#Html.DropDownList("ClubId", Model.Clubs)
<input type="submit" value="Create"/>
}
If you are using a strongly typed model that has Properties for LeagueId and ClubId then use:
#Html.DropDownListFor(m => m.LeagueId, Model.Leagues)
#Html.DropDownListFor(m => m.ClubId, Model.Clubs)
Model.Clubs and Model.League are the IEnumerables that you will use to populate your dropDowns ofcourse
in your controller make sure you have the following:
[HttpGet]
public ActionMethod Create(int LeagueId, int ClubId)
{
//return your Create View
}
[HttpPost]
public ActionMethod Create(FormCollection data)
{
//Perform the create here
}
You can add a route into the application RegisterRoutes :
routes.MapRoute(
"CreateFootBallerWith2ComboOptions",
"{controller}/{action}/{LeagueId}/{ClubId}",
new { controller = "Footballer", action = "Create", LeagueId = -1, ClubId = -1 } // Default Values
);
You can then use what Bassam suggest with the ActionLink which is a Html Helper.
#Html.ActionLink("Create New", "Create",
new { LeagueId = 1, ClubId = 213 });
or use directly from the browser using :
localhost:7246/Footballer/Create/1/5

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.

What is a way to share a drop down inside a layout for use in all views?

I am becoming more familiar with MVC 3 and the RAZOR view engine. I have a question regarding layouts and shared controls on pages.
Let’s say I have a header section defined in my main layout. In that header is a dropdown I need to populate with project names. This dropdown will serve as a context for the entire site and is present on all pages. As an example, if the user selects “Project A” from the drop down, all of the views for the site will be based on “Project A”. Since this dropdown control is rather static and is used by the entire site, where is the best place to put the code to pull all the projects to display in the dropdown? In a Partial View? In a HTML helper? Another thought is, if a user selects a new value, they would be taken to a dashboard or similar page for that newly selected project. I am trying to figure out how to reuse this control on every page in the site without having to keep wiring it up in every possible controller.
You could use a child action along with the Html.Action helper. So you start by defining a view model:
public class ProjectViewModel
{
[DisplayName("Project name")]
public string ProjectId { get; set; }
public IEnumerable<SelectListItem> ProjectNames { get; set; }
}
then a controller:
public class ProjectsController: Controller
{
private readonly IProjectsRepository _repository;
public ProjectsController(IProjectsRepository repository)
{
_repository = repository;
}
public ActionResult Index(string projectId)
{
var projects = _repository.GetProjects();
var model = new ProjectViewModel
{
ProjectId = projectId,
ProjectNames = projects.Select(x => new SelectListItem
{
Value = x.Id,
Text = x.Name
})
};
return PartialView(model);
}
}
then the corresponding view (~/views/projects/index.cshtml):
#model ProjectViewModel
#Html.LabelFor(x => x.ProjectId)
#Html.DropDownListFor(
x => x.ProjectId,
Model.ProjectNames,
new {
id = "projects",
data_url = Url.Action("SomeAction", "SomeController")
}
)
Now all that's left is to render this widget inside the _Layout.cshtml:
#Html.Action("Index", "Products", new { projectid = Request["projectId"] })
And now we could put some javascript so that when the user decides to change the selection he is redirected to some other action:
$(function() {
$('#projects').change(function() {
var url = $(this).data('url');
var projectId = encodeURIComponent($(this).val());
window.location.href = url + '?projectid=' + projectId;
});
});
Another possibility is to put the dropdown inside an HTML form:
#model ProjectViewModel
#using (Html.BeginForm("SomeAction", "SomeController", FormMethod.Get))
{
#Html.LabelFor(x => x.ProjectId)
#Html.DropDownListFor(
x => x.ProjectId,
Model.ProjectNames,
new {
id = "projects",
}
)
}
so that inside the javascript we don't have to worry about building urls when the selection changes and simply trigger the containing form submission:
$(function() {
$('#projects').change(function() {
$(this).closest('form').submit();
});
});
We just did a similiar thing on a project.
First, you can't really put it in a section because you have to put that section on every view, you could put it in a partial but you would still have to call it from every view.
Second, you can't really put it in the Layout page because the layout page isn't passed any kind of model. So I created an html helper and referenced that in the layout page. There are lots of tutorials on creating html helpers so I won't put the code here. But essentially in your html helper you can make a database call to get all of your projects. Then you can create a select list using string builder in the html helper and return that to the layout page. We then used jquery to add an on change event to the select list. When the select list changed it loaded a new page. So for example, in your select list the value of each item could be the project id, then on change it redirects them to a page like /Projects/View?id=234 where 234 is your project id.
So things to research. 1. Creating HTML Helpers 2. JQUERY change event.
That should get you in the right direction. Let me know if you need any other help and I can post some code.

DropDown for Edit() [Razor]View, Pre-Loaded with Data from Model

I have the dropdowns in my Create() View working perfect.
But in the Edit() View I can't get the Data that was submited during the Create() to show up in DropDowns with the Value enterened upon Create()
I just have textboxs in place at the moment And would really like to have Data Represented in a dropdown for easy selection.
Here is one example:
Create() View - One dropdown is for EmployeeTypes, and stores selected to EmployeeTypeId
Now How do I get that to show up in the Edit() View as the same dropdown, but with Value of EmployeeId already selected?
I have a EmployeeViewModel for the Create() View
But I am just passing the model directly into the Edit() View
Should I create some kind of Employee "partial class" for the Edit() View? to handle the IEnumerable Lists?
and set:
var employeeTypes = context.EmployeeTypes.Select(et => new SelectListItem
{
Value = et.EmployeeTypeId.ToString(),
Text = et.Type.ToString()
});
Or should I pass them in as ViewData?
If so how to do you pass a List in as ViewData and get it to display as an #Html.DropDownList with the Value passed in from the #Model as the defualt value?
I ended up implimenting this way, and it worked like a dream.
Controller Code:
SelectList typelist = new SelectList(context.CompanyType.ToList(), "CompanyTypeId", "Type", context.CompanyType);
ViewData["CompanyTypes"] = typelist;
View Code:
#Html.DropDownList("CompanyTypeId", (IEnumerable<SelectListItem>) ViewData["CompanyTypes"])
There may be bugs in this code - I haven't tested it - but what you basically want to do is:
var etId = ??? // EmployeeTypeId from your model
var employeeTypes = context.EmployeeTypes.Select(et => new SelectListItem
{
Value = et.EmployeeTypeId.ToString(),
Text = et.Type.ToString(),
Selected = et.EmployeeTypeId == etId
});
ViewData["EmployeeTypeList"] = employeeTypes.ToList();
Then in your view you can do
#Html.DropDownList("EmployeeType", ViewData["EmployeeTypeList"])

Resources