How can you do multiple saves of a model in one submit? - asp.net-mvc

I have a model:
public class CustomerAttributes
{
public Int Id { get; set; }
public string value { get; set; }
}
my create view looks like this:
<div class="editor-label">
#Html.Label("Name")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Value)
#Html.ValidationMessageFor(model => model.Value)
</div>
<div class="editor-label">
#Html.Label("Age")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Value)
#Html.ValidationMessageFor(model => model.Value)
</div>
<div class="editor-label">
#Html.Label("Height")
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Value)
#Html.ValidationMessageFor(model => model.Value)
</div>
So each textbox will be a new record in the database. Is it possible to do something like this? How can I handle this? Also my biggest problem is that each field could be a textbox or a combobox or a radio.... etc... Name might a textbox for example but age might be a combobox.... I know I have all textboxes now but that could change.

I would personally suggest creating a IEnumerable ViewModel of your CustomerAttributes model.
This way you could pass multiple values back to the controller.
Each time you added the new form elements (assuming you are adding them dynamically), you would just create a new item within the model.

The link provided in a comment was helpful:
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
To add to that, there could be a ViewModel that can hold a string or an enum or something to specify what type of control to display and with that some partial views that display the different controls. Then iterate through and display each control in the view based on that specifier.

Related

MVC: How to Use Same selected item for two diff drop downList in view

I am using same selected item for two diff Drop down list. Below is the view code.
<div id="divSelectingItem1" class="editor-field">
#Html.LabelFor(m => m.LocationOne)
#(Html.Kendo().DropDownListFor(m => m.SelectedLocation)
.DataTextField("Text").DataValueField("Value")
.BindTo(Model.LocationOne)
.Value(Model.SelectedLocation))
</div>
<div id="divSelectingItem2" class="editor-field">
#Html.LabelFor(m => m.LocationTwo)
<span id="spnObsDateTimeIcon" class="k-icon k-i-note"></span>
#(Html.Kendo().DropDownListFor(m => m.SelectedLocation)
.DataTextField("Text").DataValueField("Value")
.BindTo(Model.LocationTwo)
.Value(Model.SelectedLocation))
</div>
Model class
public class LocationViewModel :ViewModelBase
{
[DisplayName("Identifier Location")]
public List<SelectListItem> LocationOne{ get; set; }
public string SelectedLocation{ get; set; }
[DisplayName("Identifier Location")]
public List<SelectListItem> LocationTwo{ get; set; }
}
But the above code is not working.. Am i making any mistake? I am new to .net MVC any help...
In order for the binding to properly work I think you have to give the drop-down element the same name as the model property is should be bound to.
<div id="divSelectingItem1" class="editor-field">
#Html.LabelFor(m => m.LocationOne)
#(Html.Kendo().DropDownListFor(m => m.SelectedLocation)
.Name("SelectedLocation") //<--Name of the model property
.DataTextField("Text").DataValueField("Value")
.BindTo(Model.LocationOne)
.Value(Model.SelectedLocation))
</div>
I don't think you can use the bound model way with two elements representing the same property. I think if you tried would run into js errors. If the variables did make it make it back to your controller then I bet the SelectedLocation would be the value of the first drop-down list.
One way to work around this would be to give the drop downs a unique name and then save them when you are ready to send the data. But you would still need two properties.
It sounds like you want a default value in which case something like the following would work:
<div id="divSelectingItem1" class="editor-field">
#Html.LabelFor(m => m.LocationOne)
#(Html.Kendo().DropDownListFor(m => m.SelectedLocationOne)
.Name("SelectedLocationOne") //<--Name of the model property
.DataTextField("Text").DataValueField("Value")
.BindTo(Model.LocationOne)
.Value(Model.DefaultSelectedLocation))
</div>
<div id="divSelectingItem2" class="editor-field">
#Html.LabelFor(m => m.LocationTwo)
<span id="spnObsDateTimeIcon" class="k-icon k-i-note"></span>
#(Html.Kendo().DropDownListFor(m => m.SelectedLocationTwo)
.Name("SelectedLocationTwo")
.DataTextField("Text").DataValueField("Value")
.BindTo(Model.LocationTwo)
.Value(Model.DefaultSelectedLocation))
</div>

how to set default value HTML.TextBoxFor()

I have a view consisting of a form and textboxes.
How can I set a default value in each box for strings and int values?
I want the page to load up each box's value so I don't need to type values.
I'm not able to change anything in the Model.
#model MyDb.Production.ProductionMaterial
#{
ViewBag.Title = "CreateMaterial";
}
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>ProductionOrderMaterial</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Position)
</div>
<div class="editor-field"> //something like
#Html.TextBoxFor(model => model.Position, Or 5 )
#Html.ValidationMessageFor(model => model.Position)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ArticleId)
</div>
<div class="editor-field"> //something like
#Html.TextBoxFor(model => model.ArticleId. Or "")
#Html.ValidationMessageFor(model => model.ArticleId)
</div>
}
Create an instance of the model in your action, assign some values to the properties of the model and pass that into the View method.
In your action have:
ProductionMaterial model = new ProductionMaterial();
model.Position = 5;
return this.View(model);
This will pass the model to the view and TextBoxFor( model => model.Position ) will display 5.
I see you already got answer, but I'll show you how you can do it another way:
In Controller
public ActionResult Index()
{
//here you must set VALUE what u want,
//for example I set current date
Viewbag.ExactlyWhatYouNeed = DateTime.Now
return View();
}
In View
#Html.TextBoxFor(model => model.CurrentDate, new { #Value = ViewBag.ExactlyWhatYouNeed})
And when you will load your View, you will get field with default value (current date in our example)
Its work on MVC 4
Hope Its will be usefull info for another people.

ValidationMessageFor for different object

I'm using mvc4, in my view I have a declaration
#model IEnumerable<UserDisplay>
on the same view I want to have a Form with "create" post for different object type name "Review"
how can I use the EditorFor and ValidationMessageFor ? cause model is of different type.
this is not working
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Review</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Info)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Info)
#Html.ValidationMessageFor(model => model.Info)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FromId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FromId)
#Html.ValidationMessageFor(model => model.FromId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ToId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ToId)
#Html.ValidationMessageFor(model => model.ToId)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Create a partial view for that form that uses the #model declaration of the required type then use #Html.Partial("mySubFormView"). Don't mix model types in your views, it makes life too complicated.
You can use a view model containing both objects.
public class MyViewModel
{
public IEnumerable<UserDisplay> { get; set; }
public Review Review { get; set; }
}
Then your model declaration in the view becomes:
#model TheNamespace.For.MyViewModel
Which will allow you to use #Html.EditorFor and #Html.ValidationMessageFor helpers.

MVC, passing values back from multiple partial views in a page

I have problem when I am trying to pass values back from my page which contains the same partial view twice.
My class definiton is like below:
public class Account : IEntity
{
public decimal CurrentBalance { get; set; }
public List<Person> AccountHolders { get; set; }
//to get round the non-existing enum support in EF4.3 wrap enum to int
public int StatusValue { get; set; }
public AccountStatus Status { get { return (AccountStatus)StatusValue; } set { StatusValue = (int) value; } }
public DateTime AccountOpenDate { get; set; }
public DateTime AccountCloseDate { get; set; }
public DateTime AccountSuspensionDate { get; set; }
}
It has a List of Person , which I made a partial view for (for a single one).
<fieldset>
<legend>Person</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Age)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Age)
#Html.ValidationMessageFor(model => model.Age)
</div>
</fieldset>
In the Create page for the Account I include 2 of the partial views I created as below.
<div id="Person1">
#Html.Partial("_CreateAccountHolder" )
</div>
<div id="Person2">
#Html.Partial("_CreateAccountHolder")
</div>
When I look at what is posted back, it contains the values (Name and Age as the properties of Person) I put in the form values of the page and I have have the tow of them as expected:
CurrentBalance=19&Status=Closed&AccountOpenDate=12%2F12%2F2012&Name=mustafa&Age=20&Name=sofia&Age=20&AccountCloseDate=12%2F12%2F2012&AccountSuspensionDate=12%2F12%2F2012
But when I look at my create method on my controller I see the AccountHolder list as null. I tried with various signatures...
public ActionResult Create(Account personalaccount, Person [] accountHolders)
public ActionResult Create(Account personalaccount, List accountHolders)
If I only have one partial view of Person and have my controller like this, I can see the Person object bound correctly.
public ActionResult Create(Account personalaccount, Person accountHolder)
Any ideas as to where I am going wrong?
If I understand your scenario correctly one way to accomplish this is to use Editor Templates instead of partial views. I have a little write up about them here:
codenodes.wordpress.com - MVC3 Editor Templates
To create an Editor Template:
if you don't already have a folder called "EditorTemplates" in the web project of your solution then create one in the Views\Shared folder.
add a new partial view and name it the same as the model you're rendering, in your case Person, so you would call it Person.cshtml (I know partial views are supposed to start with an underscore "_" but for an Editor Template it needs to be named the same as the model).
paste the code from your "_CreateAccountHolder" partial view into the new Person.cshtml Editor Template.
in your Create page render your AccountHolders list thusly:
<div id="People">
#Html.EditorFor(x => x.AccountHolders)
</div>
If you need to have individual divs around each Person then you can add these to your Editor Template. The good thing about Editor Templates is that you only need a single call to the template even if you have multiple Person objects in your list - no need to loop or anything like that as the template automatically renders each Person object. It also names the field correctly so it should post back something like this if for example you have 2 Person objects in your collection:
AccountHolders[0].Name
AccountHolders[0].Age
AccountHolders[1].Name
AccountHolders[1].Age
Here's the code for your Editor Template:
#model Person
<fieldset>
<legend>Person</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Age)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Age)
#Html.ValidationMessageFor(model => model.Age)
</div>
</fieldset>
I understood my problem after reading
[http://stackoverflow.com/questions/653514/asp-net-mvc-model-binding-an-ilist-parameter][1]
Putting 2 partial views of the same type made the view return Name and Age pair with nothing to distingusih between the first and the second pair. I changed the parial view as below, but dont really like it...
<div class="editor-field">
#Html.TextBox("person[0].Name", "")
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-field">
#Html.TextBox("person[0].Age", "")
#Html.ValidationMessageFor(model => model.Age)
</div>
<div class="editor-field">
#Html.TextBox("person[1].Name", "")
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-field">
#Html.TextBox("person[1].Age", "")
#Html.ValidationMessageFor(model => model.Age)
</div>
It now postbacks something like below and I can read the IList in my controller..
CurrentBalance=19&Status=Closed&AccountOpenDate=12%2F12%2F2012&person%5B0%5D.Name=mustafa&person%5B0%5D.Age=19&person%5B1%5D.Name=sofia&person%5B1%5D.Age=20&AccountCloseDate=10%2F10%2F2012&AccountSuspensionDate=12%2F12%2F2012
First you should create CreateAccountModel with two instances of AccountModel, something like:
public class CreateAccountModel
{
public Account Person1 { get; set; }
public Account Person2 { get; set; }
}
Next, when you add your partial views, you should pass individual models to them, e.g:
<div id="Person1">
#Html.Partial("_CreateAccountHolder", Model.Person1)
</div>
<div id="Person2">
#Html.Partial("_CreateAccountHolder", Model.Person2)
</div>
Now MVC will automatically prefix all account fields with PersonX, so all fields will be unique.
Alternatively you can specify prefixes manually when you add your partial views:
{
var prefixData = new ViewDataDictionary { TemplateInfo = { HtmlFieldPrefix = "Person1" } };
Html.RenderPartial("_CreateAccountHolder", new ViewDataDictionary(prefixData));
}

No value for the dropdownlist when my form is submitted

I try to use a dropdownlist in my view for showing a list of authors (users). I'm able to populate this dropdown and see the content in my view. When submitting my form, I debug my action in my controller and when inspecting my model, the value of the field associated with my dropdown is null.
Here is my action controller (before showing my view):
public ActionResult Create()
{
IEnumerable<User> authors = m_AccountBusiness.GetAllUsers();
PageCreateViewModel viewModel = new PageCreateViewModel
{
PageToCreate = new PageFullViewModel(),
Authors = authors.Select(x => new SelectListItem { Text = x.UserName, Value = x.UserID.ToString() })
};
return View(viewModel);
}
Here is (a portion of) my view:
#model MyBlog.ViewModels.PageCreateViewModel
<h3>Create</h3>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.PageToCreate.PageID)
<div class="editor-label">
#Html.LabelFor(model => model.PageToCreate.Title)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.PageToCreate.Title, new { #class = "titleValue" })
#Html.ValidationMessageFor(model => model.PageToCreate.Title)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PageToCreate.Author)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.PageToCreate.Author, Model.Authors, "Please select...")
</div>
Here is my PageCreateViewModel:
public class PageCreateViewModel
{
public PageFullViewModel PageToCreate { get; set; }
public IEnumerable<SelectListItem> Authors { get; set; }
}
Any idea?
Thanks.
Thank you guys. I finally found my error: it is not Author the right property to bind to, it must be AuthorID !!
<div class="editor-field">
#Html.DropDownListFor(model => model.PageToCreate.AuthorID, Model.Authors, "Please select...")
</div>
Thanks anyway.
You have to add an extra string property to your PageCreateViewModel. In this property we will store the selected value. Lets say it's name is "Author". Edit: I noticed you have a property for it in your model but give it a try like this.
The dropdownlist filling needs to look like this on your view.
#Html.DropDownList("Author", Model.Authors)

Resources