I am facing a referance issue
empid is not insert in the table when employee generate the experiance then not display the experiance data on the index page?
HomeController.cs
public class HomeController : Controller
{
private readonly dbozeeEntities dbemp;
public HomeController()
{
dbemp = new dbozeeEntities();
}
// GET: Home
public ActionResult Index()
{
var list = dbemp.employees.ToList();
return View(list);
}
public ActionResult Create()
{
return View();
}
[HttpPost]
public ActionResult Create(employee emp)
{
var create = dbemp.employees.Add(emp);
dbemp.SaveChanges();
return RedirectToAction("Experiance", new { empId = emp.empid }); //here going to experiance page
}
public ActionResult Experiance(employee emps)
{
//ViewData["empid"] = emps.empid;
return View(new experiance() { empid = emps.empid });
}
[HttpPost]
public ActionResult Experiance(experiance exp,employee emps)
{
//ViewData["empid"] = emps.empid;
var create = dbemp.experiances.Add(exp);
dbemp.SaveChanges();
return RedirectToAction("Index");
}
Index.cshtml
#model IEnumerable<DemoOzeeTechno.Models.employee>
#using DemoOzeeTechno.Models
#{
ViewBag.Title = "Index";
IEnumerable<experiance> exp = ViewData["empid"] as IEnumerable<experiance>;
}
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.empname)
</th>
<th>
#Html.DisplayNameFor(model => model.emailaddress)
</th>
<th>
#Html.DisplayNameFor(model => model.contactno)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.empname)
</td>
<td>
#Html.DisplayFor(modelItem => item.emailaddress)
</td>
<td>
#Html.DisplayFor(modelItem => item.contactno)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.empid }) |
#*#Html.ActionLink("Details", "Details", new { id=item.empid }) |*#
#Html.ActionLink("Delete", "Delete", new { id=item.empid })
</td>
</tr>
}
</table>
<table>
<tr>
<th>CompanyName</th>
<th>YearOfExperiance</th>
</tr>
#if (ViewData["empid"] != null)
{
foreach (experiance ex in exp)
{
<tr>
<td>#ex.companyname</td>
<td>#ex.yearofexp</td>
</tr>
}
}
</table>
Experiance.cshtml
#model DemoOzeeTechno.Models.experiance
#{
ViewBag.Title = "Experiance";
}
<h2>Experiance</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>experiance</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.companyname, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.companyname, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.companyname, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.yearofexp, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.yearofexp, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.yearofexp, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#* #Html.LabelFor(model => model.empid, "empid", htmlAttributes: new { #class = "control-label col-md-2" })*#
<div class="col-md-10">
#Html.HiddenFor(model => model.empid)
#*#Html.DropDownList("empid", null, htmlAttributes: new { #class = "form-control" })*#
#Html.ValidationMessageFor(model => model.empid, "", 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>
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
Database Design:
experiance data inserted in table but issue is Does not Displaying the experiance data in index page
Watch Window:
empis is not insert in the table and experiance data not display on the page that is the issue??
First, you should know that ViewData get loss data while redirection from one action to another, So you have two options to pass empid from one Action to another one is to use Session and other is pass data in query string. So I would prefer a query string. So here is how you can do this.
First, you need to pass created empid to Experience action by the query string.
[HttpPost]
public ActionResult Create(employee emp)
{
var create = dbemp.employees.Add(emp);
dbemp.SaveChanges();
return RedirectToAction("Experiance",new{empId=emp.id}); //here going to experiance page
}
Now pass data to your view so that it post this id with newly created experience.
public ActionResult Experiance(int empId)
{
return View(new experiance(){empid=empId});
}
In the view you need a hidden field which will store this id into create experience form and submit along with experience fields.
#Html.HiddenFor(model=>model.empid)
Now in you Experience post-action you don't need to set empid explicitly it will get it from posted form values.
[HttpPost]
public ActionResult Experiance(experiance exp)
{
var create = dbemp.experiances.Add(exp);
dbemp.SaveChanges();
return RedirectToAction("Index");
}
Updated
To show the experience table on index page get all the experience list from the database and store it to ViewData.
// GET: Home
public ActionResult Index()
{
var list = dbemp.employees.ToList();
ViewData["empid"]=dbemp.experience.ToList();
return View(list);
}
Related
I'm making a CRUD but I want the create and read parts to be in a single MVC view. The create part is done, I've been trying to fill an HTML table with data from a database table when the view loads, but it won't let me do both things at once in a single view.
Here's the view header:
#model Console.Models.Product
#{
ViewBag.Title = "Create";
}
Here's the insert form:
#using (Html.BeginForm())
{
<div class="box-body">
<div class="form-horizontal">
#Html.AntiForgeryToken()
#Html.Hidden("productID", 0)
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<div class="col-md-6">
#Html.EditorFor(model => model.productName, new { htmlAttributes = new { #class = "form-control", #name = "txtProductName", #id = "txtProductName" } })
</div>
#Html.ValidationMessageFor(model => model.productName, "", new { #class = "text-danger", Type = "productName" })
</div>
<div class="form-group">
<div class="col-md-6">
#Html.EditorFor(model => model.productQuantity, new { htmlAttributes = new { #class = "form-control", #name = "txtProductQuantity", #id = "txtProductQuantity" } })
</div>
#Html.ValidationMessageFor(model => model.productQuantity, "", new { #class = "text-danger" })
</div>
<div class="form-group">
<div class="col-md-6">
#Html.EditorFor(model => model.productColor, new { htmlAttributes = new { #class = "form-control", #name = "txtProductColor", #id = "txtProductColor" } })
</div>
#Html.ValidationMessageFor(model => model.productColor, "", new { #class = "text-danger" })
</div>
</div>
</div>
}
This is the table that should show the products that are inserted into the database in the form above:
<table id="Data_table" class="table table-bordered table-striped">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.productName)
</th>
<th>
#Html.DisplayNameFor(model => model.productQuantity)
</th>
<th>
#Html.DisplayNameFor(model => model.productColor)
</th>
<th>
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.productName)
</td>
<td>
#Html.DisplayFor(modelItem => item.productQuantity)
</td>
<td>
#Html.DisplayFor(modelItem => item.productColor)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.productID }, new { #class = "btn btn-success btn-sm" })
#Html.ActionLink("Delete", "Delete", new { id = item.productID }, new { #class = "btn btn-danger btn-sm" })
</td>
</tr>
}
</tbody>
<tfoot>
<tr>
<th><div class="panel-footer">Total = #Model.Count()</div></th>
</tr>
</tfoot>
</table>
Problem is that I get an error at the foreach telling me to use IEnumerable with the model but whenever I do, the insert form gets an error. Is there any way to get around this?
Edit:
Here's the view model:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Console.Models
{
public class ProductViewModel
{
public int productID{ get; set; }
public string productName{ get; set; }
public int productQuantity{ get; set; }
public string productColor{ get; set; }
public IEnumerable<Product> Products { get; set; }
}
}
In your view you do pass a single model, and then you try to iterate over it, that of course is not possible.
You should use view models. Create a view model that contains both the fields you need for the form and the list of products you want to iterate over on foreach.
#model ProductViewModel
#{
ViewBag.Title = "Create";
}
Create a view model, like this:
public class ProductViewModel {
public string ProductName { get; set; }
// Other fields for the form
public IEnumerable<Product> Products { get; set; } // Your list of products for the table
}
And then in your view:
#Html.EditorFor(model => model.ProductName,
// Continue with the form
#foreach (var item in Model.Products)
{ //...continue with your table
I have a partial view for editing a collection (most of which I've truncated here):
#using CustomSurveyTool.Models
#model Basiclife
<div class="editorRow">
#using (Html.BeginCollectionItem(""))
{
<div class="form-horizontal">
<div class="row">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="col-md-2">
#Html.LabelFor(model => model.Plantype, htmlAttributes: new { #class = "control-label" })
#Html.EditorFor(model => model.Plantype, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Plantype, "", new { #class = "text-danger" })
</div>
<div class="col-md-1">
X
</div>
</div>
</div>
}
</div>
Which is part of a wrapper view:
#using CustomSurveyTool.Models
#model IEnumerable<Basiclife>
#{
ViewBag.Title = "CreateBasicLifeResponse";
}
<h2>Basic Life Insurance Plans</h2>
<div id="planList">
#using (Html.BeginForm())
{
<div id="editorRows">
#foreach (var item in Model)
{
#Html.Partial("_BasicLifeResponse", item)
}
</div>
#Html.ActionLink("Add", "BasicLifeResponse", null, new { id = "addItem", #class = "button" });
<input type="submit" value="submit" />
}
</div>
Which posts back to this controller:
[HttpPost]
public ActionResult CreateBasicLifeResponse(IEnumerable<Basiclife> model)
{
foreach(var item in model)
{
string currentUserId = User.Identity.GetUserId();
Response targetresponse = db.response.FirstOrDefault(x => x.Userid == currentUserId);
int responseid = targetresponse.Id;
item.ResponseId = responseid;
db.basiclife.Add(item);
db.SaveChanges();
}
List<Basiclife> basiclife = new List<Basiclife>();
return View(model);
}
I am getting a NullReferenceException on the foreach(var item in model) after submitting the form. What could be causing this?
You need to follow the MVC naming convention which involves using a for loop with an index instead of foreach in your Razor view. Check out this article:
How to pass IEnumerable list to controller in MVC including checkbox state?.
I would recommend the Editor Template approach described in the article, it is most similar to your current PartialView approach.
I am trying to send data from database when pressing Edit on ActionLink(Last line on view). Having some problem in view Controller to understand how this data will be sent to the right input field so i can Edit it and send it back to database.
(This Question is only for the GET part so i have not included Post controller)
View(view name AddCourse):
#model IEnumerable<CadProject.Models.CourseModel>
#using (Html.BeginForm("AddCourse", "AdminModel", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-group">
#Html.Label("Emnekode", new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input name="CourseCode" type="text" />
</div>
</div>
<div class="form-group">
#Html.Label("Emne", new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input name="CourseName" type="text" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Upload" class="btn btn-default" />
</div>
</div>
</div>
}
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.CourseCode)
</th>
<th>
#Html.DisplayNameFor(model => model.CourseName)
</th>
<th>
Edit/Delete
</th>
</tr>
#if (Model != null)
{
foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.CourseCode)
</td>
<td>
#Html.DisplayFor(modelItem => item.CourseName)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
#Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
}
}
</table>
View controller:
public ActionResult Edit(int id)
{
db.Courses.Find(id);
CourseModel model = db.Courses.Find(id);
if(model == null)
{
return View();
}
return View("AddCourse", db.Courses);
}
Database model:
public class CourseModel
{
[Key]
public int Id { get; set; }
public string CourseCode { get; set; }
public string CourseName { get; set; }
}
The functionality the Edit(HttpGet) method is to take the ID of the item the user want's to edit, find ONE record in the database with this ID and send the found record to the Edit view where you have various controls that display the current values and allow the user to change them through the use of text boxes e.t.c
In the code you posted you look up the course the user wants to edit but then you return all the courses to the Edit view, which is wrong.It's supposed to be like this:
public ActionResult Edit(int id)
{
db.Courses.Find(id);
CourseModel model = db.Courses.Find(id);
if(model == null)
{
return View();
}
return View("EditCourse", model);
}
Have a look at this simple example:
Edit Action:
[HttpGet]
public ActionResult Edit(int id)
{
var course1 = new Course { ID = 0, Name = "Software Engineering" };
var course2 = new Course { ID = 1, Name = "ASP.NET MVC" };
var course3 = new Course { ID = 2, Name = "C# Course" };
var courses = new List<Course> { course1 ,course2, course3};
var course = courses.FirstOrDefault(c => c.ID == id);
return View("EditCourse",course);
}
EditCourse View:
#model Example.Models.Course
#{
ViewBag.Title = "EditCourse";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Course</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.ID)
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</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>
}
I have a view model which contains a class reference and 2 IEnumerable collections.
public class BuildingTypeViewModel
{
public Static_Item BuildingType { get; set; }
public IEnumerable<Reading_Type> ReadingTypes { get; set; }
public IEnumerable<Building_Type_Reading> BuildingReadings { get; set; }
}
I populate this ViewModel in the Edit action on the controller
public ActionResult Edit(int id)
{
Static_Item staticItem = db.Static_Item.Find(id);
BuildingTypeViewModel model = new BuildingTypeViewModel
{
BuildingType = staticItem,
ReadingTypes=db.Reading_Type.ToList(),
BuildingReadings = db.Building_Type_Reading.Where(bt => bt.UN_Building_Type == staticItem.UN_Building_Type).ToList()
};
return View(model);
}
Building type on the view model is a class with an ID and Description and the data would be something like this:
UN_Building_Type=1, Description = "Hospital"
The IEnumerable of Reading_Type's would be like this:
UN_Reading_Type = 1, Description = "Electric"
UN_Reading_Type = 2, Description = "Gas"
The IEnumerable of Building_Type_Readings would be like this:
UN_Building_Type_Readings=1, UN_Building_Type=1, UN_Reading_Type = 1, Typical=300, Good=150
UN_Building_Type_Readings=2, UN_Building_Type=1, UN_Reading_Type = 2, Typical=800, Good=400
I load this data into my view:
#model SSE.Enterprise.EE_Web_Portal.Models.BuildingTypeViewModel
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Static_Item</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.BuildingType.UN_Building_Type)
<div class="form-group">
#Html.LabelFor(model => model.BuildingType.Description, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.BuildingType.Description, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.BuildingType.Description, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<label class="control-label col-md-2">Building Readings</label>
<div class="col-md-10">
<table class="table">
<tr>
<th/>
<th>
#Html.LabelFor(model=>model.BuildingReadings.FirstOrDefault().Typical)
</th>
<th>
#Html.LabelFor(model => model.BuildingReadings.FirstOrDefault().Good)
</th>
</tr>
#foreach (var item in Model.ReadingTypes)
{
<tr>
<td>
#Html.Label(item.Description)
</td>
<td>
#Html.EditorFor(model => model.BuildingReadings.FirstOrDefault(b => b.UN_Reading_Type == item.UN_Reading_Type).Typical, new { htmlAttributes = new { #class = "form-control" } })
</td>
<td>
#Html.EditorFor(model => model.BuildingReadings.FirstOrDefault(b => b.UN_Reading_Type == item.UN_Reading_Type).Good, new { htmlAttributes = new { #class = "form-control" } })
</td>
</tr>
}
</table>
</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>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Here is my edit postback method.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit([Bind(Include = "BuildingType")] BuildingTypeViewModel model)
{
if (ModelState.IsValid)
{
db.Entry(model).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(model);
}
When the page is posted back the 2 IEnumerable collections are null so I'm not able to save the data that has been entered.
Any idea?
Ta
First of all, by specifying the attribute Bind(Include = "BuildingType") you're telling MVC to only bind this single property. Remove the attribute, and MVC will try to bind your 2 IEnumerable collections.
Next, check your #Html.EditorFor calls. I'm not sure MVC can understand FirstOrDefault inside. Try avoiding LINQ selectors inside your view.
And after that, as #will mentioned, try changing IEnumerable to List.
MVC Is possible use in "create" scaffolded page, a partial view that uses the same model to summarize data already entered into the same table?
My model :
public class tag
{
public int Id { get; set; }
public string TagName { get; set; }
public string Note { get; set; }
}
my Controller :
// GET: Tags/Create
public ActionResult Create()
{
var tag = db.Tags;
return View(tag);
}
my view :
#model myAssembly.Models.Tag
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Tag</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.Tag1, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Tag1, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Tag1, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Note, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Note, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Note, "", 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>
}
#Html.Partial("_tagDetail", Model)`
my partial view:
#model IEnumerable<myAssembly.Models.Tag>
<p>
#Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.Tag1)
</th>
<th>
#Html.DisplayNameFor(model => model.Note)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Tag1)
</td>
<td>
#Html.DisplayFor(modelItem => item.Note)
</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>
My problem is that I receive same error. I don't have idea (sorry) for solve this problem! I hope in your help. Thank you.
Your Create view should have a model of type myAssembly.Models.Tag. In your controller your Create action should just return View(); or View(new Tag());
You should create a PartialViewResult in your controller. Something like
// GET: Tags/Create
public ActionResult Create()
{
return View();
}
// GET: Tags/List
public ActionResult List()
{
var tag = db.Tags;
return PartialView("_tagDetail", tag);
}
In your Create view where you're calling the partial, change that to Action.
#Html.Action("List")