Submitting an actionLink to a form mvc4 - c#

We have a list of action links
Partial View
#foreach (var item in Model.Regions) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.RegionName)
</td>
<td>
<input type="submit" value="Select" />
</td>
#Html.HiddenFor(modelItem => Model.Id)
</tr>
}
</table>
I assume that this isn't the correct way to do this, but if you could point me in the right direction it would be appreciated. I want to submit this data into an existing form
Region View
#using (Html.BeginForm()){
<fieldset>
#Html.Partial("_RegionsPartial");
<legend>Create new region</legend>
<ol>
<li>#Html.LabelFor(m => m.RegionName)</li>
<li>#Html.EditorFor(m => m.RegionName)</li>
</ol>
<input type="submit" value="Next" />
#Html.HiddenFor(model => model.RegionId)
</fieldset>
}
So you can either submit a new one or submit an existing one. Im not sure how to get the id of an existing one into my model. Here is the controller:
public ActionResult Region()
{
var model = new WizardModel();
var getRegions = _facade.FetchRegion();
model.Regions = getRegions;
return View(model);
}
[HttpPost]
public ActionResult Region(WizardModel model)
{
if (model.RegionName != null)
{
var newRegion = _facade.CreateRegion(model.RegionName);
model.RegionId = newRegion.Id;
}
else
{
model.RegionName = _facade.FetchRegion(model.RegionId).RegionName;
}
TempData["suburbModel"] = model;
return RedirectToAction("Suburb");
}
Thanks for taking the time

So heres my example of passing an instance of a model. I've got a view with many courses so I need to click a button and fire an action, thus carrying all data (including relevant ID) of the course clicked. So in the end I carry the instance I need with the hidden fields.:)
My course model...
public class CourseModel
{
public int RecordId { get; set; }
public string StudentNameField { get; set; }
public string SubjectField { get; set; }
public string CatalogField { get; set; }
public string SectionField { get; set; }
public string InstrNameField { get; set; }
public string MtgStartField { get; set; }
public string MtgEndField { get; set; }
}
My main View...Called "CourseList" in Views folder
<div id="container">
<div class="selectLabel">Select a Course:</div><br />
#foreach (var item in Model)
{
#Html.DisplayFor(model=>item)
}
</div>
My Display template - Its a view called "CourseModel" in Shared\DisplayTemplates ...For your display template, you could make a unique model for existing & new. Using your "existing" model in the displaytemplate, it results in multiple forms, each using a button type=submit to submit the form with model instance. Use CSS to model the button like a link. If you still need to use actionlink, carry the iD as one of the params.
#using LecExamRes.Helpers
#model LecExamRes.Models.SelectionModel.CourseModel
#using (Html.BeginForm("CourseList", "Home", null, FormMethod.Post))
{
<div class="mlink">
#Html.AntiForgeryToken()
#Html.EncryptedHiddenFor(model => model.RecordId)
#Html.EncryptedHiddenFor(model => model.CatalogField)
#Html.EncryptedHiddenFor(model => model.SectionField)
#Html.EncryptedHiddenFor(model => model.SubjectField)
#Html.EncryptedHiddenFor(model => model.InstrNameField)
#Html.EncryptedHiddenFor(model => model.MtgStartField)
#Html.EncryptedHiddenFor(model => model.MtgEndField)
<p>
<input type="submit" name="gbtn" class="groovybutton" value="#Model.SubjectField - #Model.CatalogField - #Model.SectionField : #Model.InstrNameField">
</p>
</div>
}
My controller, Courselist [POST] Action...
[ValidateAntiForgeryToken]
[HttpPost]
public ActionResult CourseList(SelectionModel.CourseModel model)
{
//....do something with my model
}

Related

Add DropDownList selected item to a list dynamically in .NET MVC

I have a DropDownList in my razor view, it is getting the values from my model which is populated from Data Base. What I want to achieve is when selecting an option from that DropDownList and clicking a button, show a list of this options selected one below the other, all in the same view and next to every item a link for edit or delete. Then in another screen I can add this final "list" to my data base. This is part of my code:
Model
public class SchedulerViewModel
{
public string Frequency { get; set; }
public string SelectedReportValue { get; set; }
public IEnumerable<SelectListItem> ReportList
{
get
{
List<string> reportlist = DataAccess.retrieveReportList();
return new SelectList(reportlist);
}
}
public string NewCronName { get; set; }
[Display(Name = "OrderDate")]
[DataType(DataType.Date)]
public System.DateTime OrderDate { get; set; }
public IEnumerable<SelectListItem> FrequencyList
{
get
{
List<string> frequencyList = DataAccess.retrieveFrequencyList();
return new SelectList(frequencyList);
}
}
}
Controller
[HttpGet]
public ActionResult AddCron()
{
return View();
}
[HttpPost]
public ActionResult AddCron(SchedulerViewModel model)
{
return View(model);
}
View
<script>
function myFunction() {
$("#div1").load('#Html.LabelFor(model => model.SelectedReportValue)');
}
</script>
.
.
.
<tr>
<td><h5>Frequency: </h5></td>
<td> #Html.DropDownListFor(model => model.Frequency, Model.FrequencyList)</td>
<td><h5>First Run Date: </h5></td>
<td> #Html.TextBoxFor(m => m.OrderDate, new { #class = "form-control datepicker", #id = "datepicker" })</td>
</tr>
<tr class="blank_row">
</tr>
<tr>
<td><p><b>Add Report</b></p></td>
</tr>
<tr>
<td><h5>Report :</h5></td>
<td>#Html.DropDownListFor(model => model.SelectedReportValue, Model.ReportList)</td>
<td><input type="submit" name="Add" value="Add" onclick="myFunction()" /></td>
</tr>
<div id="div1"></div>
I can see the returning selected value in my model in the [HttpPost] method, but still can't make it work in the view. Any suggestion?
and this is what I'm trying to get...
Try get rid of jquery, just use razor :
<div id="div1">
#Html.LabelFor(model => model.SelectedReportValue)
</div>
Base of your comment I suggest you can use jquery to trigger change event and add item to the list manually :
$( "#filetype" ).change(function() {
//code handler to add to list
});

Validation messages not coming in the form displayed through editorfor template

I am creating a simple MVC3 application in which I am using editorfor template to display a simple form containing two fields and these properties are having model-level validation having "Required" attribute.
But when I click the submit button on form and check the ModelState in the controller action, it comes as Invalid but the error messages are not displaying in the form.
I am pasting the code below:
1) Models:
public class EmployeeList
{
public List<Employee> ListOfEmployees { get; set; }
}
public class Employee
{
[Required(ErrorMessage="{0} is required.")]
public int? Id { get; set; }
[Required(ErrorMessage="{0} is required.")]
public string Name { get; set; }
}
2) Controller action:
[HttpPost]
public ActionResult AddEmployee(EmployeeList ListOfEmployees1)
{
if (ModelState.IsValid)
{
service.AddEmployee(ListOfEmployees1);
return RedirectToAction("ListofEmployees");
}
return View();
}
3) Main View (AddEmployee.cshtml):
#using (Html.BeginForm("AddEmployee", "Home", FormMethod.Post, new { #id = "testForm" }))
{
#Html.EditorFor(x => x.ListOfEmployees)
<p>
<input type="submit" value="Add" />
</p>
}
EditorFor template View (Employee.cshtml):
#model test.Models.Employee
<table border="0">
<tr>
<td>#Html.LabelFor(model => model.Id)</td>
<td>#Html.TextBoxFor(model => model.Id)
#Html.ValidationMessageFor(model => model.Id)
</td>
</tr>
<tr>
<td>#Html.LabelFor(model => model.Name)</td>
<td>#Html.TextBoxFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</td>
</tr>
</table>
If I use a partial view instead of editorfor template to display those two fields, than the validation messages comes on the form but the same is not happening with editorfor template.
Can someone please help?
In your action method, return the view with the model
[HttpPost]
public ActionResult AddEmployee(EmployeeList ListOfEmployees1)
{
if (ModelState.IsValid)
{
....
}
return View(ListOfEmployees1);
}
I ques it does not work because you use EditorFor for a model of collection type. Instead try something like:
#for(var i=0; i< Model.ListOfEmployees.Count; i++){
Html.EditorFor(m => m.ListOfEmployees[i])
}

Html.BeginForm passing Model item value

Am using mvc4 and am calling another controller in my view using Html.BeginForm
It work fine!but here am using textbox to pass the value.
How to modify this code so am using
#Html.DisplayFor(modelItem => item.UserName)
....instead of
#Html.TextBox("UserName")
here my view :
image of it:
#using OTMS.Models
#model IEnumerable<OTMS.Models.UserProfile>
#{
ViewBag.Title = "Index";
}
<!-- Table Continer -->
<div class="spacer_10px"></div>
<div class="container clearfix">
<div class="grid_12">
<div class="table_wrapper table_gray">
<table>
<tr>
<th>
<p>User Name</p>
</th>
<th>
<p>Role</p>
</th>
<th>
<p>Role</p>
</th>
</tr>
#if (Model != null) {
foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.UserName)
</td>
<td>
#using(Html.BeginForm("GetRoles", "Account",FormMethod.Post)){
#Html.AntiForgeryToken()
<div class="editor-label">Username : </div>
#Html.TextBox("UserName") //here user will enter user name / I dont want user to enter that ,it should be done Automatically
<div class="spacer_20px"></div>
<div class="button button-orange"> <span class=" form_button clearfix">
<input type="submit" class="submit" name="submit" value="Get Roles for this User" />
</span> </div>//by clicking that will pass the user name to controller (GerRole)/I dont want button
}
</td>
<td>
#using (Html.BeginForm("Submit", "Account", FormMethod.Post))
{
#Html.Hidden("userName", item.UserName)
#Html.DropDownList("selectedRole", (SelectList)ViewBag.Roles)
<div class="button button-orange"> <span class=" form_button clearfix">
<input type="submit" class="submit" name="submit" value="Update Change" />
</span> </div>
}
</td>
</tr>
}
}
</table>
</div> </div>
here my controller :
public ActionResult Index()
{
var model = _db.UserProfiles.ToList();
ViewBag.Roles = new SelectList(Roles.GetAllRoles());
return View(model);
}
[HttpPost]
public ActionResult GetRoles(string UserName)
{
if (!string.IsNullOrWhiteSpace(UserName))
{
ViewBag.RolesForThisUser = Roles.GetRolesForUser(UserName);
SelectList list = new SelectList(Roles.GetAllRoles());
ViewBag.Roles = list;
}
return View("showrole");
}
another view:
image of it :
#{
ViewBag.Title = "showrole";
}
<h2>showrole</h2>
#if(ViewBag.RolesForThisUser != null) {
<text>
<h3>Roles for this user </h3>
<ol>
#foreach (string s in ViewBag.RolesForThisUser){
<li>#s</li>
}
</ol>
</text>
}
What you definetely need to do is to create a view model for your view, for me it looks something like this:
public class UserViewModel
{
public string UserName {get;set;}
public IEnumerable<string> UserRoles { get; set; }
}
Then in your index action you would return a list of these view models.
You certainly could do it like this:
public ActionResult Index()
{
var model = _db.UserProfiles.ToList()
.Select(u => new UserViewModel{
UserName = u.UserName,
UserRoles = Roles.GetRolesForUser(u.UserName)
.AsEnumerable()
})
.ToList();
ViewBag.Roles = new SelectList(Roles.GetAllRoles());
return View(model);
}
but I wouldn't. It's because with this code you're doing one aditional query for every user just to get his roles. I think you need to add roles table to your EntityFramework model and try to do this with single query. So you need to extend your UserProfile with roles:
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
public ICollection<UserRoles> UserRoles { get; set; }
}
[Table("webpages_Roles")]
public class UserRoles
{
[Key]
public int RoleId { get; set; }
public string RoleName { get; set; }
public ICollection<UserProfile> UserProfiles { get; set; }
}
Then update your DbContext with info about many to many relationship between UserProfils and UserRoles:
public class UsersContext : DbContext
{
public UsersContext()
: base("DefaultConnection")
{
}
public DbSet<UserProfile> UserProfiles { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<UserRoles>()
.HasMany<UserProfile>(r => r.UserProfiles)
.WithMany(u => u.UserRoles)
.Map(m =>
{
m.ToTable("webpages_UsersInRoles");
m.MapLeftKey("UserId");
m.MapRightKey("RoleId");
});
}
}
After that in your index action - you can simply do:
var model = _db.UserProfiles.Select(u => new UserViewModel()
{
UserName = u.UserName,
UserRoles = u.UserRoles.Select(ur=>ur.RoleName)
}).ToList();
And it will be one query instead of several in cycle.
EDIT:
Your model changed so you need to change #model IEnumerable<OTMS.Models.UserProfile> to #model IEnumerable<OTMS.Models.UserViewModel>
And then:
#foreach(var user in Model)
{
//display user
#foreach(var role in user.UserRoles)
{
//display roles with #role
}
}
If you want to use DisplayTemplates - you can move logic for displying user into template. For this you need to create view by path
~/Views/Shared/DisplayTemplates/UserViewModel.cshtml
#model OTMS.Models.UserViewModel
//display user
#foreach(var role in user.UserRoles)
{
//display roles with #role
}
then in Index.cshtml you can change code to this:
#foreach (var user in Model)
{
#Html.DisplayFor(n => user)
}
First and for All ,The Main Confusion is with this Helper..have a Breif Look here
Use HiddenFor when you want to provide posted data that the user does not need to be aware of."
Use DisplayFor when you want to show records but not allow them to be editted.
Use TextBoxFor when you want to allow user input or allow the user to edit a field.
`
Now your question is Like this..
How can i use displayfor to hit my controller!!!!
You could accomplish this with a duo of HiddenFor and DisplayFor. Use HiddenFor to have the values ready to be posted, and DisplayFor to show those values.
so to meet your Requirement
<div class="editor-label"> Username : </div>
#Html.TextBox("UserName")
Replace
<div class="editor-label"> Username : </div>
#Html.HiddenFor(modelItem=>item.username)
#Html.DisplayFor(modelItem=>item.username)
Remember Displayfor Renders Only Label In the Browser,to post it back to Controller you need HiddenFor
Try this:
Controller
[HttpPost]
public ActionResult GetRoles(string UserName)
{
if (!string.IsNullOrWhiteSpace(UserName))
{
ViewBag.RolesForThisUser = Roles.GetRolesForUser(UserName);
SelectList list = new SelectList(Roles.GetAllRoles());
ViewBag.Roles = list;
}
return View("......");
}
View
#ViewBag.Name
#using(Html.BeginForm("GetRoles", "Account")){
#Html.AntiForgeryToken()
<div class="editor-label">Username : </div>
#Html.TextBox("UserName")
<div class="spacer_20px"></div>
<div class="button button-orange">
<span class=" form_button clearfix">
<input type="submit" class="submit" name="submit" value="Get Roles for this User" />
</span>
</div>
}
Here is the DEMO

How do i save a list of objects in my ViewModel using EF DB Context?

I have a model women which is part of my db context and a view Model womenEditmodel which conatins a list of women items. I am using a partialview to loop through this list and display an editable Grid or List in my view. These are my models:
public class Women
{
public string ID { get; set; }
public string FirstName {get; set;}
public string LastName {get; set;}
}
public class WomenEditModel
{
public List<Women> WomenList { get; set; }
}
My view has this loop for injecting into my view rows for the women records
#foreach (Women women in Model.Womens)
{
Html.RenderPartial("WomenEditor", women);
}
which i display using a table. So now users can edit the list and post or save changes.
my partialview looks like:
#model XXX.Models.Women
#using (Html.BeginCollectionItem("Women")) {
<td>
#Html.HiddenFor(model => model.ID)
</td>
<td>
#Html.TextBoxFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</td>
<td>
#Html.TextBoxFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</td>
}
My http post action method looks like this
[HttpPost]
public ActionResult PostWomen(WomenEditModel model)
{
/*I need to iterate through the returned list and save all
changes to the db.*/
return RedirectToAction("Index");
}
How do i loop through the model WomenEditModel recieived at the post action method and save changes to the women list back to db?
Thanks in advance!!
I just got back to my machine. Here is how you can acheive it, if you haven't already.
My Action which renders the list
public ActionResult Index()
{
List<Women> womens = new List<Women>
{
new Women
{
Id=1,
FirstName = "Women1",
LastName = "Lastname1"
},
new Women
{
Id=2,
FirstName = "Women2",
LastName = "Lastname2"
}
};
WomenList womenList=new WomenList();
womenList.Womens = womens;
return View(womenList);
}
The action where the list is posted.
public ActionResult SaveWomens(List<Women> womenList)
{
System.Diagnostics.Debugger.Break();
//Your save logic goes here
return View("");
}
Partial View (Dont know whether it is required)
#model List<MvcApplication1.Models.Women>
<table>
#for (var i = 0; i < Model.Count; i++)
{
<tr>
<td>
#Html.TextBoxFor(m => m[i].Id)
</td>
<td>#Html.TextBoxFor(m => m[i].FirstName)
</td>
<td>#Html.TextBoxFor(m => m[i].LastName)
</td>
</tr>
}
</table>
And here is the view
#model MvcApplication1.Models.WomenList
#{
ViewBag.Title = "Home Page";
}
#section featured {
}
#using (Html.BeginForm("SaveWomens", "Home", FormMethod.Post))
{
#Html.Partial("_Women", Model.Womens)
<input type="submit" value="save" />
}
You can achieve it as follows
foreach (var item in womenList)
{
var obj = new Womens();
//Assign values to obj for eg: obj.prop = item.prop
dataContext.Womens.AddObject(obj);
}
dataContext.SaveChanges();

MVC4 Selecting from a List of Items in a view

I'm looking for a way to select from a lists of items that I have retrieve from a database. I send these items to a view and I want to select from the list and return this to the controller to populate a secondary table within the database. I can pass the items to the view and get them to display but I can not seem to pass these items back to the controller.
Controller Calls (Updated Again):
public ActionResult Create()
{
var myMeal = new CreateMeal();
List<ProductsToInclude> pti = new List<ProductsToInclude>();
myMeal.ProductsToInclude = pti;
IList<Product> prods = db.Products.ToList();
foreach(var prod in prods)
{
pti.Add(new ProductsToInclude { Product = prod });
}
return View(myMeal);
}
//
// POST: /Meal/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(CreateMeal myMeal)
{
if (ModelState.IsValid)
{
/* Add code to handle my meal and create a meal for data base*/
db.Meals.Add(meal);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(pti);
}
The ProductsToInclude ViewModel
public class ProductsToInclude
{
public Product Product { get; set; }
public Boolean Include { get; set; }
}
New CreateMeal ViewModel:
public class CreateMeal
{
public String Name { get; set; }
public IList<ProductsToInclude> ProductsToInclude { get; set; }
}
The Create View:
#model MealPlanner.ViewModels.CreateMeal
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Meal</legend>
<div>
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name)
</div>
<div>
#Html.EditorFor(m => m.ProductsToInclude)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
And the Editor Templete (UpDated) :
#model MealPlanner.ViewModels.ProductsToInclude
<tr>
<td>
#Html.CheckBoxFor(m => m.Include)
</td>
<td>
#Model.Product.Name
#Model.Product.Quantity
#Model.Product.unit.UnitName
#Html.HiddenFor(m => m.Product.Name)
#Html.HiddenFor(m => m.Product.Quantity)
#Html.HiddenFor(m => m.Product.unit.UnitName)
</td>
</tr>
Meal Model:
public class Meal
{
public int MealId { get; set; }
public String Name { get; set; }
//public virtual IList<Product> Products { get; set; }
public int UserId { get; set; }
}
UPDATE:
Switching over to EditorTemplete I can not get this to display. I get an error now with myMeal.ProductsToInclude.Add(new ProductsToInclude { Product = prod, Include = false}); in the Create Method. prod is populated has 8 products in it.
You have two basic problems here. (and a third, you're not passing any model to the view, but your view is expecting a Meal object) First, is that you are posting a different model than you are rendering from. So, when you post your form it's not going to recognize the Meal.Name object because the post action is expecting a list of ProductsToInclude.
If you don't intend to change the value of the Meal.Name, then I would suggest rendering it with a DisplayFor rather than an EditorFor.
Second, the way you are rendering your form fields will not create the correct naming structure to allow the default model binder to bind to the collections. You can use EditorTemplates, which is the method I prefer.
Instead of using the Partial, you would create an editor template called ProductsToInclude.cshtml, set the model type to be ProductsToInclude (without the List) and then render as if it were a single item. You will also want to move the table and header info out into the main view.
EditorTemplates handle this situation without having to do anything special. They automatically iterate over collections, and they render names correctly. Use them wherever you can.
<div>
<table>
<tr>
<th>
#Html.DisplayName("Include")
</th>
<th>
#Html.DisplayName("Available Products")
</th>
<th></th>
</tr>
#Html.EditorFor(m => m.ProductsToInclude)
</table>
</div>
Your ProductsToInclude.cshtml should live in a folder called EditorTemplates in either ~/Views/Shared or in your local view folder.
#model ProductsToInclude
<tr>
<td>
#Html.CheckBoxFor(m => m.Include)
</td>
<td>
#Html.DisplayFor(m => m.Product.Name)
#Html.DisplayFor(m => m.Product.Quantity)
#Html.DisplayFor(m => m.Product.unit.UnitName)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=Model.PrimaryKey }) |
#Html.ActionLink("Details", "Details", new { id=Model.PrimaryKey }) |
#Html.ActionLink("Delete", "Delete", new { id=Model.PrimaryKey })
</td>
</tr>

Categories