I wanna Add new multi records to databese,
and I design View have multi form to filed data and insert it.
My View have:
--item 1
#Html.EditorFor(modelitem => item.Description)...
.
.
.
--item 2
#Html.EditorFor(modelitem => item.Description)...
I use
[HttpPost]
public ActionResult Edit(FormCollection c)
{
var desc = c.GetValue("item.Description");
}
I use it do get value, but I wanna separate value of desc.
I use .Split(','); but if desc has value :
"test value, test desc"
So I can't use it.
So Anyone tell me. how to loop item to insert it
You can also use -
Request.Form["Your property Name"]
WORKING CODE:
Model -
public class MyClass
{
public string MyName { get; set; }
}
View -
#using (Html.BeginForm("SubmitData","Post", FormMethod.Post))
{
<div class="form-horizontal">
<h4>MyClass</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.MyName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.MyName)
#Html.ValidationMessageFor(model => model.MyName)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
On POST, you can access it like this -
[HttpPost]
public ActionResult SubmitData(MyClass c)
{
var name = Request.Form["MyName"];
return View();
}
We will have the input value in the name variable. Check below image.
Also in the above code I showed how to do model binding too. If you use variable 'c', that will also have value from UI. Check below image.
You could prefix the id's of the fields so that you can retrieve the two separate fields;
#Html.TextBoxFor(x => x.SomeProperty, new { #id = "item_1_description" });
And that would allow you to get that specific value from the FormCollection;
string description = c.GetValue("item_1_description");
However, it would be cleaner if you could take advantage of strongly-typing your views. In your position, I would create a ViewModel that represents both of your objects. Since I don't know what your data types are, I'll use the example of a Person, which looks like this;
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
To to add two people in one form, you would create a `ViewModel' that represents what the form would look like - a flattened version of two people;
public class MuliplePeopleViewModel
{
public string Person1Name { get; set; }
public string Person2Name { get; set; }
}
Which would generate a view with two textboxes;
#model MuliplePeopleViewModel
#Html.EditorFor(x => x.Person1Name);
#Html.EditorFor(x => x.Person2Name);
Now in your Controller you can replace your use of FormCollection with our new ViewModel, that will automatically bind the values of the TextBox's to the relevant properties;
[HttpPost]
public ActionResult Edit(MuliplePeopleViewModel viewModel)
{
string person1Name = viewModel.Person1Name;
}
Food for thought: I'm not entirely sure the DefaultModelBinder will bind an unflattened version of the ViewModel, such as;
public class MuliplePeopleViewModel
{
public Person Person1 { get; set; }
public Person Person2 { get; set; }
}
But perhaps you could try it!
EDIT
Following comments from the author, you could also create a ViewModel that contains an ICollection<Person>;
public class MuliplePeopleViewModel
{
public ICollection<Person> People { get; set; }
}
And in your view you can loop through the collection and display fields for each;
#model MuliplePeopleViewModel
#foreach (Person person in Model.People)
{
#Html.EditorFor(x => person.Name);
}
Now, the DefaultModelBinder should now give you a list of people to use in your action. However, if not, you may need to write a custom model binder.
More food for thought: You might be able to utilise EditorTemplates to simplify your view.
Let me know if I can help further.
Matt
Try this:
[HttpPost]
public ActionResult Edit(FormCollection c, string[] description)
{
}
So you will have the values in an array.
Related
I need to bring data from my database and show it in a dropdownlist in my webpage:
The returned data will have two parameters: DisciplineID and DisciplaneName.
Everything works proper until the Controller. It returns proper data but need help on how to move the data to the view properly.
Here is the breakdown of my project using MVC5:
Model Class:
public class Discipline
{
public int DisciplineID { get; set; }
public string DisciplineName { get; set; }
}
Model Class Implementation:
public class DisciplineModel : IDiscipline
{
private List<Discipline> disciplinesList = new List<Discipline>();
public IEnumerable<Discipline> disciplines()
{
LoadDisciplines(); //populates disciplinesList from database
return disciplinesList;
}
}
Controller:
[HttpGet]
public ActionResult EditDiscipline()
{
var disciplinesList = _idiscipline.disciplines();
return View(disciplinesList);
}
Data is brought upto here, but need to move that data to the View.
View:
#model OnlineTestingSystem.Models.Discipline
<div class="container">
#using (Html.BeginForm("EditDiscipline", "Discipline", FormMethod.Post))
{
<div class="form-group">
#Html.LabelFor(a => a.DisciplineName, "Discipline Name")
#Html.DropDownListFor(a => a.DisciplineID, Model.disciplines,"Selected")
</div>
<input class="btn btn-primary" type="submit" />
}
#ViewBag.message
</div>
I need to add the data returned from the dropdownlist to show The DisciplineIDs. So How do I modify my different classes to achieve this goal?
The syntax of the line below is not proper, I just wanted to show that this is what I am trying to do.
#Html.DropDownListFor(a => a.DisciplineID, Model.disciplines,"Selected")
Thanks in Advance.
First, you need to create a ViewModel that holds the list and the selected id of this list:
public class DisciplineViewModel
{
public int? DisciplineId {get; set;}
public List<Discipline> DisciplineList {get ; set;}
}
then initialize this view model in the controller:
[HttpGet]
public ActionResult EditDiscipline()
{
var disciplinesList = _idiscipline.disciplines();
var vm = new DisciplineViewModel
{
DisciplineList = disciplinesList;
}
return View(vm);
}
then in the view :
#model OnlineTestingSystem.Models.DisciplineViewModel
<div class="container">
#using (Html.BeginForm("EditDiscipline", "Discipline", FormMethod.Post))
{
<div class="form-group">
#Html.LabelFor(m => m.DisciplineList)
#Html.DropDownListFor(m => m.DisciplineId, new SelectList(Model.DisciplineList , "DisciplineID ", "DisciplineName "), "Select..." )
</div>
<input class="btn btn-primary" type="submit" />
}
#ViewBag.message
I have this Model:
public class ClassRoom
{
public List<Student> Students { get; set; }
}
public class Student
{
public int ID { get; set; }
public int Type { get; set; }
public string Name { get; set; }
public string LastName { get; set; }
}
The values of the ID and Type are already full, I need to create a view where the student can add his name and last name.
So I need to loop the list of students in the view.
I am doing the following:
#model Models.ClassRoom
#{
ViewBag.Title = "Classroom";
}
#if (Model != null)
{
<form action="Controller/Method">
foreach (var item in Model.Students)
{
#Html.HiddenFor(model => model.ID)
<div>
#Html.TextBoxFor(model => model.Name)
#Html.TextBoxFor(model => model.LastName)
</div>
}
<input type="submit">
</form>
}
I want to eventually submit a model of type Classroom with a list of students filled with Name and Last Name for each ID
But this is not working.
How can I bind values From the View to item on a certain index in a list?
For each ID in the hidden input,I want to save the written name and last name.
Please help
I need to create a form and submit the ClassRoom with a full List of Students eventually. What should be the types in my Controller method and views?
If you want to send your model back to controller, then you would need to generate naming correctly. There are several ways, one of them would look like this:
#using (Html.BeginForm("Index", "Home")) {
<div style="margin-top: 100px;">
#if (Model != null) {
for (var i = 0; i <= Model.Students.Count - 1; i++) {
#Html.HiddenFor(model => model.Students[i].ID)
<div>
#Html.TextBoxFor(model => model.Students[i].Name)
#Html.TextBoxFor(model => model.Students[i].LastName)
</div>
}
}
<input type="submit" value="Go"/>
</div>
}
And in controller dont forget to add:
[HttpGet]
public async Task<IActionResult> Index() {
var classroom = new ClassRoom();
... //add some students to the classroom
return View(classroom);
}
[HttpPost]
public async Task<IActionResult> Index(ClassRoom classRoom) {
...
}
Here can be found some more reading.
Model.cs
A campaign can have multiple images, that's why IEnumerable<int> ImageIdList.
public class Campaign
{
public int Id { get; set; }
public int CreatedBy { get; set; }
public int UpdatedBy { get; set; }
public IEnumerable<int> ImageIdList { get; set; }
}
View.cshtml
I want to download all the images related to a campaign, based on the ImageIdList, that's why I need to post all these ImageIds when a particular Campaign is checked and download button is clicked.
#model Campaign
#{
Layout = "....";
var assets = Model.AssetsInCampaign.ToList();
}
#using (Html.BeginForm("action-method", "controller", FormMethod.Post))
{
<div class="btnSubmit">
<input type="submit" value="Download Asset(s)" />
</div>
#foreach(var i in assets)
{
<div class="s_checkcol">
<input type="checkbox" name="ids" />
#foreach (var imageId in i.Where(c => c.AssetId == doc.FileDataId).SelectMany(c => c.ImageIdList))
{
<input type="hidden" name="ids" value=#(imageId)>
}
</div>
}
}
Controller.cs
public ActionResult DownloadFiles(IEnumerable<int> ids)
{
// code
}
NOTE: Only a part of code(where I'm facing the problem) is provided here. Its a DB first approach and in no way I can alter that (ORDERS).
I tried the above, but all of the ids are posted to the controller no matter how many checkboxes are selected.
Question: How should I bind the IEnumerable<int> ImageIdList property to a checkbox in View.cs and post the data to Controller.cs so that only the ids of selected checkboxes are posted?
This is a nice practice... it will work and Iam working with such a
manner (Iam sure that it will work very well) but one thing you have to be very carefull while coding this, little bit
complicated
Iam taking this effort not only for as an answer to this particular question.
Its for all stackoverflow users. Because i never found the below method anyware in stackoverflow.
I get this method by a long search. You people can use this.
It will help you to avoid for loops to bind the Checkboxlist
Its the best good for re-usability (need a single line (max: 20-25 chars to bind a CheckBoxList in Razor))
CheckBoxListItem.cs
create a New Class CheckBoxListItem //you can use any other names
public class CheckBoxListItem
{
public int ID { get; set; }
public string Display { get; set; }
public bool IsChecked { get; set; }
}
MyModel.cs
This is modelclass
public class MyModel
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<CheckBoxListItem> ChkList { get; set; }
}
HomeController.cs
This is controller
public ActionResult Index()
{
var model = new MyModel(){
Id = 0,
Name = "Your Name",
ChkList = dbContext.myTable.Select(x => new CheckBoxListItem { ID = x.MyTableFieldID, Display = x.MyTableFieldName, IsChecked = true })
//If you need only int part, then just avoid to bind data on Display field
};
return View(model);
}
[HttpPost]
public ActionResult Index(MyModel myModel) //Your model object on PostAction
{
IEnumerable<CheckBoxListItem> ChkList = myModel.ChkList;
// Here is your answer, You can see all your check box items (both checked and unchecked) in ChkList, it will shows all your checked items are true and non-checked items are false in IsChecked field
}
Here you have to give more patiance
Goto the Folder View>Shared>EditorTemplates and RightClick Add>View... and Create a new View with the same name CheckBoxListItem.cshtml
CheckBoxListItem.cshtml
#model Project.Models.CheckBoxListItem
<div class="">
#Html.HiddenFor(x => x.ID)
<div class="">
#Html.CheckBoxFor(x => x.IsChecked)
</div>
#Html.LabelFor(x => x.IsChecked, Model.Display, new { #class = "" })
</div>
Create your View
Index.cshtml
#model #model Project.Models.MyModel
<div class="form-group">
#Html.LabelFor(model => model.Id, htmlAttributes: new { #class = "" })
<div class="col-md-10">
#Html.EditorFor(model => model.Id, new { htmlAttributes = new { #class = "" } })
#Html.ValidationMessageFor(model => model.Id, "", new { #class = "" })
</div>
</div>
#Html.EditorFor(model => model.ChkList) //This only one line of code is enough to bind a checkBoxList in future
<input type="submit" value="Create" class="" />
You will get all these in your post action
Overview:
I'm trying to use a ViewModel that has a property that is the model class that I'm trying to edit. I've seen the edit form work using the MVC scaffolding edit forms when editing a model directly, however I am trying to use a ViewModel that contains the model being edited. Everything works except for the saving of a field that's displayed in a DropDownList.
Explanation:
I've attempted to use the scaffolding features of MVC 3 to create an edit form for a model.
In the MVC Music Store tutorial, this is done for the Edit page of an Album, in the StoreManagerController.
Within that page, they have two drop downs for Genre and Artist. Each looks similar to this in the view:-
<div class="editor-label">
#Html.LabelFor(model => model.GenreId, "Genre")
</div>
<div class="editor-field">
#Html.DropDownList("GenreId", String.Empty)
#Html.ValidationMessageFor(model => model.GenreId)
</div>
As far as I can tell, these have their options filled out in the controller using the ViewBag.
ViewBag.GenreId = new SelectList(db.Genres, "GenreId", "Name", album.GenreId);
ViewBag.ArtistId = new SelectList(db.Artists, "ArtistId", "Name", album.ArtistId);
Working with the Model directly
In my code, I managed to do the same with an object that's being saved to the DB through Entity Framework.
Model
public class Season
{
public int SeasonId { get; set; }
public int ClubId { get; set; }
public Club Club { get; set; }
}
Code in Controller
ViewBag.ClubId = new SelectList(clubs, "ClubId", "Name", season.ClubId);
View
<div class="editor-label">
#Html.LabelFor(model => model.ClubId, "Club")
</div>
<div class="editor-field">
#Html.DropDownList("ClubId", String.Empty)
#Html.ValidationMessageFor(model => model.ClubId)
</div>
This works fine.
Working with the View Model
However now I have realised that the page needs more text displayed than what is available in the model I'm editing.
I was hoping to create a special View Model, with the edited model (season) and the extra text I want to display.
ViewModel
public class EditSeasonViewModel
{
public string PlayerName {get; set;}
public string SummaryText {get; set;}
public int PlayerId {get; set;}
public Season season {get; set;}
}
I did this, changed the controller to have the HttpGet and HttpPost methods use the new ViewModel, changed the View to accept the new ViewModel, and changed the all 'EditorFor' methods in the view to use model.season.MyProperty.
Code in Controller
ViewBag.ClubId = new SelectList(clubs, "ClubId", "Name", seasonVM.season.ClubId);
Code in View
<div class="editor-label">
#Html.LabelFor(model => model.season.ClubId, "Club")
</div>
<div class="editor-field">
#Html.DropDownList("ClubId", String.Empty)
#Html.ValidationMessageFor(model => model.season.ClubId)
</div>
When debugging the HttpPost method, all of the values for season properly exist, except for the ClubId value which should come from the DropDropList.
I haven't changed the DropDownList in the View at all from the way it was when we were using the Model directly.
Question:
My question is, what do I need to change to get the ClubId to be saved properly when using this new EditSeasonViewModel?
Also, how does the ViewBag.ClubId in the HttpGet method in the controller match to the DropDownList in the View, and then have it's value passed back to the HttpPost method?
It's your DropDownList declaration that's incorrect. Try this instead:
#Html.DropDownListFor(m => m.season.ClubId, ViewBag.ClubId)
But really, you should put that select list in your model:
public SelectList Clubs { get; set; }
Then populate it in your controller:
Model.Clubs = new SelectList(clubs, "ClubId", "Name", season.ClubId);
Then you can do:
#Html.DropDownListFor(m => m.season.ClubId, Model.Clubs)
Avoid using dynamic stuff like ViewBag/ViewData to transfer data from action methods to views. Switch to the strongly typed approach.
Update your Viewmodel to have 2 more properties. one to hold a collection of available clubs and one to hold the selected club.
public class EditSeasonViewModel
{
public List<SelectListItem> Clubs { set;get;}
public int SelectedClub { set;get;}
public string PlayerName {get; set;}
public string SummaryText {get; set;}
public int PlayerId {get; set;}
public Season season {get; set;}
public EditSeasonViewModel()
{
Clubs=new List<SelectListItem>();
}
}
Now in your GET action, Get the clubs and load it to the Clubs Property.
public ActionResult create(int id)
{
var vm=new EditSeasonViewModel();
vm.Clubs=GetListOfSelectListItemFromClubsFromSomeWhere();
return View(vm);
}
assuming GetListOfSelectListItemFromClubsFromSomeWhere is a method which returns a list of SelectListItem for your Clubs
public List<SelectListItem> GetListOfSelectListItemFromClubsFromSomeWhere()
{
// to do : return List<SelectListItem> with Value and Text(ClubId Id & Name)
}
and in your view, use the Html.DropDownListFor helper method
#model EditSeasonViewModel
#using(Html.Beginform())
{
#Html.DropdownlistFor(x=>x.SelectedClub,
new SelectList(Model.Clubs,"Value","Text"),"select")
<input type="submit" />
}
When this form is being posted, you will get the selected club's id in the SelectedClub property of your posted model.
[HttpPost]
public ACtionResult Create(EditSeasonViewModel model)
{
if(ModelState.IsValid)
{
int clubId= model.SelectedClub;
//to do : save and redirect (PRG pattern)
}
vm.Clubs=GetListOfSelectListItemFromClubsFromSomeWhere();
return View(model);
}
Please be sure that in your edit/creat action controller, the property is correctly binded:
public async Task<ActionResult> Edit([Bind(Include = "SeasonId,ClubId, otherproperties"]){
// code ...
}
I have a problem while passing an object with HttpPost...
Once the form is submitted, the model is set "null" on the controller side, and I don't know where is the issue..
Here is my controller :
public ActionResult AddUser(int id = 0)
{
Group group = db.Groups.Find(id);
List<User> finalList = db.Users.ToList() ;
return View(new AddUserTemplate()
{
group = group,
users = finalList
});
//Everything is fine here, the object is greatly submitted to the view
}
[HttpPost]
public ActionResult AddUser(AddUserTemplate addusertemplate)
{
//Everytime we get in, "addusertemplate" is NULL
if (ModelState.IsValid)
{
//the model is null
}
return View(addusertemplate);
}
Here is AddUserTemplate.cs :
public class AddUserTemplate
{
public Group group { get; set; }
public User selectedUser { get; set; }
public ICollection<User> users { get; set; }
}
Here is the form which return a null value to the controller (note that the dropdown list is greatly populated with the good values) :
#using (Html.BeginForm()) {
<fieldset>
<legend>Add an user</legend>
#Html.HiddenFor(model => model.group)
#Html.HiddenFor(model => model.users)
<div class="editor-field">
//Here, we select an user from Model.users list
#Html.DropDownListFor(model => model.selectedUser, new SelectList(Model.users))
</div>
<p>
<input type="submit" value="Add" />
</p>
</fieldset>
}
Thanks a lot for your help
I tried your code and in my case the addusertemplate model was not null, but its properties were all null.
That's because of a few model binding issues: Html.HiddenFor and Html.DropDownListFor do not work with complex types (such as Group or User) (at least that's how it is by default).
Also, Html.HiddenFor cannot handle collections.
Here's how to solve these issues:
instead of #Html.HiddenFor(model => model.group) there should be one #Html.HiddenFor for each property of the group that you need bound
instead of #Html.HiddenFor(model => model.users) you need to iterate through the list of users and for each object add #Html.HiddenFor for each property of the user that you need bound
instead of #Html.DropDownListFor(model => model.selectedUser [...], create a property like int SelectedUserId {get;set;} and use that in the DropDownList (as it cannot handle complex types).
Here's the code that works:
1. The User and Group classes, as I imagined them to be:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
}
public class Group
{
public int Id { get; set; }
public string Name { get; set; }
}
2. The adjusted AddUserTemplate class:
public class AddUserTemplate
{
public Group Group { get; set; }
public IList<User> Users { get; set; }
public int SelectedUserId { get; set; }
public User SelectedUser
{
get { return Users.Single(u => u.Id == SelectedUserId); }
}
}
The adjustments:
Users was changed from ICollection to IList, because we'll need to access elements by their indexes (see the view code)
added SelectedUserId property, that will be used in the DropDownList
the SelectedUser is not a readonly property, that returns the currently selected User.
3. The adjusted code for the view:
#using (Html.BeginForm())
{
<fieldset>
<legend>Add an user</legend>
#*Hidden elements for the group object*#
#Html.HiddenFor(model => model.Group.Id)
#Html.HiddenFor(model => model.Group.Name)
#*Hidden elements for each user object in the users IList*#
#for (var i = 0; i < Model.Users.Count; i++)
{
#Html.HiddenFor(m => m.Users[i].Id)
#Html.HiddenFor(m => m.Users[i].Name)
}
<div class="editor-field">
#*Here, we select an user from Model.users list*#
#Html.DropDownListFor(model => model.SelectedUserId, new SelectList(Model.Users, "Id", "Name"))
</div>
<p>
<input type="submit" value="Add" />
</p>
</fieldset>
}
Another option that does not require a bunch of hidden fields is to simply specify that you want the model passed to the controller. I think this is much cleaner.
#using(Html. BeginForm("action","controller", Model, FormMethod.Post)){
...
}