I have a list of checkboxes generated in the View using the following code:
using (Html.BeginForm("UpdateItems", "Home", FormMethod.Post)) {
foreach (myProject.Models.item t in ViewBag.Items)
{
<div>
#Html.CheckBox("chkT", t.selected, new { id = "chkT" + t.id })
#Html.Label(t.description)
</div>
}
<button type="submit" class="mfButton" value="SaveItemss">Save Changes</button>
}
What I need to is to be able to get the values of these generated checkboxes in the controller. So far I have the following:
public ActionResult UpdateItemss(List<bool> chkT)
{
return View();
}
However this being a boolean only give me true or false and the id of the values to which they belong. Is there a way get the name/value pair?
Thanks
Rather than using ViewBag, I would use strongly typed view. I would create a model and add the lists as property. My Models should look like:
public class Test
{
public int Id { get; set; }
public List<Item> Items { get; set; }
}
public class Item
{
public int Id { get; set; }
public bool Selected { get; set; }
public string Description { get; set; }
}
In the controller I am passing the model with dummy data:
public ActionResult Index()
{
Test model = new Test()
{
Id = 1,
Items = new List<Item>()
{
new Item {Id = 1, Selected = false, Description = "Item1"},
new Item {Id = 2, Selected = false, Description = "Item2"},
new Item {Id = 3, Selected = false, Description = "Item3"}
}
};
return View(model);
}
In my View I am using for loop to generate list of Items:
#model MVCTest.Models.Test
#using (Html.BeginForm("UpdateItems", "Home", FormMethod.Post)) {
#Html.HiddenFor(m=>m.Id)
for (int i = 0; i < Model.Items.Count; i++)
{
<div>
#Html.HiddenFor(m=>m.Items[i].Id)
#Html.CheckBoxFor(m=>m.Items[i].Selected, new {id = "checkbox_" + i} )
#Html.DisplayFor(m=>m.Items[i].Description)
</div>
}
<button type="submit" class="mfButton" value="SaveItemss">Save Changes</button>
}
In the controller I am catching the posted model and find all Items inside its Items property:
[HttpPost]
public ActionResult UpdateItems(Test model)
{
if (model != null)
{
// You can access model.Items here
//Do whatever you need
}
return View(model);
}
I would suggest to read this blog: ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries.
Related
I am using view to generate hidden field but the value is always null. Here is my code. Not sure what is wrong. I have list of FillRequest which contains Id and Name properties. it is part of submodel.
#using Computs.Models
#model RequestViewModel
#using (Html.BeginForm(null, null, FormMethod.Post, id = "PostForm", class = "form-horizontal" ))
{
foreach(var reqest in Model.FillRequest)
{
#Html.HiddenFor(m=>reqest.Id)
#Html.HiddenFor(m=>reqest.Name)
}
<button class="btn btn-default">Save</button>
}
After inspecting the post method in controller the Id and Name properties are always null.
Here is the model.
public class RequestViewModel
{
public String TypeOfRequest { get; set; }
public List<FillRequest> FillRequests { get; set; }
}
This is my Controller get method
public ActionResult Index()
{
var requestModel = new RequestViewModel();
requestModel.FillRequests = new List<FillRequest>();
requestModel.FillRequests.add(new FillRequest() { Id = 1, Name = "John"});
requestModel.FillRequests.add(new FillRequest() { Id = 2, Name = "Terry"});
return View(requestModel);
}
For-each loops don't allow you to tie the lambda in #Html.HiddenFor() to a model element. Notice tha tyou pass the parameter 'm' but don't use it:
foreach(var reqest in Model.FillRequest)
{
#Html.HiddenFor(m=>reqest.Id)
#Html.HiddenFor(m=>reqest.Name)
}
Instead use a For loop:
for(var i = 0; i < Model.FillRequest.Count(); i++)
{
#Html.HiddenFor(m=>m.FillRequest[i].Id)
#Html.HiddenFor(m=>m.FillRequest[i].Name)
}
I want to pass a collection of skills id from my view to controller action, i have a dropdownlist of SKILLS :
<select name="skills">
<option value="0">Java</option>
<option value="1">C++</option>
<option value="2">Fortran</option>
<option value="3">ASP</option>
</select>
i want that user can select many skills from dropdown and store their value in a collection ,i.e an array, and then post that array to action in controller as follow [employee and skills have a manytomany relationship]:
[HttpPost]
public ActionResult AddEmp(Employee emp ,IEnumerable<Skills> skills )
{
DBCtx db=new DbCtx();
db.employees.Add(emp);
var emp_id=db.SaveChanges();
var employee=db.employees.Find(emp_id);
foreach(item in skills)
{
var skill = db.skills.Find(item);
employee.skills.Add(skill);
}
db.SaveChanges();
return View();
}
How can i achieve this ,thanks in advance ....
You have quite few options on front end . Razor, Angular, Jquery... To simplfy things in following example i have used Razor view. I dont think you need to pass Skills as a strongly type object as you only need Id of selected Skills . Also in the example i have the skills list static / hard coded into razor view, ideally it should be bound from backend.
Saying that lets assume our Employee View Model as it follows
public class EmployeeViewModel
{
public EmployeeViewModel()
{
SelectedSkills=new List<int>();
}
public int Id { get; set; }
public string Name { get; set; }
public List<int> SelectedSkills { get; set; }
}
public class Skills
{
public int Id { get; set; }
public string Name { get; set; }
}
Then our Controller (EmployeeController.cs) would be .(please ignore the EF logic after data is bound to class)
public class EmployeeController : Controller
{
public ActionResult Index()
{
return View("Employee",new EmployeeViewModel());
}
[HttpPost]
public ActionResult AddEmp(EmployeeViewModel employee)
{
var idOfEmployee=AddEmployee(employee);
foreach (var item in employee.SelectedSkills)
{
AddSkill(idOfEmployee,item);
}
return View("Employee");
}
private void AddSkill(int idOfEmployee, int skillId)
{
// your EF logic
}
private int AddEmployee(EmployeeViewModel emp)
{
// your EF logic, get your id of the inserted employee
return 0;
}
}
Then our Employee.cshtml view could be
#using System.Web.UI.WebControls
#using WebApplication4.Controllers
#model WebApplication4.Controllers.EmployeeViewModel
#{
ViewBag.Title = "Employee";
}
<h2>Employee</h2>
#{var listItems = new List<Skills>
{
new Skills { Id = 0,Name="Java" },
new Skills { Id = 1,Name="C++" },
new Skills { Id = 2,Name="Fortran" }
};
}
#using (Html.BeginForm("AddEmp", "Employee"))
{
#Html.TextBoxFor(m => m.Name, new { autofocus = "New Employee" })
<br/>
#Html.ListBoxFor(m => m.SelectedSkills,
new MultiSelectList(listItems, "Id", "Name",#Model.SelectedSkills)
, new { Multiple = "multiple" })
<input type="submit" value="Submit" class="submit"/>
}
What I have is a form with multiple inputs that I want to use to query database for some results. Form has some default values and it all works, however I have problem submitting it to itself.
The returned error is "No paramaterless constructor defined for this object" and it is caused by SelectList object.
I have tried this solution and made psUserType private with getter and setter and intialized it as empty list, but then my dropDown menu had no values on start. Not sure why GetUserTypes hadn't filled them.
What am I doing wrong here? How does one have both preselected values and also send the same model with user-selected values, while also displaying results on the same page?
Does it make sense to use the same model for all 3 actions: 1. display form and inputs with default values 2. post selected values during submit 3. return results and selected values? I've read this solution also but not sure how to use 2 or 3 separate models here.
Any help is appreciated. Thanks in advance.
Model
public class SearchDownloadsModel
{
public SelectList psUserType { get; private set; } //causes problem on submit
public string psText { get; set; }
public MultiSelectList psColumns { get; private set; }
public IEnumerable<ResultsRowModel> psResults { get; set; }
public SearchDownloadsModel()
{
this.psUserType = GetUserTypes();
this.psColumns = GetColumns();
this.psResults = new List<ResultsRowModel>(); //empty by default
}
public SelectList GetUserTypes()
{
List<SelectListItem> items = new List<SelectListItem>()
{
new SelectListItem { Value="user", Text="Single User" },
new SelectListItem { Value="group", Text="User group" },
...
};
return new SelectList(items, "Value", "Text");
}
public MultiSelectList GetColumns()
{
List<SelectListItem> items = new List<SelectListItem>()
{
new SelectListItem { Value = "user", Text="Username" },
new SelectListItem { Value = "file", Text="Filename" },
new SelectListItem { Value = "titl", Text="Title" },
new SelectListItem { Value = "auth", Text="Author" },
...
};
return new MultiSelectList(items, "Value", "Text");
}
}
public class ResultsRowModel
{
public int ID { get; set; }
public string EventTime { get; set; }
public string FileName { get; set; }
public string FilePath { get; set; }
public string UserName { get; set; }
...
}
View
#model Proj.Models.SearchDownloadsModel
#using (Html.BeginForm("Downloads", "Home", FormMethod.Post))
{
#Html.DropDownListFor(x => x.psUserType, Model.psUserType)
#Html.TextBoxFor(x => x.psText)
#Html.ListBoxFor(x => x.psColumnsSelected, Model.psColumns, new { multiple = "multiple" })
<button type="submit" class="btn btn-primary">Search</button>
}
#if (Model.psResults != null && Model.psResults.Any())
{
<table>
<tr>
<th>User</th>
<th>File</th>
</tr>
#foreach (var row in Model.psResults)
{
<tr>
<td>#row.UserName</td>
<td>#row.FileName</td>
</tr>
}
</table>
}
Controller
[HttpGet]
public ActionResult Downloads()
{
SearchDownloadsModel model = new SearchDownloadsModel();
model.psColumnsSelected = new List<string>() { "user", "file" }; //preselected values
return View(model);
}
[HttpPost]
public ActionResult Downloads(SearchDownloadsModel model)
{
model.psResults = queryDatabase(model);
return View(model);
}
private List<ResultsRowModel> queryDatabase(SearchDownloadsModel model)
{
//...
}
EDIT: Added ResultsRowModel under SearchDownloadsModel
In ASP.NET MVC you should only put variables containing the posted or selected values in the ViewModel class. Select List items are considered extra info and are typically passed from the Action Method into the View (.cshtml) using ViewBag items.
Many of the rendering extension methods are even written specifically for such an approach, leading to code such as this:
Controller
ViewBag.PersonID = persons.ToSelectList(); // generate SelectList here
View
#Html.DropDownListFor(model => model.PersonID)
#* The above will look for ViewBag.PersonID, based on the name of the model item *#
The DropDownListFor generates a <select> element with the name of the property you bind it to. When you submit the form, that name will be included as one of the form fields and its value will be the option's value you select.
You're binding the DropDownList to a property of type SelectList (psUserType) and when your action is called, a new instance of SelectList must be created in order to bind the form field to it. First of all, the SelectList class does not have a parameterless constructor and, thus, your error. Secondly, even if a SelectList could be created as part of model binding, the <select> element is submitting a string value which wouldn't be convertible to SelectList anyways.
What you need to do is to add a string property to your SearchDownloadsModel, for example:
public string SelectedUserType { get; set; }
Then bind the dropdownlist to this property:
#Html.DropDownListFor(x => x.SelectedUserType, Model.psUserType)
When you submit the form, this new property will have the value you selected in the drop down.
Peter's answer and Stephen's comments helped me solve the problem.
Pehaps someone will find it useful.
Any further suggestions always welcome.
Model
public class PobraniaSzukajModel
{
public IEnumerable<SelectListItem> UserTypes { get; set; }
public string psSelectedUserType { get; set; }
public IEnumerable<SelectListItem> Columns { get; set; }
public IEnumerable<string> psSelectedColumns { get; set; }
public string psText { get; set; }
public ResultsModel psResults { get; set; }
}
View
#Html.ListBoxFor(x => x.psSelectedUserType, Model.Columns)
#Html.TextBoxFor(x => x.psText)
#Html.ListBoxFor(x => x.psSelectedColumns, Model.Columns)
Controller
[HttpGet]
public ActionResult Downloads()
{
SearchDownloadsModelmodel = new SearchDownloadsModel();
model.UserTypes = GetUserTypes();
model.Columns = GetColumns();
model.psColumnsSelected = new List<string>() { "user", "file" }; //preselected values
return View(model);
}
[HttpPost]
public ActionResult Downloads(SearchDownloadsModel model)
{
model.UserTypes = GetUserTypes();
model.Columns = GetColumns();
model.psResults = GetResults(model);
return View(model);
}
public SelectList GetUserTypes()
{
//...
}
public MultiSelectList GetColumns()
{
//...
}
public ResultsModel GetResults()
{
//...
}
This is quite simple situation actually, but I can't get how to make this work. So, there is list of checkboxes rendered in PartialView. Data passed from parent ViewModel to child ViewModel in PartialView. All these wrapped by form, unfortunately I can't get the data from PartialView.
Parent ViewModel:
public class UserProgramsViewModel
{
public int Id { get; set; }
[Required(ErrorMessage = "Введите название")]
[DisplayName("Название")]
public string ProgramName { get; set; }
[DisplayName("Пользователь")]
public string UserName { get; set; }
[DisplayName("Пользователь")]
public int UserId { get; set; }
[DisplayName("Дни Программы")]
public ICollection<ProgramDaysDTO> ProgramDays { get; set; }
public IEnumerable<DaysViewModel> Days { get; set;} //Passed to Partial
}
Child ViewModel:
public class DaysViewModel
{
public int Id { get; set; }
public string DayName { get; set; }
}
Parent View:
#Html.Partial("Days", Model.Days)
PartialView (here we are using attribute name 'Days' to bind it to Parent model)
#model IEnumerable<BBN.Admin.ViewModels.DaysViewModel>
<ul class="list-group col-lg-2">
#foreach (var item in Model)
{
<li class="list-group-item"><input type="checkbox" name="Days" value="#item.Id" /> #item.DayName</li>
}
</ul>
Controller:
[HttpPost]
[RBAC]
public async Task<ActionResult> Create(UserProgramsViewModel model)
{
var groups = await _us.GetAll();
ViewBag.Users = groups.Select(x => new SelectListItem
{
Text = x.Login,
Value = x.Id.ToString()
});
var dto = new UserProgramsDTO
{
ProgramName = model.ProgramName,
UserId = model.UserId,
Days = model.Days
};
var result = await _ps.Create(dto);
if (result.IsSuccess == (BLL.Utilities.Enums.IsSuccess)Enums.IsSuccess.Success) return RedirectToAction("Index");
else return View("Create");
}
You can use FormCollection. Assign item.DayName to input's name attribute:
PartialView(fragment):
<li class="list-group-item">
<input type="checkbox" name="#(item.DayName)Days" #if (item.Id > 0) { <text>checked</text> } /> #item.DayName
</li>
Then process FormCollection parameter and fill model's Days property with it's help:
Controller:
[HttpPost]
[RBAC]
public async Task<ActionResult> Create(UserProgramsViewModel model, FormCollection formCollection)
{
model.Days = new List<DaysViewModel>();
foreach(var key in formCollection.AllKeys.Where(x => x.Contains("Days")))
model.Days.Add(new DaysViewModel { Id = formCollection[key] == "on" ? 1 : 0, DayName = key.Replace("Days", "")} );
//other stuff...
}
Have you set values for "Days" in your parent view from controller?
like Suppose your parent view name is "Parent" then you should write like this,
public ActionResult Parent()
{
UserProgramsViewModel loUser = new UserProgramsViewModel();
//Assign Your values here
View(loUser);
}
So may be you will not get Null value here.
I am using a template to display my data in a kendo Treeview. Currently, the data is coming from Asp.net MVC model. I am new to kendo. I saw various kendo examples for binding to local data, but I am confused how to bind my local data inside a template in a kendo treeview.
I know this is a bit vague. Appreciate your prompt response.
Any simple example could help greatly.
Here is basic example of ASP.NET MVC and Kendo UI. For more information see Telerik documentation
View
<script id="TreeViewTemplate" type="text/kendo-ui-template">
<div>
<span style="background-color: Pink">#: item.text #</span>
<span style="background-color: yellow">#: item.id #</span>
<span style="background-color: Green">#: item.expanded #</span>
</div>
</script>
#(
Html.Kendo().TreeView()
.Name("TreeViewTemplateBiding")
.TemplateId("TreeViewTemplate")
.BindTo((IEnumerable<NodeViewModel>)ViewBag.Tree, (NavigationBindingFactory<TreeViewItem> mappings) =>
{
mappings.For<NodeViewModel>(binding => binding.ItemDataBound((item, node) =>
{
item.Id = node.Id.ToString();
item.Text = node.Title;
item.Expanded = node.Expanded;
})
.Children(node => node.Children));
})
)
Controller
public class HomeController : Controller
{
public ActionResult Index()
{
var items = new List<NodeViewModel>();
var root = new NodeViewModel { Id = 1, Title = "Root" };
items.Add(root);
root.Children.Add(new NodeViewModel { Id = 2, Title = "One" });
root.Children.Add(new NodeViewModel { Id = 3, Title = "Two" });
this.ViewBag.Tree = items;
return View();
}
}
public class NodeViewModel
{
public NodeViewModel()
{
this.Expanded = true;
this.Children = new List<NodeViewModel>();
}
public int Id { get; set; }
public string Title { get; set; }
public bool Expanded { get; set; }
public bool HasChildren
{
get { return Children.Any(); }
}
public IList<NodeViewModel> Children { get; private set; }
}