How to make an insert form and a table displaying data from database in a single view in MVC? - asp.net-mvc

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

Related

issue with foreign key in asp.net mvc?

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);
}

View is expecting for viewmodel while List item has been passed to controller

Error::
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[ProjDAL.Models.ViewModels.EmpViewModel]', but this dictionary requires a model item of type 'ProjDAL.Models.ViewModels.EmpViewModel'.
I am working on a mvc application. For one view which basically has a functionality for multiple parameter search. I am using same view for get and post method... It means i am passing 1 or more parameters to the textboxes and fetching the result using linq and mapping to a datatable.
After passing the parameters, the values are going to the controller and fetching the exact result using linq but the problem is coming when i am trying to map the linq result-set to my view.
Here is the code for the project -
Controller -
[HttpPost]
public ActionResult EmpSearch([Bind(Include = "employee,EmpID,PAN")] Get_EmpDetails_Result get_EmpDetails_Result)
{
var result = from emp in dbCollections.Employees
join nat in dbCollections.NationalID on emp.EmpID equals nat.EmpID
select new EmpViewModel
{
PAN = nat.pan,
EmpID = emp.EmpID,
employee = emp.Name
};
var searchRes = result
.Where(s => s.PAN.Contains(get_EmpDetails_Result.pan)
|| s.EmpID.Contains(get_EmpDetails_Result.empid)
|| s.employee.Contains(get_EmpDetails_Result.employee));
var modelSys = searchRes.ToList();
return View(modelSys);
}
View ::::
#model NewProjDAL.Models.ViewModels.EmpViewModel
#{
ViewBag.Title = "empDetails";
Layout = "~/Views/Shared/_Layout.cshtml";
}
//////////// this part is for the multiple criteria search
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
<label>By EmpID</label>
<div class="col-md-10">
#Html.EditorFor(model => model.GetEmpDetails.FirstOrDefault().empid, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<label>By PAN</label>
<div class="col-md-10">
#Html.EditorFor(model => model.GetEmpDetails.FirstOrDefault().pan, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<label>By Name</label>
<div class="col-md-10">
#Html.EditorFor(model => model.GetEmpDetails.FirstOrDefault().employee, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-actions center">
<button type="submit" data-animation="pulse" class="btn btn-lg font-medium-1 btn-outline-teal mb-1 block-multiple-msgs buttonAnimation">
<i class="fa fa-check-square-o"></i> Go
</button>
</div>
</div>
}
//////////////////////////////this part is to fetch the result of the previously mentioned multiple search
#if (Model.EmpDetails.Count != 0)
{
<div class="table-responsive">
<table class="table table-striped table-bordered dom-jQuery-events compact" id="DataTbl">
<thead class="navbar-dark navbar-dark bg-blue-grey white">
<tr>
<th>
employee
</th>
<th>
PAN
</th>
<th>
empid
</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.GetEmpDetails)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.employee)
</td>
<td>
#Html.DisplayFor(modelItem => item.PAN)
</td>
<td>
#Html.DisplayFor(modelItem => item.empid)
</td>
</tr>
}
</tbody>
</table>
</div>
}
It's told you exactly what the problem is. You've set up the view to accept a single EmpViewModel as the Model, but your controller is passing a List
You need to create a view model to represent the search criteria and the results
public class EmployeeSearchViewModel
{
public string EmpId { get; set; }
public string PAN { get; set; }
public string Employee { get; set; }
public List<EmpViewModel> Employees { get; set; } = new List<EmpViewModel>();
}
then in your controller method:
var modelSys = searchRes.ToList();
var viewModel = new EmployeeSearchViewModel
{
PAN = get_EmpDetails_Result.pan,
EmpId = get_EmpDetails_Result.empid,
Employee = get_EmpDetails_Result.employee
Employees = modelSys
};
return View(viewModel);
In the view:
#Model EmployeeSearchViewModel
Then your parameters display don't need to pull the EmpID, PAN, etc. from the collection, just from the view model, and you can bind your repeated results to the inner collection "Employees".

How to create multiple in-line forms for a list property

I want to create a view where a user can update (create/edit) multiple Journal Entries (one for each journal) at the same time.
ViewModel:
public class CompanyRecoMonthViewModel
{
public Company Company { get; set; }
public string RecoMonth { get; set; }
}
Company has a list of Journals:
public virtual IList<Journal> Journals { get; set; }
Every journal has a list of JournalEntries
public IList<JournalEntry> JournalEntries { get; set; }
In each month Journal will have one (or none) JournalEntry .
From the controller I'm loading the Journals into the view.
Now the code in the view. I'm trying to put the inline forms into a table view.
My problem is that upon submitting the form none of the values are captured.
Probably not using the #Html.BeginForm properly. Seems that form doesn't know which object it is meant to edit.
<table class="table">
<tr>
<th>
Person Responsible
</th>
<th>
Journal Number
</th>
<th>
SomeID
</th>
<th>
Status
</th>
<th>
Upload Date
</th>
<th>
Amount<
</th>
<th></th>
</tr>
#foreach (var item in Model.Company.Journals)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.User.Name)
</td>
<td>
#Html.DisplayFor(modelItem => item.JournalNumber)
</td>
<!-- this is where we start inline form for Journal Entry-->
#using (Html.BeginForm("Edit", "JournalEntries", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<form class="form-inline">
#Html.HiddenFor(modelItem => item.JournalID)
<div class="form-group">
<td>
#Html.TextBoxFor(modelItem => item.JournalEntries[0].SomeID, new { #class = "form-control", maxlength = "8" })
</td>
<td>
#Html.DropDownListFor(modelItem => item.JournalEntries[0].Status, Model.JournalStatuses.Select(e => new SelectListItem { Text = e }), string.Empty, new { #class = "form-control" })
</td>
<td>
#Html.EditorFor(modelItem => item.JournalEntries[0].DatePosted, new { htmlAttributes = new { #class = "form-control datepicker" } })
</td>
<td>
#Html.DropDownListFor(modelItem => item.JournalEntries[0].JournalType, Model.JournalTypes.Select(e => new SelectListItem { Text = e }), string.Empty, new { #class = "form-control" })
</td>
<td>
#Html.EditorFor(modelItem => item.JournalEntries[0].AmountPosted, new { htmlAttributes = new { #class = "form-control" } })
</td>
<td>
<button type="submit" class="btn btn-default">Save</button>
</td>
</div>
</form>
}
</tr>
}
</table>
Add virtual keyword to JournalEntries property in your Journal class to navigate to the JournalEntry class.
public virtual IList<JournalEntry> JournalEntries { get; set; }
Managed to achieve that using multiple partial views with inline-forms for one entity per partial view.

MVC Is possible use in "create" scaffolded page, a partial view that uses the same model

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")

asp.net mvc onr-to-many details partial view in master main view

I am sorry if im asking same thing for the nth time but i can not find the answer to my question...
I have problem adding partial views...
I have One-to-Many relation in the database tables.
My Model is:
using System;
using System.Collections.Generic;
public partial class Job
{
public Job()
{
this.Flights = new HashSet<Flight>();
}
public int JobID { get; set; }
public string JobNumber { get; set; }
public int ClientID { get; set; }
public virtual Client Client { get; set; }
public virtual ICollection<Flight> Flights { get; set; }
}
My Controller (Create):
// GET: /Jobs/Create
public ActionResult Create()
{
ViewBag.ClientID = new SelectList(db.Clients, "ClientID", "ClientName");
return View();
}
And View (for create Job):
#model AOG.Models.Job
<div class="form-horizontal">
<h4>Job</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.JobNumber, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.JobNumber)
#Html.ValidationMessageFor(model => model.JobNumber)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ClientID, "ClientID", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("ClientID", String.Empty)
#Html.ValidationMessageFor(model => model.ClientID)
</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>
Now if i add partial view (Generated Partial List View) On Create Job Page:
#html.Partial("_PartialFlights");
I get an error: Object reference not set to an instance of an object on
Line 23: #foreach (var item in Model) {
in my partial view. This is the code:
#model IEnumerable<AOG.Models.Flight>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.FlightName)
</th>
<th>
#Html.DisplayNameFor(model => model.FlightETD)
</th>
<th>
#Html.DisplayNameFor(model => model.FlightETA)
</th>
<th>
#Html.DisplayNameFor(model => model.Job.JobNumber)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.FlightName)
</td>
<td>
#Html.DisplayFor(modelItem => item.FlightETD)
</td>
<td>
#Html.DisplayFor(modelItem => item.FlightETA)
</td>
<td>
#Html.DisplayFor(modelItem => item.Job.JobNumber)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.FlightID }) |
#Html.ActionLink("Details", "Details", new { id=item.FlightID }) |
#Html.ActionLink("Delete", "Delete", new { id=item.FlightID })
</td>
</tr>}</table>
How ever If i put this in the details view:
#foreach (var item in Model.Flights)
{
<div>
<table>
<tr><th>Flight</th><th>ETD</th><th>ETA</th></tr>
<tr>
<td>#Html.DisplayFor(modelItem => item.FlightName)</td>
<td>#Html.DisplayFor(modelItem => item.FlightETD)</td>
<td>#Html.DisplayFor(modelItem => item.FlightETA)</td>
</tr></table>
</div>
}
It shows everything I need, but i want to learn how to do it with the partial views.
Thank you all so much!
You need to pass an IENumerable<Flight> instance to your partial view, so in stead of:
#html.Partial("_PartialFlights");
...do this:
#html.Partial("_PartialFlights", Model.Flights);

Resources