I want to store fields and checkboxes in a database table in a form: The connection table contains the following fields:
connection table:
public partial class Connection
{
[Key]
public int ID { get; set; }
public string CommunicationName { get; set; }
public bool IsSelected { get; set; }
}
Register table:
public class RegisterForm
{
#region Ctor
public RegisterForm()
{
}
#endregion Ctor
#region Properties
[Key]
[Required]
public int ID { get; set; }
[Required(ErrorMessage = ("Required"))]
[StringLength(50, ErrorMessage = "This field must be a maximum of 50 characters")]
[TypeConverter("NVarchar(121)")]
[DisplayName("FullName")]
public string FullName { get; set; }
public string Email { get; set; }
public List<Connection> Communications { get; set; }
}
The values of the checkbox fields in the list are displayed using the following method:
questionForm.Communications = db.Connections.ToList<Connection>();
Now how to save the information in the post and save it to the register table. ????????? What changes should be Create to the update, delete operation in the register?
controller for register:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "ID,FullName,PhoneNumber,Email,Communication,")]RegisterForm questionForm)
{
if (ModelState.IsValid)
{
db.Registers.Add(questionForm);
var data = db.SaveChanges();
return View("FormSuccessfullySubmitted");
}
return View(questionForm);
}
You should read about MVC model binding. Normally it could bound it without any problem. But lists are slightly different. You are to provide index of item in list. That is why it is better to use for, instead of foreach.
Check this view and grab it POSTed values to examine. Pay attention, that all list items are displayed using its index in list.
<table class="table">
#using (Html.BeginForm("Bind", "Bind", FormMethod.Post))
{
for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model[i].CommunicationName)
</td>
<td>
#Html.CheckBoxFor(modelItem => Model[i].IsSelected)
</td>
</tr>
}
<button type="submit">Submit</button>
}
</table>
Related
I've created an ASP.NET MVC CRUD site for entering numerical data into fields that are then added to the db which are raw test results. I have a pretty large table storing each individual raw test value which are weights and lbs of force. The problem I'm trying to noodle through is now that I have the raw data in the db, I need to pull values and do math on them in order to present summary data in another view.
For example, I have 6 columns:
hardness1_before
hardness2_before
hardness3_before
hardness1_after
hardness2_after
hardness3_after
These values are stored in the database. I need to calculate the average of all 3 hardness_before values, all 3 hardness_after values and then output the difference:
changeInHardness = (Avg_hardness_after) - (Avg_hardness_before)
At this point, I've figured out to do this in the html view itself, but I'm thinking there has got to be a better way using the viewmodel and controller? Here is my code and workflow below. I feel this solution is not ideal coding as shouldn't be we only passing data to views rather than using the view to calculate? Also, I wish to convert this data into a bar graph so I'm suspecting that I'll need publicly available values to do so.
Any thoughts and insight on how I might go about cleaning this up would be greatly appreciated.
Model classes:
public class Test
{
public int TestID { get; set; }
public int CustomerID { get; set; } //foreign key
[Display(Name = "Contact")]
public string? ContactName { get; set; }
[Required]
[Display(Name ="Mud Type")]
public string? MudType { get; set; }
public Customer? Customer { get; set; }
public ICollection<TestResults>?Results { get; set; }
}
public class TestResults
{
public int TestResultsID { get; set; } //primary key
public int TestID { get; set; } //foreign key
[Display(Name = "Hardness After")]
[Required]
public double S1Hardness_a { get; set; }
[Display(Name = "Hardness Before")]
[Required]
public double S1Hardness_b { get; set; }
[Display(Name = "Hardness After")]
[Required]
public double S2Hardness_a { get; set; }
[Display(Name = "Hardness Before")]
[Required]
public double S2Hardness_b { get; set; }
[Display(Name = "Hardness After")]
[Required]
public double S3Hardness_a { get; set; }
[Display(Name = "Hardness Before")]
[Required]
public double S3Hardness_b { get; set; }
public Test Test { get; set; } //nav prop
}
I'm using a ViewModel as the results returns many test results per test
public class ReportsViewModel
{
public Test TestDVm { get; set; } //1 test
public IEnumerable<TestResults>? TestResultsDVm { get; set; } //multiple tests
}
The controller:
public class ReportsController : Controller
{
private readonly MudTestAppContext _context;
public ReportsController(MudTestAppContext context)
{
_context = context;
}
public async Task<IActionResult> Index(int? id) //id = test ID
{
if (id == null)
{
return NotFound();
}
viewModel.TestDVm = await _context.Tests
.Include(i => i.Results)
.FirstOrDefaultAsync(t => t.TestID == id);
if (viewModel == null)
{
return NotFound();
}
return View(viewModel);
}
}
The view currently looks like this:
#model MudTestApp.Models.TestViewModels.ReportsViewModel
#{
ViewData["Title"] = "Report";
}
<div>
<h4>Details for Test Number: #Model.TestDVm.TestID</h4>
<hr />
<dl class="row">
<dt class = "col-sm-2">
#Html.DisplayNameFor(model => model.TestDVm.Customer.CompanyName)
</dt>
<dd class = "col-sm-10">
#Html.DisplayFor(model => model.TestDVm.Customer.CompanyName)
</dd>
<dt class = "col-sm-2">
#Html.DisplayNameFor(model => model.TestDVm.ContactName)
</dt>
<dd class = "col-sm-10">
#Html.DisplayFor(model => model.TestDVm.ContactName)
</dd>
</dl>
<div>
<a asp-controller="Tests" asp-action="Index">Back to List</a>
</div>
<h2>Test Results Summary</h2>
<div>
<table class="table">
<th>Compound</th>
<th>Test Temp</th>
<th>Change in Hardness</th>
#foreach (var item in Model.TestDVm.Results)
{
var AvgHb = ((item.S1Hardness_b + item.S2Hardness_b + item.S3Hardness_b) / 3);
var AvgHa = ((item.S1Hardness_a + item.S2Hardness_a + item.S3Hardness_a) / 3);
var AvgHard = AvgHa - AvgHb;
<tr>
<td>#Html.DisplayFor(modelItem => item.TestTemp)</td>
<td>#AvgHard</td>
</tr>
}
</table>
</div>
</table>
Edit My view is using the Employer model. Employer and JobPosting have a 1:M relationship. I will share more of the view for context.
Context: In my application, I want to show the Employer the number of applicants who applied for their JobPosting. The code that I currently have written is not returning any value. It's not throwing any errors- but it's not working either. I'm pretty sure the issue is in my controller, but I'll provide the Model and View as well.
Controller:
public ActionResult AppCount()
{
foreach (var app in db.JobPostings.ToList())
{
int id = app.JobPostingID;
int count= db.Applications.Where(a => a.JobPostingID == id).Count();
app.AppCount = count;
ViewBag.AppCount = count;
}
return View();
}
View:
#model InTurn_Model.Employer
.
.
.
<h2>My Job Postings</h2>
<p>
#Html.ActionLink("Create New", "Create", "JobPostings", null, null)
</p>
<div id="employeeContainer"></div>
<table class="table table-striped">
<tr>
<th>Position</th>
<th>Job Type</th>
<th>Number of Applicatiosn</th>
<th></th>
</tr>
#foreach (var item in Model.JobPostings)
{
if (item.EmployerID == Model.EmployerID)
{
<tr>
<td>
#Html.DisplayFor(model => item.Position)
</td>
<td>
#Html.DisplayFor(model => item.JobType)
</td>
<td>#ViewBag.AppCount</td>
<td>#Html.ActionLink("Details", "Details", "JobPostings", new { id = item.JobPostingID }, null) </td>
</tr>
}
}
</table>
Model:
[MetadataType(typeof(JobPostingMetaData))]
public partial class JobPosting
{
public int AppCount { get; set; }
private sealed class JobPostingMetaData
{
[Display(Name = "Job Posting ID")]
public int JobPostingID { get; set; }
[Display(Name = "Employer ID")]
public int EmployerID { get; set; }
[Display(Name = "Description")]
public string Desc { get; set; }
[Display(Name = "Job Type")]
public JobType JobType { get; set; }
[Display(Name = "Employment Type")]
public TimeType TimeType { get; set; }
[DataType(DataType.Currency)]
public decimal Wage { get; set; }
}
}
There are two problems that I see.
First, you are not passing Model from controller to view. However, you are iterating through Model.JobPostings. It is empty.
Second, you assign ViewBag.AppCount in the loop. So, all values, except for the last one are lost. But if you fix the first problem (use Model instead of ViewBag) - the second might go away by itself.
You need to specify the model in the view with #model:
#model YourNameSpace.JobPosting
Then return that model to the view:
public ActionResult AppCount()
{
foreach (var app in db.JobPostings.ToList())
{
int id = app.JobPostingID;
int count= db.Applications.Where(a => a.JobPostingID == id).Count();
app.AppCount = count;
ViewBag.AppCount = count;
}
return View(app);
}
This will make the values in the model available to the view. There is no need to use ViewBag, as AppCount is part of the model.
I was overthinking this. I just needed to set this up from the JobPosting model, and then the rest worked, I didn't need to iterate through the Controller at all.
public int AppCount => Applications.Count;
The view is not able to get my GridData, not sure why.
The code pass the GridData in the view, but the view page is not able to access GridData object.
UserMaster Models:
namespace Project.Models
{
public class UserMaster
{
[Key]
public int UserId { get; set; }
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Required]
}
public class UserMasterList
{
public List<UserMaster> GridData { get; set; }
}
}
Control:
UserMasterList userMasterList = new UserMasterList();
List<UserMaster> gl = new List<UserMaster>();
var userMasterListResult = _context.UserMaster.FromSql("EXECUTE [dbo].[UserMaster_Get] {0}", 0).ToList();
foreach (var data in userMasterListResult)
{
gl.Add(data);
}
userMasterList.GridData = gl;
return View(userMasterList);
View:
#model Project.Models.UserMaster
#foreach (var data in #Model.GridData) {
<tr>
<td>
#Html.DisplayFor(modelItem => data.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => data.LastName)
</td>
</tr>
}
Error:
The code pass the GridData in the view, but the view page is not able to access GridData object.
in view, you should have
#model Project.Models.UserMasterList
In your controller you are passing an object with type of UserMasterList, but in your view, model is type of UserMaster so that you should update used model in view as like as below:
#model Project.Models.UserMasterList
I have the following view:
#model Entities.Models.Tournament
#using (Html.BeginForm("Index", "Game"))
{
<table>
<tr>
<td><label>Team</label></td>
<td><label>Points Brought To Tournament</label></td>
</tr>
#{
const int maxNumOfTeams = 8;
for (int i = 0; i < maxNumOfTeams; i++)
{
<tr>
<td>#Html.DropDownList("SelectedTeams[" + i + "].TeamId", Model.Teams, "Please select:")</td>
<td>#Html.TextBox("SelectedTeams[" + i + "].Points", "", new { type = "number" })</td>
</tr>
}
}
</table>
<input type="submit" value="Create game" />
}
Is there a more elegant/"best practice" way of generating 8 dropdowns which are then used to build a List<T> and send it to an action method using HTTP Post?
The way I am doing it now seems messy as I have to build the dropdown's html ID string using concatenation and the i variable.
Here is the model:
public class Tournament
{
//This is populated with teams from the DB and then used in the view to allow the user to select a team
public IEnumerable<SelectListItem> Teams { get; set; }
//This represents the teams the user selected
public List<TeamWithPointsBroughtForward> SelectedTeams { get; set; }
}
public class TeamWithPointsBroughtForward
{
public int TeamId { get; set; }
public int Points { get; set; }
}
Here is the controller and action method:
public class GameController : Controller
{
public ActionResult Index(Tournament tournament)
{
Game game = new Game();
//TODO: set up the game object based on the tournament settings
return View(game);
}
}
I am new to asp.net mvc . This is how my model looks like:
[Bind(Exclude = "JournalId")]
public class Journal
{
[ScaffoldColumn(false)]
public int JournalId { get; set; }
[DisplayName("Customer")]
public int CustomerId { get; set; }
[DisplayName("Till")]
public int TillId { get; set; }
[Required(ErrorMessage = "A Journal name is required")]
[StringLength(160)]
public string Name { get; set; }
[DisplayName("Journal creation date")]
public DateTime Date { get; set; }
[DisplayName("Journal creation time")]
public DateTime Time { get; set; }
public virtual Customer Customer { get; set; }
public virtual Till Till { get; set; }
}
[Bind(Exclude = "CustomerId")]
public class Customer
{
[ScaffoldColumn(false)]
public int CustomerId { get; set; }
[Required(ErrorMessage = "A customer name is required")]
[StringLength(160)]
public string Name { get; set; }
[StringLength(250)]
public string Address { get; set; }
}
[Bind(Exclude = "TillId")]
public class Till
{
[ScaffoldColumn(false)]
public int TillId { get; set; }
[Required(ErrorMessage = "A till no is required")]
[StringLength(160)]
public string TillNo { get; set; }
[StringLength(100)]
public string TillOperator { get; set; }
}
This is how my one of my controller's action is defined:
public ViewResult Index()
{
var journals = db.Journals.AsEnumerable<Journal>();
ViewData["journals"] = journals;
return View();
}
and the view :
#model IEnumerable<ErikDemo.Models.Journal>
#foreach (var item in (IEnumerable<ErikDemo.Models.Journal>)ViewData["journals"]) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Customer.Name)
</td>
<td>
#Truncate(item.Till.TillNo, 25)
</td>
<td>
#Truncate(item.Name, 25)
</td>
<td>
#Html.DisplayFor(modelItem => item.Date)
</td>
<td>
#Html.DisplayFor(modelItem => item.Time)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.JournalId }) |
#Html.ActionLink("Details", "Details", new { id=item.JournalId }) |
#Html.ActionLink("Delete", "Delete", new { id=item.JournalId })
</td>
</tr>
Although when I am debugging I can see in the controller that the list passed to the View is not empty, and also I see that the ViewData["journals"].Local in a watch is not empty, nothing gets displayed. I have also used the View.Model and return View(journals.ToList()) to send data to the View, but nothing seems to work. What is the issue here? Been on that half a day.
This is wrong: (Well it can be done like this, but I think you want to pass a model)
public ViewResult Index()
{
var journals = db.Journals.AsEnumerable<Journal>();
ViewData["journals"] = journals;
return View();
}
Try this:
public ViewResult Index()
{
var journals = db.Journals.AsEnumerable<Journal>();
return View(journals); //You just passed journals as a model
}
Also if you are using mvc 3 you can use ViewBag instead of ViewData
Example:
ViewData["Journal"] = "my string";
is the same as
ViewBag.Journal = "my string";
The ViewBag is dynamic, so you can use dot notation.
Additionally
This code:
#model IEnumerable<ErikDemo.Models.Journal>
#foreach (var item in (IEnumerable<ErikDemo.Models.Journal>)ViewData["journals"])
Should be like this:
#model IEnumerable<ErikDemo.Models.Journal>
#foreach (var item in Model)
Update:
I'm not sure what you're doing with this db.Journals.AsEnumerable<Journal>();
You should have a method somewhere that gets data from a table or table(s) and returns Journals. So lets say this all comes from one table in a database:
public class JournalViewModel
{
public IEnumerable<Journals> GetJournals()
{
using(var db = new ErikDataContext())
{
return db.Journals.ToList();
}
}
}
Then in the action:
public ViewResult Index()
{
var journals = new JournalsViewModel.GetJournals();
return View(journals); //You just passed journals as a model
}
Did you forget the <table> tag? If you haven't viewed the source of your page as it is rendered, I would recommend that you do this as a next step.