I am trying to get the data from database through model and display it on a view. Here is the sample code, i am able to pull the data but that is not showing up on the view.I appreciate any help. Thanks in advance
Model Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.SqlClient;
using System.Configuration;
namespace Test.Models
{
public class CustModel
{
SqlConnection con = new SqlConnection();
List<CustModel> CustList = new List<CustModel>();
public String CustName { get; set; }
public String CustPhone { get; set; }
CustModel p = null;
public List< CustModel > GetCustInfo()
{
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["CustConnectionString"].ToString());
con.Open();
using (con)
{
SqlCommand cmd = new SqlCommand("select * FROM Cust_tb where ZIP = 37771", con);
SqlDataReader rd = cmd.ExecuteReader();
while (rd.Read())
{
p = new CustModel ();
p.CustName =Convert.ToString(rd.GetSqlValue(0));
p.CustPhone = Convert.ToString(rd.GetSqlValue(10));
CustList.Add(p);
}
return CustList;
}
}
}
Controller Code
public ActionResult CustDisplay()
{
CustModel p = new CustModel();
List<CustModel> Li = new List<CustModel>();
Li = p. GetCustInfo ();
ViewData["CustInfo"] = Li;
return View("CustDisplay");
}
View Code
#model Test.Models.CustModel
#{
ViewBag.Title = "CustDisplay";
}
<!DOCTYPE html>
<head>
<title> Customer Information </title>
</head>
<body>
<div class="display-label">
Name
</div>
<div class="display-field">
#Html.DisplayFor(Model => Model.CustName)
</div>
<div class="display-label">
Phone
</div>
<div class="display-field">
#Html.DisplayFor(Model => Model. CustPhone)
</div>
</body>
</html>
Maybe I am over-simplifying this - but I think it is just because you didn't actually send or use your list in the view... I don't get my data the way you did - so I will assume that you are getting the data you want, and the returning list contains 1 to many rows of data in p (name and phone)
even though you pass your list in ViewData - you aren't assigning it in the view.. the best way to do this would be in your controller to call return View(Li); and not return View("CustDisplay"); you are already in the view you want to call - so it will send the list into the #model. (There may be a way to assign the ViewData to the model in the view also) - but I pass the list in, so the data is bound...
You should make the model #model IEnumerable<Test.Models.CustModel>
and then
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.CustName)
</th>
<th>
#Html.DisplayNameFor(model => model.CustPhone)
</th>
</tr>
#foreach (var item in Model){
<tr>
<td>
#Html.DisplayFor(modelItem => item.CustName)
</td>
<td>
#Html.DisplayFor(modelItem => item.CustPhone)
</td>
</tr>
}
</table>
Related
This question already has answers here:
Post an HTML Table to ADO.NET DataTable
(2 answers)
Closed 5 years ago.
I am new to ASP .NET MVC. My problem is - I want to 'POST' a collection of the items , so that controller can process it.
My model is collection of -
public class CheckedRentalProperty
{
public bool IsSelected { get; set; }
public int Id { get; set; }
public String Address { get; set; }
}
My controller is defined like this -
public class RentalPropertiesController : Controller
{
public ActionResult Index()
{
List<CheckedRentalProperty> checkHsList = new List<CheckedRentalProperty>();
// Fill the list
return View(checkHsList);
}
[HttpPost]
public ActionResult Save(IEnumerable<CheckedRentalProperty> checkHsList)
{
// why checkHsList is coming as null ??
}
}
And the view is like this -
#model IEnumerable<XXX.Models.CheckedRentalProperty>
#using (Html.BeginForm("Save", "RentalProperties", FormMethod.Post))
{
<div class="form-horizontal">
<div class="form-group">
<table class="table">
<tr>
<th>
</th>
<th>
#Html.DisplayNameFor(model => model.Address)
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>#Html.CheckBoxFor(modelItem => item.IsSelected)</td>
<td>
#Html.DisplayFor(modelItem => item.Address)
</td>
</tr>
}
</table>
</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>
}
My expectations was - when I hit the "Save" button, the Model, which is IEnumerable<CheckedRentalProperty> item, will be passed to the Save() action of the controller. However, I find that the passed parameter is "null" all the time. What am I missing?
Model that are solely IEnumerable are not too friendly as MVC Model.
There are many issues arise here, but in a nutshell, MVC webform bindings needs form name requests to be send in the following format: PropertyName[Index].Property
Which is not the case at your example.
It is a good design practice, to create a wrapping ViewModel which will hold the properties you need for the given controller + pages.
ViewModel
public class RentalPropertiesViewModel
{
public List<CheckedRentalProperty> CheckedRentalProperties { get; set; }
}
Controller: Next we will want to use this ViewModel in our controller.
public ActionResult Index()
{
var checkHsList = new List<CheckedRentalProperty>();
checkHsList.Add(new CheckedRentalProperty { Id = 1, Address = "Address1", IsSelected = true });
checkHsList.Add(new CheckedRentalProperty { Id = 2, Address = "Address2", IsSelected = false });
checkHsList.Add(new CheckedRentalProperty { Id = 3, Address = "Address3", IsSelected = true });
var model = new RentalPropertiesViewModel
{
CheckedRentalProperties = checkHsList
};
return View(model);
}
[HttpPost]
public ActionResult Save(RentalPropertiesViewModel model)
{
// why checkHsList is coming as null ??
return null;
}
View: Now in our view we should set the Model as the new ViewModel type we created.
#model TestBindings.Models.RentalPropertiesViewModel
And our view form should be something like:
<table class="table">
<tr>
<th>
Is Selected
</th>
<th>
Address
</th>
</tr>
#for (int i = 0; i < Model.CheckedRentalProperties.Count(); i++)
{
<tr>
#Html.HiddenFor(model => model.CheckedRentalProperties[i].Id);
<td>#Html.CheckBoxFor(model => model.CheckedRentalProperties[i].IsSelected)</td>
<td>#Html.TextBoxFor(model => model.CheckedRentalProperties[i].Address)</td>
</tr>
}
</table>
I've use the following format model => model.CheckedRentalProperties[i].IsSelected and now MVC InputExtensions will bind it correctly. e.g: CheckedRentalProperties[0].IsSelected
Important Note: Notice i'm passing Id property as hidden, so MVC Binder will know to set the Id to the correct item.
Good day guys, I'm in a little limbo here. I have created my database, model, controller and view in visual studio using ASP.NET MVC and C#, but I can't figure out how to call a stored procedure that I created also.
I want for the stored procedure to be called on a button I placed in my view.
This stored procedure should execute and display results when the button is click.
Below are the Stored procedure, view, model and controller I created.
This is my 'Employee' Model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Web;
namespace MVCSimpleApp.Models
{
[Table("Employees")]
public class Employee
{
[Display(Name ="Employee Id")]
public int EmployeeId { get; set; }
[Display(Name ="First Name")]
public string FirstName { get; set; }
[Display(Name ="Last Name")]
public string LastName { get; set; }
}
}
This is my Data Context:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web;
namespace MVCSimpleApp.Models
{
public class EmployeeContext : DbContext
{
public DbSet<Employee> Employee { get; set; }
}
}
This is my Employee Controller:
using MVCSimpleApp.Models;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
namespace MVCSimpleApp.Controllers
{
public class EmployeeController : Controller
{
private EmployeeContext db = new EmployeeContext();
// GET: Employee
public ActionResult Index()
{
var employees = from e in db.Employee select e;
return View(employees);
}
}
}
And now this is my Stored procedure. It is not much, just something for practice purpose.
Create Proc DisplayStudents
AS
BEGIN
/*selecting all records from the table whose name is "Employee"*/
Select * From Employee
END
This is my view:
#model IEnumerable<MVCSimpleApp.Models.Employee>
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Student List</h2>
<p>
<a href="#Url.Action("Create")" title="Add new" class="btn btn-primary btn-lg">
<span class="glyphicon glyphicon-plus "></span>
Add Student
</a>
</p>
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.EmployeeId)
</th>
<th>
#Html.DisplayNameFor(model => model.FirstName)
</th>
<th>
#Html.DisplayNameFor(model => model.LastName)
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(model => item.EmployeeId)
</td>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
<span>
<a href="#Url.Action("Edit", new { id = item.EmployeeId})" title="Edit Record">
<span class="glyphicon glyphicon-pencil"></span>
</a>
</span>
|
<span>
<a href="#Url.Action("Details", new { id = item.EmployeeId})" title="View Details">
<span class="glyphicon glyphicon-th-list"></span>
</a>
</span>
|
<span>
<a href="#Url.Action("Delete", new { id = item.EmployeeId})" title="Delete">
<span class="glyphicon glyphicon-trash"></span>
</a>
</span>
</td>
</tr>
}
/*this is the button I want the stored procedure to be called on when I click it*/
<button>Run</button>
</table>
Please guys I need your opinions and feedback on this matter. Will accept tips in passing parameters to a stored procedure. Please correct me if I am not doing things right here. Thanks for your concern.
If using EF is not a necessity you can do it in the following way:
string cnnString = System.Configuration.ConfigurationManager.ConnectionStrings["ConnectionStringName"].ConnectionString;
SqlConnection cnn = new SqlConnection(cnnString);
SqlCommand cmd = new SqlCommand();
cmd.Connection = cnn;
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.CommandText = "ProcedureName";
//add any parameters the stored procedure might require
cnn.Open();
object o = cmd.ExecuteScalar();
cnn.Close();
If you need to use Entity Framework check out this discussion. Also you want to use the Stored Procedures for Inserting, Updating and deleting check out this tutorial from Microsoft.
To execute the code from a button click you can create a form an place just one button inside the form like this:
#using(Html.BeginForm("TestAction", "TestController", FormMethod.Get))
{
<input type="submit" value="Submit" />
}
And in your controller you would have a TestAction method like this
public ActionResult TestAction(){....}
if you need to pass any arguments to TestAction, just specify them as parameters in the method and then use the overloaded version of BeginForm that accepts actionName, controllerName, routeValues and formMethod as arguments.
To pass the results to a view you need to create a view model with properties according to the values you recieve from the stored procedure and then, return a view with the view model from the TestAction method.
Here is an example of how you can do this with entity framework. I personally am not a big fan of entity frameworks because it is slow and clunky, but people with limited DB EXP tend to like it.
Normally I like to give a full example with all the code but due to the way entity frameworks is configured I will pass on that part. Keep in mind this wont work without the entity framework context already being setup.
private RAP_Entities db = new RAP_Entities();
public string GetGUID(string DeviceID, string CCCShopID)
{
SqlParameter[] Parameters =
{
new SqlParameter("#DeviceID", DeviceID),
new SqlParameter("#CCCShopID", CCCShopID)
};
string DistributionChannelGUID = db.Database.SqlQuery<string>("GetDistributionChannelGUID #DeviceID, #CCCShopID", Parameters).ToString();
return DistributionChannelGUID;
}
You can make it through Normal ADO.Net Approach where you call StoredProcedure using SqlCommand and pass few parameters to it.
try
{
conn.Open();
SqlCommand dCmd = new SqlCommand("store_procedure_name",conn);
dCmd.CommandType = CommandType.StoredProcedure;
dCmd.Parameters.Add(new SqlParameter("#parameter2",parameter2));
dCmd.Parameters.Add(new SqlParameter("#parameter1", parameter1));
SqlDataAdapter da = new SqlDataAdapter(dCmd);
DataTable table = new DataTable();
ds.Clear();
da.Fill(ds);
conn.Close();
var das = ds.Tables[0].AsEnumerable();
return ConvertToDictionary(ds.Tables[0]);
}
catch
{
}
I want to post quantity property to Controller (It's an edit action). I'm editing OrderedProductSet which is connected with ProductSet in my SQL Database (I get the name and price from there). How to pass multiple data from the view to controller? How to write method in controller class to receive the data (I'm asking about method arguments in this specific case).
My view:
#model Shop.Models.ProductViewModel#{
ViewBag.Title = "Edycja zamówienia";
}
<h2>Edycja zamówienie</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<table class="table">
<tr>
<th>
<b>Nazwa produktu</b>
</th>
<th>
<b>Cena</b>
</th>
<th>
<b>Ilość</b>
</th>
<th></th>
</tr>
#foreach (var item in Model.orderedProductSet)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.ProduktSet.name)
</td>
<td>
#Html.DisplayFor(modelItem => item.ProduktSet.price)
</td>
<td>
#Html.EditorFor(model => item.quantity, new { htmlAttributes = new { #class = "form-control" } })
</td>
</tr>
}
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Potwierdź zmiany" class="btn btn-default" />
</div>
</div>
}
<div>
#Html.ActionLink("Powrót", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
My model (in separated classes of course):
public class ProductViewModel
{
public OrderSet orderSet { get; set; }
public IEnumerable<OrderedProductSet> orderedProduktSet { get; set; }
}
public partial class OrderedProduktSet
{
public int orderNumber{ get; set; }
public int productNumber { get; set; }
public int ilosc { get; set; }
public virtual ProduktSet ProduktSet { get; set; }
public virtual OrderSet OrderSet { get; set; }
}
You need to construct controls for you collection in a for loop or use a custum EditorTemplate for OrderedProduktSet so that the controls are correctly named with indexers and can be bound on post back. Note the for loop approach required that the collection be IList.
#model Shop.Models.ProductViewModel
#using(Html.BeginForm())
{
....
for(int i = 0; i < Model.orderedProductSet.Count; i++)
{
#Html.DisplayFor(m => m.orderedProductSet[i].ProduktSet.name)
....
#Html.EditorFor(m => m.orderedProductSet[i].quantity, new { htmlAttributes = new { #class = "form-control" } })
}
<input type="submit" />
}
Controller (the model will be bound, including the collection of OrderedProductSet)
public ActionResult Edit(ProductViewModel model)
{
....
}
Alternatively, you can create an EditorTemplate
/Views/Shared/EditorTemplates/OrderedProduktSet.cshtml
#model OrderedProduktSet
#Html.DisplayFor(m => m.ProduktSet.name)
#Html.EditorFor(m => m.quantity, new { htmlAttributes = new { #class = "form-control" } })
and in the main view
#model Shop.Models.ProductViewModel
#using(Html.BeginForm())
{
....
#Html.EditorFor(m => m.orderedProductSet)
<input type="submit" />
}
Viewbag is your friend here. You normally pass data from View to Controller in MVC. You can access data set in a Viewbag in the controller in your View.
The simplest way to let your controller handle your view is to create an actionresult method in your controller with the same name as your view.
For example, your view is called Index, thus you would have the following method in your controller to handle the view data:
public ActionResult Index()
{
return View();
}
Accessing a list:
Use a Viewbag.
Controller
Viewbag.MyList = myList
View
#foreach (var item in Viewbag.MyList)
Here is good link for more info:
http://www.asp.net/mvc/overview/older-versions/getting-started-with-aspnet-mvc4/adding-a-view
I have a model, ApplicantBranchList, that is used as a property in a larger model as follows:
[Display(Name = "Where would you want to work?")]
public ApplicantBranchList PreferedBranches { get; set; }
ApplicantBranchList:
public class ApplicantBranchList : ViewModel
{
public ApplicantBranchItem HeaderItem { get; set; }
public ApplicantBranchList()
{
HeaderItem = new ApplicantBranchItem();
}
public void MapFromEntityList(IEnumerable<ApplicantBranch> applicantBranches)
{
var service = new BranchService(DbContext);
var selectedIds = applicantBranches.Select(b => b.BranchId);
Items = service.ReadBranches()
.Where(i => !i.IsDeleted)
.Select(p => new ApplicantBranchItem { BranchName = p.Name, WillWorkAt = selectedIds.Contains(p.Id) });
}
public IEnumerable<ApplicantBranchItem> Items { get; set; }
}
ApplicantBranchList has its own editor template, and an inner editor template for each item in ApplicantBranchList:
Views/Shared/EditorTemplates/ApplicantBranchList.cshtml:
#model Comair.RI.UI.Models.ApplicantBranchList
<table>
<tr>
<th style="display: none;"></th>
<th>
#Html.DisplayNameFor(model => model.HeaderItem.BranchName)
</th>
<th>
#Html.DisplayNameFor(model => model.HeaderItem.WillWorkAt)
</th>
</tr>
#foreach (var item in Model.Items)
{
#Html.EditorFor(m => item)
}
</table>
Views/Shared/EditorTemplates/ApplicantBranchItem.cshtml:
#model Comair.RI.UI.Models.ApplicantBranchItem
<tr>
<td style="display: none;">
#Html.HiddenFor(m => m.BranchId)
</td>
<td>
#Html.DisplayFor(m => m.BranchName)
</td>
<td>
#Html.EditorFor(m => m.WillWorkAt)
</td>
</tr>
This editor renders properly in the view, but in the post action:
public ActionResult Create(ApplicantProfileModel model)
{
if (ModelState.IsValid)
{
var branches = model.PreferedBranches;
PreferedBranches.Items is null.
What am I doing wrong?
The problem is that ASP.NET can't figure out how to bind to Model.Items property.
To to fix it replace:
public IEnumerable<ApplicantBranchItem> Items { get; set; }
with this:
public List<ApplicantBranchItem> Items { get; set; }
and instead of:
#foreach (var item in Model.Items)
{
#Html.EditorFor(m => item)
}
use this one:
#for (var i = 0; i < Model.Items.Count; i++)
{
#Html.EditorFor(model => model.Items[i]) // binding works only with items which are accessed by indexer
}
With MVC and editor templates you don't need to manually move through a list and call #HTMLEditorFor.
Doing this:
#Html.EditorFor(model => model.Items)
is the same as:
#for (var i = 0; i < Model.Items.Count; i++)
{
#Html.EditorFor(model => model.Items[i]) // binding works only with items which are accessed by indexer
}
MVC will handle the iteration through your items and generate your editor template once per item. As is noted in the comments your template must be named the same as your model. Also, your model definition should be a singular representation of your model, not of type IEnumerable. Lastly, as noted in the comments, if you specify the template name parameter in your call to #Html.EditorFor() you will not have the benefit of the automatic iteration over your collection. You will need to manually iterate as is demonstrated above.
This is My model:
public class MyModel
{
public List<long> NeededIds { get; set; }
public string Name { get; set; }
}
My Controllers:
public ActionResult Create()
{
MyModel model = new MyModel();
model.NeededIds = new List<long> { 1, 2, 3, 4 };
return View(model);
}
[HttpPost]
public ActionResult Create(MyModel model)
{
string name = model.Name;
List<long> ids = model.NeededIds;
return RedirectToAction("Index");
}
And View:
#model TestMVC.Models.MyModel
#using(Html.BeginForm()) {
<table>
<thead>
<tr>
<th>
Id
</th>
</tr>
</thead>
<tbody>
#foreach(long id in Model.NeededIds) {
<tr>
<td>
#id
</td>
</tr>
}
</tbody>
</table>
#Html.ValidationSummary(true)
<fieldset>
<legend>MyModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
I set NeededIds in Get action and in the view I can see NeededIds. I also need it in Post action, but in post action the NeededIds is always null. How can I get the property value in post action when I set it in get action? What is your suggestion?
You are not posting your NeededIds back to the server. In order to get this working you can add them as hidden fields in a for loop inside the form:
#for (int i = 0; i < Model.NeededIds.Count(); i++) {
#Html.HiddenFor(model => model.NeededIds[i])
}
if you are using layout page than simply remove the form tag from the layout page.
in addition to the answer by Yakimych
you have kept the ids as constant.. this means two things
1. you can use arrays in place of list
2.you can just save the ids list/array in TempData and retrive it back from there when POST happens
you can do this like this
in your GET handler
TempData.Add("ids",idArray);
in your POST handler
var idArray = (long[])TempData["ids"];