I have the following ViewModel:
public class MyViewModel
{
public int Id { get; set; }
public string Title { get; set; }
public int ParentClassId { get; set; }
public List<AnotherClass> AnotherClassItems { get; set; }
}
And in the view I only have a form input for Title, and a list of AnotherClassItems that aren't editable - they are just used to display a list of items related to the class. All of the properties are set when the 'edit' view loads, but when the view does a post, the ParentClassId & AnotherClassItems lists are null. Here is the HttpPost ActionResult from the controller:
[HttpPost]
public ActionResult Edit(FormCollection collection, MyViewModel myviewmodel)
{
if (ModelState.IsValid)
{
//myviewmodel.ParentClassId and myviewmodel.AnotherClassItems are null??
}
return View(myviewmodel);
}
Is there a way to pass the ParentClassId & AnotherClassItems properties without having them as form inputs in the view? Or should I use the Viewbag for this?
Remember, the form only posts back HTML input fields. So if you did not make any text boxes or hidden boxes they will not post to your Edit action.
The correct way to handle this is by passing the ID as a hidden field, then pulling the original values from your database/repository.
Then apply the new values for Title and AnotherClassItems to your model and save to the repository/database.
Related
i need to render list data in partial page... I have store procedure that is responsible to get list of menus and have master Layoutpage in view--> shared folder--> now i am rendering partial page in masterLayout page but i am not getting any result. I am aware that partial page doesn't go through controller so how i would pass the data in that?
Controller Action
public ActionResult DisplayFunctionsList()
{
var myList = F_UOF.GetAllFunctions();
return View(myList);
}
Store Procedure Mapping (Model) class
public class GetAllFunction_SP_Map
{
public GetAllFunction_SP_Map() { }
[Key]
public int Hierarchy_ID { get; set; }
[Required]
public int ParentID { get; set; }
[StringLength(250)]
[Required]
public string ParentName { get; set; }
[Required]
public int ChildID { get; set; }
[StringLength(250)]
[Required]
public string ChildName { get; set; }
[StringLength(250)]
[Required]
public string Controller { get; set; }
[StringLength(250)]
[Required]
public string Action { get; set; }
}
MasterLayout Page
#Html.Partial("_DisplayFunctionList_Partial")
Partial Page (_DisplayFunctionList_Partial)
#model IEnumerable<DatabaseLayer.StoreProcedures.StoreProceduresMapping.GetAllFunction_SP_Map>
#foreach(var item in Model)
{
#item.ParentName
}
In this example, since you are calling from the master page, you want to use the Html.RenderAction() method.
#{Html.RenderAction("DisplayFunctionsList", "Controller");}
Edit - the Html.RenderAction must be surrounded by curly braces with the semicolon (';') at the end of the function call. To avoid this, you can use the #Html.Action call, which returns an MvcHtmlString
#Html.Action("DisplayFunctionsList", "Controller")
Also, in using this method, you would need to change your view result slightly because the view you are trying to render is not the name of the action you are calling it from and you appear to be wanting to return a PartialViewResult
public ActionResult DisplayFunctionsList()
{
var myList = F_UOF.GetAllFunctions();
return PartialView("_DisplayFunctionList_Partial", myList);
}
If you are within a view (not a master page), then you would need to pass the model, assuming the model is of the correct type. If the model for the partial view is a property on your overall view model, then just send the model property instead of the entire model.
*Send Entire Model*
#Html.Partial("_DisplayFunctionList_Partial", Model)
*Send Model Property*
#{Html.Partial("_DisplayFunctionList_Partial", Model.MyList)}
The call to #Html.Partial takes a second parameter, which is the model to pass to the partial view. All you need to do is include the list in your View's Model and then pass it along appropriately.
I have setup validation in my viewmodel such as the below:
[Required(ErrorMessage = "This field is required.")]
[StringLength(25, MinimumLength = 6)]
[DataType(DataType.Password)]
public string Password { get; set; }
[DataType(DataType.Password)]
[System.Web.Mvc.CompareAttribute("Password", ErrorMessage = "Password must be the same")]
public string ConfirmPassword { get; set; }
When I submit the form I check if ModelState.IsValid and if its not valid then return the original view but by doing this I lose the original data I had in my model.
[HttpPost]
public ActionResult Form(MemberAddViewModel viewModel, string returnUrl)
{
if (ModelState.IsValid)
{
...
}
return View("Form", viewModel);
}
I would have expected the viewModel to be passed back to the original View but it seems only model items populated in the view are. What is best practice for this? Hidden fields / Session data?
To understand why you have to rebuild parts of the model, you need to think about what's going on under the hood when the model binder is passed the data from your view. A SelectList is a perfect example of this.
Let's say you have a view model as follows:
public class EmployeesViewModel
{
public int EmployeeId { get; set; }
public SelectList Employees { get; set; }
// other properties
}
Here, EmployeeId represents the Id of the selected Employee from the SelectList. So let's assume you have a controller action like this, which populates the SelectList and passes the data to the view:
public ActionResult Index()
{
var model = new EmployeesViewModel();
model.Employees = new SelectList(/* populate the list */);
return View(model);
}
Now let's assume a user comes along, navigates to this view, chooses an employee from the list, and POSTs the data back to the server. When this happens, the only thing that gets submitted from that form, is the Id of the employee. There's no need for HTTP to transport all of the other options from the SelectList to the server, because a) they haven't been selected and b) you have that data on the server already.
Not sure for I undertandood your question... This is how i populate lost fields: i divide model population into 2 parts: for editable props (elements that being posted back to server) and non-editable (that are getting lost on postback)
// View model
public class MyModel
{
public MyModel() { }
public MyModel(Entity e, ContractTypes[] ct)
{
// populate model properties from entity
ContractTypeId = e.ContractTypeId;
// and call magic method that'll do the rest my model needs
PopulateNonEditableFields(ct);
}
public void PopulateNonEditableFields(
Dictionary<int, string> ContractTypes [] ct)
{
// populate dictionaries for DDLs
ContractTypesList = new SelectList(..., ct,...);
}
// model properties
public ContractTypeId { get; set; }
public SelectList ContractTypesList { get; set; }
}
// controller action
[HttpPost]
public ActionResult Action(MemberAddViewModel viewModel)
{
if (ModelState.IsValid)
{
...
}
// user input stays as-is but need to populate dictionaries and evrithing
// that was lost on postback
viewModel.PopulateNonEditableFields(context.ContractTypes.GetAll());
return View("Form", viewModel);
}
As I understand it, you have data in the view model which is not posted back through the form. There can be many valid reasons why this is the case.
Another alternative is to always create the view model manually, and then update it using the posted back values through a call to TryUpdateModel. Calling TryUpdateModel will do two things: set the model's public properties using the controller's value provider, then runs validation checks on the model.
[HttpPost]
public ActionResult Action(int id, string returnUrl)
{
MemberAddViewModel viewModel = CreateViewModel(id); // Populates with
// intial values
if(TryUpdateModel(viewModel))
{
// If we got here, it passed validation
// So we continue with the commit action
// ...
}
else // It failed validation
{
return View("Form", viewModel);
}
}
I'm creating a search application in mvc3 where I have 2 tables :
1.State:Id(pk) and state_name
2.District:Id(pk),s_id(f.k.), District_name
I am using code first and EF and have database created for it called Search
I want my index to show all states in drop down list
following is my State.cs code
public partial class State
{
public State()
{
this.Districts = new HashSet<District>();
this.Search_master = new HashSet<Search_master>();
}
public int Id { get; set; }
public string State_name { get; set; }
public virtual ICollection<District> Districts { get; set; }}
this is my District class:
public partial class District
{
public District()
{
this.Search_master = new HashSet<Search_master>();
}
public int Id { get; set; }
public string District_name { get; set; }
public int StateId { get; set; }
public virtual State State { get; set; } }
How can I call the data stored in my tables in my index page
thank you in advance!!
You can use JQuery to bind to the onChange event of the State dropdown. And do an ajax call passing the stateId to the server that will return a json list with the correct districts.
Look here for a sample
Update
on how to populate a dropdownlist look here
Pass the contents of the first dropdown in the model and use a
#Html.DropDownListFor(m => m.MyList)
Bind to the change event and send a jQuery ajax call to a server method you create in a controller. Pass the dynamic list back using JSON and parse the results. Manually add them to your dropdown.
Alternatively just do a full post back and send the second list back in the model, hiding the other dropdown while it has an empty result set.
I think I am getting somewhere with mvc.
I have created a view that is bound to my view model that looks like this
public class CreatePurchaseViewModel
{
public Order Order { get; set; }
public IEnumerable<Product> Products { get; set; }
public DateTime OrderDate { get; set; }
public bool OrderSent { get; set; }
}
I have also created another view model
public class ProductsViewModel
{
public int ProductID { get; set; }
public int OrderID { get; set; }
}
I have create a partial view that is bound to this viewmodel.
I am loading it from my view
#Html.Partial("_AddProductItem", new MVC_WireFrame.ViewModels.ProductsViewModel())
Now how do I get the items from my ProductsViewModel into my CreatePurchaseViewModel or is that not the correct way of doing things?
I can access the data from the ProductsViewModel in my controller like
[HttpPost]
public ActionResult InsertProduct(string input)
{}
2 questions really, how do I pass the value into the other viewcontroller? and
how do I populate a list within the AddProduct partial view so I can show what products have been added?
Thanks in advance for any help.
Normally you should not be passing data from one view model to another. You should create your view model classes in such a way that they contain all the required information for the view to display. It is the controller's responsibility to fill this information. Concerning you second question about the list, well you simply add a property which is of type IEnumerable<T> to this view model which will be filled by the controller and the view can show what products have been added. So think of what information your views require and add it to the view models as properties.
In my MVC application I have a problem with passing data from view to controller. I have fairly complex domain classes:
public class TaskBase : PersistableObject
{
public virtual TaskCategory Category { get; set; }
public virtual IList<TaskNote> Notes { get; set; }
public virtual string TaskTitle { get; set; }
public virtual string TaskBody { get; set; }
public virtual DateTime? CreationTime { get; set; }
public virtual User CreatedBy { get; set; }
public virtual int CompletionRatio { get; set; }
}
public class MainTask : TaskBase
{
public virtual IList<TaskBase> ChildTasks { get; set; }
public virtual User AssignedTo { get; set; }
public virtual IList<TaskHistory> History { get; set; }
}
public class TaskFormModel : ViewDomainBase
{
public MainTask Task { get; set; }
public LoginForm LoginInfo { get; set; }
}
And in my view I want to pass an instance of TaskFormModel to the controller.
<%= Html.ActionLink<TaskController>("Edit Task", (x) => x.Edit(new TaskFormModel() { Task = item, LoginInfo = Model.LoginInfo }))%>
And here is the controller action:
public ActionResult Edit (TaskFormModel taskInfo)
{
return View(ViewPageName.TaskDetailsForm, task.Task);
}
In this action method taskInfo comes null even if I pass non-null instance from view. I think I have a binding problem here. I think, writing custom model binder requires every property to be converted and also when new fields added then binder class should also be changed, so I don't want custom model binder to do this. Is there any other way to pass data to controller in this scenario? Or could custom model binder can be coded so that less code written and also when new properies are added binder class will not need to be changed?
Edit After Comments: What I am trying to achieve is basically to pass an instance from one view to another view, without querying repository/db in my controller's action.
First version of answer:
Your GET edit method should be like:
public ActionResult Edit (int id)
{
var model = taskRepository.GetTaskEditModel(id);
return View(ViewPageName.TaskDetailsForm, model);
}
and ActionLink:
<%= Html.ActionLink("Edit Task", "Edit", "Task", new { model.Task.id })%>
If you want to pass complex objects to controller, you should wrap them up in html form and pass to POST action.
In my opinion you are doing something wrong.
As I understand: you are trying to instantiate a new object, pass it to browser and get it back.
well you cant.
If object you want to edit exists already in your storage, then you should alter your ActionLink to reference it by id, and instantiate it inside your Edit action.
Take a look at default strongly typed index views created by tooling.