I am creating a MVC application. I open a View in a controller like this:
return RedirectToAction("AddGroupsQty", "Account", new { qty = model.qty, id = id });
The AddGroupsQty Controller looks like this:
public ActionResult AddGroupsQty(int qty, int id)
{
var model = new AddGroupsQtyViewModel();
model.subject_id = id;
model.qty = qty;
ClassDeclarationsDBEntities1 entities1=new ClassDeclarationsDBEntities1();
var subj = entities1.Subjects
.Where(b => b.class_id == model.subject_id)
.FirstOrDefault();
model.subject_name = subj.name;
if (ModelState.IsValid)
{
int maxId = 0;
int total = 0;
total = entities1.Groups.Count();
if (total == 0)
{
maxId = 0;
}
else
{
maxId = entities1.Groups.Max(u => u.group_id);
}
for (int i = 0; i < qty; i++)
{
var teacher = entities1.Users
.Where(b => b.email.Replace(" ", String.Empty) == model.teacher_emails[i].Replace(" ", String.Empty))
.FirstOrDefault();
var group=new Models.Group(id, maxId+1, model.group_names[i], teacher.user_id);
}
return RedirectToAction("OperationSuccess", "Account");
}
return View(model);
}
The ViewModel:
public class AddGroupsQtyViewModel
{
public int qty { get; set; }
public int subject_id { get; set; }
public string subject_name { get; set; }
[Required]
[Display(Name = "Name of group")]
public List<string> group_names { get; set; }
[Required]
[Display(Name = "Email of teacher")]
[RegularExpression(#"^[a-zA-Z0-9._%+-]+(#student.mini.pw.edu.pl|#mini.pw.edu.pl)$", ErrorMessage = "Registration limited to university domain email.")]
public List<string> teacher_emails { get; set; }
}
And the problem is that whenever the view is called, the validation of the form in the window is always Valid. The view looks like this:
#using System.IdentityModel.Configuration
#using System.Web.UI.WebControls
#model ClassDeclarationsThsesis.Models.AddGroupsQtyViewModel
#{
ViewBag.Title = "AddGroupsQty";
}
<h2>Add Groups to #Model.subject_name</h2>
#if (Model != null)
{
using (Html.BeginForm("AddGroupsQty", "Account", new { qty = Model.qty, Model.subject_id }, FormMethod.Post, new { #class = "form-horizontal", role = "form", }))
{
#Html.AntiForgeryToken()
<h4>Insert data</h4>
<hr />
<table>
<tr>
<th>
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.group_names, new { #class = "col-md-2 control-label" })
</div>
</th>
<th>
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.teacher_emails, new { #class = "col-md-2 control-label" })
</div>
</th>
</tr>
#for (int i = 0; i < Model.qty; i++)
{
<tr>
<th>
<div class="form-group">
<div class="col-md-10">
#Html.TextBoxFor(m => m.group_names[i], new { #class = "form-control" })
</div>
</div>
</th>
<th>
<div class="form-group">
<div class="col-md-10">
#Html.TextBoxFor(m => m.teacher_emails[i], new { #class = "form-control" })
</div>
</div>
</th>
</tr>
}
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Submit" />
</div>
</div>
}
}
I have no Idea what is wrong about this piece of code, but anytime I open this window, it is straight away Valid and then the error occurs in controller, because it enters IF, but it should validate the form first.
Validation is performed based on the model binder. So in controller action, it should be the view model as a parameter.
Public ActionResult AddGroupsQty(AddGroupsQtyViewModel value)
Related
I am building a Todo list application
Model class Todo.cs is as below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.ComponentModel.DataAnnotations;
namespace Todo_Application.Models
{
public class Todo
{
[Display(Name ="Item Id")]
[Required]
public int ItemId { get; set; }
[Display(Name ="Description")]
[Required(ErrorMessage ="Description is required")]
[StringLength(100,MinimumLength =10)]
public string Description { get; set; }
[Display(Name = "Start Date")]
[Required(ErrorMessage ="Start date is required")]
public DateTime StartDate { get; set; }
[Display(Name = "End Date")]
[Required(ErrorMessage ="End date is required")]
public DateTime EndDate { get; set; }
[Display(Name = "Status of completion")]
public Status StatusOfCompletion { get; set; }
public class SortByStartDate : IComparer<Todo>
{
public int Compare(Todo x, Todo y)
{
return x.StartDate.CompareTo(y.StartDate);
}
}
public class SortByEndDate:IComparer<Todo>
{
public int Compare(Todo x,Todo y)
{
return x.EndDate.CompareTo(y.EndDate);
}
}
}
}
I have a home controller with index, add and edit as actions as below.
public class HomeController : Controller
{
public static List<Todo> ListOfTodos = new List<Todo>()
{
new Todo()
{
ItemId=101,
Description="Plan the module",
StartDate=DateTime.Now,
EndDate=DateTime.Now.AddDays(4),
StatusOfCompletion=Status.YetToStart},
new Todo()
{
ItemId=102,
Description="Dry run the plan",
StartDate=DateTime.Now.AddDays(3),
EndDate=DateTime.Now.AddDays(5),
StatusOfCompletion=Status.YetToStart
}
};
public ActionResult Index()
{
return View(ListOfTodos);
}
static int max = 0;
void maxid()
{
foreach (var v in ListOfTodos)
max = Math.Max(max, v.ItemId);
}
public ActionResult Add()
{
maxid();
Session["id"]= max;
return View();
}
[HttpPost]
public ActionResult Add(Todo t)
{
//if(!ModelState.IsValidField("ItemId"))
//{
// ModelState.AddModelError("ItemId", "invalid id");
//}
//if(string.IsNullOrEmpty(t.Description))
//{
// ModelState.AddModelError("Description", "Description field is empty");
//}
//if (!ModelState.IsValidField("StartDate"))
// ModelState.AddModelError("StartDate", "invalid start date");
//if (!ModelState.IsValidField("EndDate"))
// ModelState.AddModelError("EndDate", "invalid end date");
//if (!ModelState.IsValidField("StatusOfCompletion"))
// ModelState.AddModelError("StatusOfCompletion", "invalid status");
if(ModelState.IsValid)
{
ListOfTodos.Add(t);
return View("Index", ListOfTodos);
}
//ModelState.AddModelError("", "Invalid data");
return View();
}
public ActionResult Delete(int id)
{
ListOfTodos.Remove(ListOfTodos.Find(m => m.ItemId == id));
return View("Index",ListOfTodos);
}
public ActionResult Edit(int id)
{
Todo t = ListOfTodos.Find(m => m.ItemId == id);
return View(t);
}
[HttpPost]
public ActionResult Edit(Todo t1)
{
if (ModelState.IsValid)
{
Todo t = ListOfTodos.Find(m => m.ItemId == t1.ItemId);
t.ItemId = t1.ItemId;
t.Description = t1.Description;
t.StartDate = t1.StartDate;
t.EndDate = t1.EndDate;
t.StatusOfCompletion = t1.StatusOfCompletion;
return View("Index", ListOfTodos);
}
return View();
}
[HttpPost]
public ActionResult SortBy(string Sortby)
{
Todo t = new Todo();
if (Sortby.Equals("Start Date"))
ListOfTodos.Sort(new Todo.SortByStartDate());
else if (Sortby.Equals("End Date"))
ListOfTodos.Sort(new Todo.SortByEndDate());
return View("Index", ListOfTodos);
}
}
And also the views as below:
Index.cshtml
#model IEnumerable<Todo_Application.Models.Todo>
#{
ViewBag.Title = "Index";
int count = 0;
}
<h2>List of todo items</h2>
Add New Item
<form method="post" action="/Home/SortBy">
Sort By #Html.DropDownList("Sortby", new SelectList(new List<string>() { "Start Date", "End Date" }),
new { htmlAttributes = new {#class = "form-control"}})
<input type="submit" value="Go" class="btn btn-primary" />
</form>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Serial No</th>
<th>Item Id</th>
<th>Description</th>
<th>Start Date</th>
<th>End Date</th>
<th>Completion Status</th>
</tr>
</thead>
<tbody>
#{
foreach(var v in Model)
{
<tr>
<td>
#(count=count+1)
</td>
<td>
#v.ItemId
</td>
<td>
#v.Description
</td>
<td>
#v.StartDate.ToShortDateString()
</td>
<td>
#v.EndDate.ToShortDateString()
</td>
<td>
#v.StatusOfCompletion
</td>
<td>
#Html.ActionLink("edit", "Edit", new { id = v.ItemId })
</td>
<td>
#Html.ActionLink("delete", "Delete", new { id = v.ItemId })
</td>
</tr>
}
}
</tbody>
</table>
and Edit.cshtml as below
#model Todo_Application.Models.Todo
#{
ViewBag.Title = "Edit";
}
<h2>Edit Item</h2>
#using (Html.BeginForm("Edit", "Home", FormMethod.Post))
{
<div class="col-sm-3">
<div class="form-group">
#Html.EditorFor(m => m.ItemId,
new { htmlAttributes = new {#class = "form-control",type="hidden"} })
</div>
<div class="form-group">
#Html.LabelFor(m => m.Description)
#Html.EditorFor(m => m.Description,
new { htmlAttributes = new { #class = "form-control"} })
#Html.ValidationMessageFor(m=>m.Description)
</div>
<div class="form-group">
#Html.LabelFor(m => m.StartDate)
#Html.EditorFor(m => m.StartDate,
new { htmlattributes = new { #class = "form-control datepicker",
type="date" } })
#Html.ValidationMessageFor(m=>m.StartDate)
</div>
<div class="form-group">
#Html.LabelFor(m => m.EndDate)
#Html.EditorFor(m => m.EndDate,
new { htmlattributes = new { #class = "form-control datepicker",
type="date"} })
#Html.ValidationMessageFor(m=>m.EndDate)
</div>
<div class="form-group">
#Html.LabelFor(m => m.StatusOfCompletion)
#Html.EnumDropDownListFor(m => m.StatusOfCompletion,
new { htmlattributes = new { #class = "form-control" } })
</div>
<input type="submit" value="Update" class="btn btn-primary" />
</div>
}
index view just displays all the items.
edit view is used to update the item details.
The moment I click on the edit link, it takes me to edit view but does not populate the date fields. It populates description field.
How to populate the date fields?
Updated:
In the home controller, I defined the a list that has values of type Todo. The startdate will be today's date and time. When I displayed on the index page, I just wanna display date which I am able to do by using ToShortDateString(). Now when i click on edit, only the date should be populated and not time. Initially i used a textbox so it used to display both date and time. Later, I added datepicker class , now nothing gets populated instead the format dd/mm/yyyy is shown.
If you want to display the default datetime meanwhile can choose the datetime, Razor doesn't support that. If you want to display date while loading the edit page in that case it should be type of string in that case it will be like textbox. If you want that as a date picker I think in that case we should change the text to date picker.
Here is a working demo:
Model:
public class Todo
{
[Display(Name ="Item Id")]
[Required]
public int ItemId { get; set; }
[Display(Name ="Description")]
[Required(ErrorMessage ="Description is required")]
[StringLength(100,MinimumLength =10)]
public string Description { get; set; }
[Display(Name = "Start Date")]
[Required(ErrorMessage ="Start date is required")]
public DateTime StartDate { get; set; }
[Display(Name = "End Date")]
[Required(ErrorMessage ="End date is required")]
public DateTime EndDate { get; set; }
[Display(Name = "Text To Date Picker")]
public Nullable<DateTime> TestDate { get; set; }
}
View:
#model DotNet6MVCWebApp.Models.Todo
#{
ViewBag.Title = "Edit";
}
<h2>Edit Item</h2>
#using (Html.BeginForm("Edit", "Todo", FormMethod.Post))
{
<div class="col-sm-3">
<div class="form-group">
#Html.EditorFor(m => m.ItemId,
new { htmlAttributes = new {#class = "form-control",type="hidden"} })
</div>
<div class="form-group">
#Html.LabelFor(m => m.Description)
#Html.EditorFor(m => m.Description,
new { htmlAttributes = new { #class = "form-control"} })
#Html.ValidationMessageFor(m=>m.Description)
</div>
<div class="form-group">
#Html.LabelFor(m => m.StartDate)
#Html.EditorFor(m => m.StartDate,
new { htmlattributes = new { #class = "form-control datepicker",
type="date" } })
#Html.ValidationMessageFor(m=>m.StartDate)
</div>
<div class="form-group">
#Html.LabelFor(m => m.EndDate)
#Html.EditorFor(m => m.EndDate,
new { htmlattributes = new { #class = "form-control datepicker",
type="date"} })
#Html.ValidationMessageFor(m=>m.EndDate)
</div>
<div class="form-group">
#Html.LabelFor(m => m.TestDate)
#Html.TextBoxFor(model => model.TestDate, "{0:d/M/yyyy}",new { id="textTodate", #class = "form-control", type = "text" })
</div>
<input type="submit" value="Update" class="btn btn-primary" />
</div>
}
Script:
#section scripts {
<script>
$(document).ready(function () {
$("#textTodate").click(function (e) {
$("#textTodate").prop('type','date');
});
});
</script>
}
Note: This is loading with the existing date. While user clicking it to modify I am changing it from textbox to date picker by its click event.
Output:
I am having a problem sending parent ID to child ID, even if I do, I want to display the child's data only of a particular parent. In my code, List is the parent, and Notes are the children. When I create a List, I have redirected to Notes Index Page (Different Controller) along with ID but in all lists, I can see the same notes. I am using TempData in NotesController to keep hold of that ID.
List Controller:
//Index
public ActionResult Index()
{
return View(db.Lists.ToList());
}
//Create
public ActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(ListViewModel lists)
{
if (ModelState.IsValid)
{
Lists list = new Lists();
list.CreationDate = DateTime.Now;
list.ListName = lists.ListName;
db.Lists.Add(list);
db.SaveChanges();
int? idFromView = list.Id;
return RedirectToAction("Index", "NotesInLists", new { id = idFromView });
}
return View(lists);
}
Notes Controller:
//Index
public ActionResult Index(int? id)
{
TempData["idFromView"] = id;
return View(db.NotesInLists.ToList());
}
//Create
public ActionResult CreateWithtext()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult CreateWithtext(NoteTagViewModel notesInList)
{
if (ModelState.IsValid)
{
List<string> TagsList = notesInList.TagsList.Split(',').ToList();
NotesInList note = new NotesInList();
int tempDataId = (int)TempData["idFromView"];
note.CreationDate = DateTime.Now;
note.ListName = notesInList.ListName;
note.TextDescription = notesInList.TextDescription;
note.listID = tempDataId;
db.NotesInLists.Add(note);
db.SaveChanges();
//saving tags
foreach (var item in TagsList)
{
Tags tag = new Tags();
tag.CreationDate = DateTime.Now;
tag.TagName = item;
tag.Note_Id = note.Id;
db.Tags.Add(tag);
}
db.SaveChanges();
return RedirectToAction("Index", new { id = tempDataId });
}
return View(notesInList);
}
Here, in this NotesController, I am also saving tags and it is working fine, but the main issue is with List. Also using ViewModels but that is of no concern to me for now. If I try accessing List using
Lists list = new List();
I still am not able to check and compare that ID with that List ID, it throws an exception.
List Model:
namespace NoteBlocks.Models
{
public class Lists
{
public int Id { get; set; }
[Required]
[Display(Name = "List Name")]
public string ListName { get; set; }
[Display(Name = "Creation Date")]
public DateTime? CreationDate { get; set; }
[Display(Name = "Last Updated")]
public DateTime? UpdateDate { get; set; }
}
}
List ViewModel:
namespace NoteBlocks.ViewModels
{
public class ListViewModel
{
public int Id { get; set; }
[Required]
[Display(Name = "List Name")]
public string ListName { get; set; }
[Display(Name = "Creation Date")]
public DateTime? CreationDate { get; set; }
[Display(Name = "Last Updated")]
public DateTime? UpdateDate { get; set; }
}
}
Notes Model:
namespace NoteBlocks.Models
{
public class NotesInList
{
public int Id { get; set; }
[Required]
[Display(Name = "List Name")]
public string ListName { get; set; }
[DataType(DataType.Date)]
[Display(Name = "Creation Date")]
public DateTime? CreationDate { get; set; }
[DataType(DataType.Date)]
[Display(Name = "Last Updated")]
public DateTime? UpdateDate { get; set; }
public string customFile { get; set; }
[Display(Name = "Enter Note Content")]
public string TextDescription { get; set; }
public Lists List { get; set; }
public int listID { get; set; }
}
}
Notes ViewModel:
namespace NoteBlocks.Models
{
public class NoteTagViewModel
{
public int NoteId { get; set; }
[Required]
[Display(Name = "List Name")]
public string ListName { get; set; }
[DataType(DataType.Date)]
[Display(Name = "Creation Date")]
public DateTime? CreationDate { get; set; }
[DataType(DataType.Date)]
[Display(Name = "Last Updated")]
public DateTime? UpdateDate { get; set; }
public string customFile { get; set; }
[Display(Name = "Enter Note Content")]
public string TextDescription { get; set; }
//multiple tags
public string TagsList { get; set; }
public Lists List { get; set; }
public int ListId { get; set; }
}
}
Created a foreign key but it is not working.
HTML - List Index
#model IEnumerable<NoteBlocks.Models.Lists>
#{
ViewBag.Title = "List";
//ViewBag.Id = model.Lists.Id;
}
<h2>List</h2>
<p>
#Html.ActionLink(" Create New List", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.ListName)
</th>
<th>
#Html.DisplayNameFor(model => model.CreationDate)
</th>
<th>
#Html.DisplayNameFor(model => model.UpdateDate)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
//using ActionLink to open list of notes for that particular List
//and passing particular List ID from here if already created
#Html.ActionLink(item.ListName, "Index", "NotesInLists", new { id = item.Id }, null)
#*#TempData.Peek("tempDataId")*#
</td>
<td>
#Html.DisplayFor(modelItem => item.CreationDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.UpdateDate)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
#Html.ActionLink("Details", "Details", new { id=item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
</table>
HTML - List Create
#model NoteBlocks.Models.Lists
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>List</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.ListName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ListName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ListName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.CreationDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.CreationDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.CreationDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.UpdateDate, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.UpdateDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.UpdateDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
HTML - Notes Index
#model IEnumerable<NoteBlocks.Models.NotesInList>
#{
ViewBag.Title = "List Notes";
}
<h2>List Notes</h2>
<p id="buttonsInPTag">
<button type="button" class="btn btn-primary" id="addButton1"><span class="glyphicon glyphicon-plus">#Html.ActionLink(" Create Textual Note", "CreateWithtext")</span></button>
<button type="button" class="btn btn-primary" id="addButton2"><span class="glyphicon glyphicon-plus">#Html.ActionLink(" Create Note from Document", "CreateWithDoc")</span></button>
<button type="button" class="btn btn-primary" id="addButton3"><span class="glyphicon glyphicon-plus">#Html.ActionLink(" Create Image Note", "CreateWithImage")</span></button>
<button type="button" class="btn btn-primary" id="addButton4"><span class="glyphicon glyphicon-plus">#Html.ActionLink(" Create Audio / Video Note", "CreateWithMedia")</span></button>
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.ListName)
</th>
<th>
#Html.DisplayNameFor(model => model.CreationDate)
</th>
<th>
#Html.DisplayNameFor(model => model.UpdateDate)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ListName)
</td>
<td>
#Html.DisplayFor(modelItem => item.CreationDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.UpdateDate)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
#Html.ActionLink("Details", "Details", new { id = item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
}
</table>
HTML - Notes CreateWithText
#model NoteBlocks.Models.NoteTagViewModel
#{
ViewBag.Title = "Create Note with Text";
}
<h2>Create Note with Text</h2>
#using (Html.BeginForm("CreateWithText", "NotesInLists", FormMethod.Post))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.ListName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.ListName, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.ListName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TextDescription, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<textarea cols="50" rows="12" class=form-control id="TextDescription" name="TextDescription"></textarea>
#Html.ValidationMessageFor(model => model.TextDescription, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.Label("Tags", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="text" id="tagsField" name="tagsField" class=form-control data-role="tagsinput" />
<input type="hidden" name="TagsList" id="TagsList" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section scripts
{
<script>
$(document.body).on('focusout', '.bootstrap-tagsinput input', () => {
let array = $('#tagsField').tagsinput('items');
$("#TagsList").val(array);
})
</script>
}
I am stuck to this point. Please guide. p.s. using code first approach.
There is no filter applied to the query that gets notes in your Index action of notes controller.
I think adding where method;
.Where(x=>x.listID == id)
will solve your problem.
//Index
public ActionResult Index(int? id)
{
TempData["idFromView"] = id;
return View(db.NotesInLists/*.Where(x=>x.listID == id)*/.ToList());
}
I am creating a form in a for loop in Razor.
#model SignAPI.ViewModels.ChannelManagerViewModel
#{
ViewBag.Title = "Index";
}
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
crossorigin="anonymous"></script>
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#using (Html.BeginForm("Index", "ChannelManager", FormMethod.Post))
{
<div class="form-group">
#Html.LabelFor(m => m.CustomerNames, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.CustomerNameSelected, Model.CustomerNames, "Select", new { onchange = "this.form.submit();", #class = "form-control form-control-sm", #id = "CustomerDdl", #data_val = false })
#Html.ValidationMessageFor(m => m.CustomerNameSelected, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Devices, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(x => x.DeviceSelected, Model.Devices, "Select", new { onchange = "this.form.submit();", #class = "form -control form-control-sm", #id = "DeviceDdl", #data_val = false })
#Html.ValidationMessageFor(m => m.DeviceSelected, "", new { #class = "text-danger" })
</div>
</div>
}
#using (Html.BeginForm("SaveData", "ChannelManager", FormMethod.Post))
{
<table class="table table-striped" style="font-size:small;">
<thead>
<tr>
<th>
Channel Name
</th>
<th>
UOM's'
</th>
<th>
Channel UOM
</th>
<th>
Calculated
</th>
<th></th>
</tr>
</thead>
<tbody>
#{ var channelNames = Model.ChannelNames.Select(x => x.ChannelName).OrderByDescending(x => Model.ChannelName).ToList();
for (int count = 0; count < channelNames.Count(); count++)
{
var channel = channelNames[count];
var ddlId = ("ddlId" + count).ToString();
var txtBoxId = ("txtBoxId" + count).ToString();
<tr>
#Html.HiddenFor(x => x.CustomerNameSelected)
#Html.HiddenFor(x => x.DeviceSelected)
<td>
#Html.Label(channel)
</td>
<td>
#Html.DropDownListFor(x => x.UomSelected, Model.Uom, "Select", new { #class = "form-control form-control-sm", #id = #ddlId, #data_val = false })
<script type="text/javascript">
$('##ddlId').change(function () {
$('##txtBoxId').val($(this).val());
});
</script>
</td>
<td>
#Html.EditorFor(x => x.ChannelDataToSave, Model.UomSelected, new { htmlAttributes = new { #id = #txtBoxId, #class = "form-control form-control-sm" } })
#Html.ValidationMessageFor(x => x.ChannelType, "", new { #class = "text-danger" })
</td>
<td>
#Html.CheckBoxFor(x => x.Calculated)
</td>
</tr>
}
}
</tbody>
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-sm btn-primary" />
</div>
</div>
}
</div>
I want to pass all of the data created in the second form back to my Action using the ViewModel:
public class ChannelManagerViewModel
{
[Display(Name = "Select a customer")]
public IEnumerable<SelectListItem> CustomerNames { get; set; }
public string CustomerNameSelected { get; set; }
[Display(Name = "Select a device")]
public IEnumerable<SelectListItem> Devices { get; set; }
public string DeviceSelected { get; set; }
[Display(Name = "Channel Name")]
public string ChannelName { get; set; }
[Display(Name = "Channel Type")]
public string ChannelType { get; set; }
[Display(Name = "Calculated")]
public bool Calculated { get; set; }
public int ChannelCount { get; set; }
public List<ChannelManagerModel> ChannelNames { get; set; }
public List<ChannelManagerViewModel> ChannelDataToSave { get; set; }
private List<string> UomList {
get
{
var l = new List<string>();
l.Add("Electricity");
l.Add("Gas");
l.Add("Water");
l.Add("Heat");
l.Add("kWh");
l.Add("Wh");
l.Add("kVarh");
l.Add("Wh");
l.Add("Volts 1");
l.Add("Volts 2");
l.Add("Volts 3");
l.Add("Current 1");
l.Add("Current 2");
l.Add("Current 3");
l.Add("Hz");
l.Add("Litres");
l.Add("Cubic Metres");
l.Add("Cubic Feet");
return l;
}
}
public IEnumerable<SelectListItem> Uom {
get {
List<SelectListItem> sl = new List<SelectListItem>();
foreach (var item in UomList)
{
sl.Add(new SelectListItem() { Text = item, Value = item });
};
return sl;
}
set { }
}
public string UomSelected { get; set; }
}
I want to then save the data.
I have tried a number of things including using a partial view, but that doesn't work. I have also tried adding the loop index
#Html.EditorFor(x => x[count].ChannelDataToSave, Model.UomSelected, new { htmlAttributes = new { #id = #txtBoxId, #class = "form-control form-control-sm" } })
but this just tells me Cannot apply indexing with [] to an expression of type 'ChannelManagerViewModel'
I was hoping that the form would create a List<ChannelManagerViewModel> to pass back to the Action
[HttpPost]
public ActionResult SaveData(ChannelManagerViewModel vm)
{
//Do some stuff
return View(vm);
}
All it passes back is a null viewmodel.
Can you advise what is wrong with this?
The expected outcome is that when the form is created in the for loop, it creates a List to pass back to the Action in the Controller. Currently it doesn't...
TIA
In my Create(Purchase/Purchasing) page i'm showing some dropdown-lists like Outlets, Suppliers. But after creating, i'm not getting the Names of the Outlets. It passes OutletId via model & i can also see that in Database. But don't know how to get Names against these OutletId.
Here's is the page image link in which Outlet & Supplier Names are not loading
Here's my Code --->
Model & View Model
Purchase.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OnlineShopping.Models.EntityModels
{
public class Purchase
{
public int Id { get; set; }
public int EmployeeId { get; set; }
public Employee Employee { get; set; }
public DateTime PurchaseDate{get;set;}
public int SupplierId { get; set; }
public Supplier Supplier { get; set; }
public string Remarks { get; set; }
public double GrandTotal { get; set; }
public List<PurchaseDetails> PurchaseDetailses { get; set; }
public int OutletId { get; set; }
public Outlet Outlet { get; set; }
public List<Outlet> Outlets { get; set; }
}
}
PurchaseVM.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.ComponentModel.DataAnnotations;
using OnlineShopping.Models.EntityModels;
namespace OnlineShopping.Models.VM
{
public class PurchaseVM
{
[Display(Name = "Outlet")]
public int OutletId { get; set; }
[Display(Name = "Employee")]
public int EmployeeId { get; set; }
public DateTime PurchaseDate { get; set; }
[Display(Name ="Supplier")]
public int SupplierId { get; set; }
public string Remarks { get; set; }
public double GrandTotal { get; set; }
public List<PurchaseDetails> PurchaseDetailses { get; set; }
public Outlet Outlet { get; set; }
public List<Outlet> Outlets { get; set; }
public List<Supplier> Suppliers { get; set; }
public List<Item> Items { get; set; }
public List<Employee> Employees { get; set; }
}
}
View
Purchasing.cshtml
#model OnlineShopping.Models.VM.PurchaseVM
#{
ViewBag.Title = "Purchasing";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Purchasing</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<div class="col-md-6">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<div class="form-group">
#Html.LabelFor(c => c.OutletId, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-8">
#Html.DropDownListFor(c => c.OutletId, new SelectList(Model.Outlets, "Id", "Name"), "Select...", htmlAttributes: new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(c => c.EmployeeId, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-8">
#Html.DropDownListFor(c => c.EmployeeId, null, htmlAttributes: new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.PurchaseDate, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-8">
#Html.EditorFor(model => model.PurchaseDate, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.PurchaseDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(c => c.SupplierId, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-8">
#Html.DropDownListFor(c => c.SupplierId, new SelectList(Model.Suppliers, "Id", "Name"), "Select...", htmlAttributes: new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Remarks, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-8">
#Html.EditorFor(model => model.Remarks, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Remarks, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group" id="GrandTotal">
#Html.LabelFor(model => model.GrandTotal, htmlAttributes: new { #class = "control-label col-md-4" })
<div class="col-md-8">
#Html.EditorFor(model => model.GrandTotal, new { htmlAttributes = new { #class = "form-control" } })
#*#Html.ValidationMessageFor(model => model.Remarks, "", new { #class = "text-danger" })*#
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="row">
<div class="row">
<div class="col-md-6">
<div class="form-group">
#Html.Label("Item", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("Item", new SelectList(Model.Items, "Id", "Name"), htmlAttributes: new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.Label("Qty", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBox("Qty", null, htmlAttributes: new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.Label("Price", htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.TextBox("Price", null, htmlAttributes: new { #class = "form-control" })
</div>
</div>
</div>
<div class="col-md-offset-3">
<input id="addButton" class="btn btn-success" type="button" value="Add" />
</div>
</div>
<div class="row">
<table>
<thead>
<tr>
<th>Item</th>
<th>Quantity</th>
<th>Price</th>
<th>Total</th>
</tr>
</thead>
<tbody id="tbenroll"></tbody>
</table>
</div>
</div>
</div>
<div class="col-md-offset-8">
<input class="btn btn-primary" type="submit" value="Save" />
#ViewBag.Message
</div>
<p>
#Html.ActionLink("Cancel", "Index")
</p>
</div>
}
#section scripts
{
<script src="~/Scripts/Purchasing/Purchase.js"></script>
}
Index.cshtml
#model IEnumerable<OnlineShopping.Models.EntityModels.Purchase>
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
#Html.ActionLink("Create New", "Purchasing")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Outlet)
</th>
<th>
#Html.DisplayNameFor(model => model.Supplier)
</th>
<th>
#Html.DisplayNameFor(model => model.Employee)
</th>
<th>
#Html.DisplayNameFor(model => model.PurchaseDate)
</th>
<th>
#Html.DisplayNameFor(model => model.Remarks)
</th>
<th>
#Html.DisplayNameFor(model => model.GrandTotal)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Outlet.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.Supplier.Name)
</td>
<td>#Html.DisplayFor(modelItem => item.Employee.Name)</td>
<td>
#Html.DisplayFor(modelItem => item.PurchaseDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.Remarks)
</td>
<td>
#Html.DisplayFor(modelItem => item.GrandTotal)
</td>
<td>
#*#Html.ActionLink("Edit", "Edit", new { id = item.Id }) |*#
#Html.ActionLink("Details", "Details", new { id = item.Id })
#*#Html.ActionLink("Delete", "Delete", new { id = item.Id })*#
</td>
</tr>
}
</table>
Controller
Purchase Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using AutoMapper;
using OnlineShopping.BLL;
using OnlineShopping.Models.EntityModels;
using OnlineShopping.Models.VM;
using OnlineShopping.BLL.Managers;
namespace OnlineShopping.Controllers
{
public class PurchaseController : Controller
{
OrganizationManager organizationManager = new OrganizationManager();
OutletManager outletManager = new OutletManager();
ItemManager itemManager = new ItemManager();
PurchaseOpManager purchaseOpManager = new PurchaseOpManager();
EmployeeManager employeeManager = new EmployeeManager();
SupplierManager supplierManager = new SupplierManager();
public ActionResult Index()
{
var purchaseList = purchaseOpManager.GetAll();
return View(purchaseList);
}
// GET: Purchase
public ActionResult Purchasing()
{
var model = new PurchaseVM();
model.Outlets = outletManager.GetAll();
model.Items = itemManager.GetAll();
model.Suppliers = supplierManager.GetAll();
ViewBag.EmployeeId = new List<SelectListItem>()
{
new SelectListItem() {Value = "", Text = "Select..."}
};
//ViewBag.SupplierId = new List<SelectListItem>()
//{
// new SelectListItem() {Value = "", Text = "Select.." }
//};
return View(model);
}
[HttpPost]
public ActionResult Purchasing(PurchaseVM model)
{
try
{
if (ModelState.IsValid)
{
var purchase = Mapper.Map<Purchase>(model);
bool isSaved = purchaseOpManager.Save(purchase);
if (isSaved)
return RedirectToAction("Index");
}
}
catch (Exception exception)
{
ModelState.AddModelError("", exception.Message);
var employeeList = ViewBag.EmployeeId;
model.EmployeeId = employeeList;
return View(model);
}
var outlets = outletManager.GetAll();
model.Outlets = outlets;
return View(model);
//model.Outlets = outletManager.GetAll();
//model.Items = itemManager.GetAll();
//return View(model);
}
}
}
Use Virtual keyword when declaring property of POCO class.
example below
public class Purchase
{
public int Id { get; set; }
public int EmployeeId { get; set; }
public Virtual Employee Employee { get; set; }
public DateTime PurchaseDate{get;set;}
public int SupplierId { get; set; }
public Virtual Supplier Supplier { get; set; }
public string Remarks { get; set; }
public double GrandTotal { get; set; }
public List<PurchaseDetails> PurchaseDetailses { get; set; }
public int OutletId { get; set; }
public Virtual Outlet Outlet { get; set; }
public List<Outlet> Outlets { get; set; }
}
I have read several answers on this issue but despite this, it would appear I have developed code blindness.
I have the following view model:
public class IndividualProductVm
{
public virtual Products Products { get; set; }
public ProductSummary ProductSummary { get; set; }
public virtual IEnumerable<ProductSimpleResponse> ProductSimpleResponse { get; set; }
}
This is then passed into a view and then a partial view:
#model Websites.ViewModels.IndividualProductVm #{ ViewBag.Title = "Edit"; }
<h2>Edit</h2>
#using (Html.BeginForm(null, null, FormMethod.Post, new { name = "form", id = "mainForm" })) { #Html.AntiForgeryToken() #Html.ValidationSummary(true, "", new { #class = "text-danger" }) #Html.HiddenFor(model => model.Products.Id) #Html.HiddenFor(model
=> model.ProductSummary.SupplierId) Html.RenderPartial("_IndividualProduct", Model);
<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>
#Html.ActionLink("Back to List", "Index", new { id = Model.ProductSummary.SupplierId }, new { #class = "btn btn-default" })
</div>
#section Scripts { #Scripts.Render("~/bundles/jqueryval") }
#model Websites.ViewModels.IndividualProductVm
<div>
#Html.LabelFor(model => model.Products.ProductCode, htmlAttributes: new { #class = "control-label col-md-2" })
<div>
#Html.DisplayFor(model => model.Products.ProductCode, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div style="clear:both;"></div>
<div>
#Html.LabelFor(model => model.Products.ProductDescription, htmlAttributes: new { #class = "control-label col-md-2" })
<div>
#Html.DisplayFor(model => model.Products.ProductDescription, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<table class="table">
<tr>
<th>
Present
</th>
</tr>
#foreach (var item in Model.ProductSimpleResponse)
{
<tr>
#Html.HiddenFor(modelItem => item.Id)
#Html.HiddenFor(modelItem => item.SupplierId)
#Html.HiddenFor(modelItem => item.ProductCode)
<td>
#Html.EditorFor(modelItem => item.Present)
</td>
</tr>
}
</table>
However, when I enter the edit post, my viewmodel is null for the IEnumerable<ProductSimpleResponse> but fine for the other two classes.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(IndividualProductVm model)
{
if (ModelState.IsValid)
{
return RedirectToAction("Index", new { id = model.ProductSummary.SupplierId });
}
return View(model.Products);
}
If someone can explain what I'm doing wrong, I'd be most grateful.
Your property name is ProductSimpleResponse, alhtough the type is ProductSvhcSimpleResponse, so to iterate through it you should have.
#foreach (var item in Model.ProductSimpleResponse)
NOT
#foreach (var item in Model.ProductSvhcSimpleResponse)
use List because
IEnumerable is suitable just for iterate through collection and you can not modify (Add or Remove) data IEnumerable bring ALL data from server to client then filter them, assume that you have a lot of records so IEnumerable puts overhead on your memory.
public class IndividualProductVm
{
public virtual Products Products { get; set; }
public ProductSummary ProductSummary { get; set; }
public virtual List<ProductSvhcSimpleResponse> ProductSimpleResponse { get; set; }
}
More help click here