ASP MVC View posts null to Controller - c#

I am a beginner in ASP MVC, and, after a lot of help from SO, am progressing through ViewModels. Using a ViewModel however, I have encountered the following error.
Given the following View:
#model November.ViewModels.Staff_Salutation_VM
//...
using (Html.BeginForm("UpdateStaff", "Settings", FormMethod.Post,
new { #class = "clearfix parameter-form update-parameter update-staff", enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
//...
#for (int i = 0; i < Model.AvailableStaffMembers.Count; i++)
{
var staff = Model.AvailableStaffMembers[i];
<tr>
<td>#Html.HiddenFor(model => staff.ID)#Html.ValueFor(model => staff.ID)</td>
<td>
#Html.DropDownListFor(
model => model.SalutationID, Model.AvailableSalutations.Select(option => new SelectListItem
{
Text = option.Desc.ToString(),
Value = option.ID.ToString(),
Selected = (option.ID.ToString() == staff.SalutationID.ToString())
}
),
"Choose...")
</td>
<td>#Html.EditorFor(model => staff.FName)</td>
<td>#Html.EditorFor(model => staff.LName)</td>
<td>#Html.EditorFor(model => staff.Active)</td>
<td>Delete</td>
</tr>
}
and the following Controller:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using November.Models;
using November.ViewModels;
using November.DAL;
//...
//GET
var staffCreateViewModel = new Staff_Salutation_VM();
staffCreateViewModel.AvailableSalutations = new List<Prm_Salutation>();
var activeSalts = (from a in db.Prm_Salutations
where a.Active == true
orderby a.Desc ascending
select a);
staffCreateViewModel.AvailableSalutations = activeSalts.ToList();
staffCreateViewModel.AvailableStaffMembers = new List<Prm_Staff>();
var activeStaff = (from a in db.Prm_Staffs
where a.Active == true
orderby a.LName ascending
select a);
staffCreateViewModel.AvailableStaffMembers = activeStaff.ToList();
return View("StaffMembers", staffCreateViewModel);
//POST
public ActionResult UpdateStaff(Staff_Salutation_VM list)
{
if (ModelState.IsValid)
{
foreach (var formData in list) //no longer works due to dropping List<>
{
var tbl = db.Prm_Staffs.Where(a => a.ID.Equals(formData.ID)).FirstOrDefault();
if (tbl != null)
{
var Prm_StaffModel = new Prm_Staff();
Prm_StaffModel.SalutationID = formData.SalutationID;
Prm_StaffModel.FName = formData.FName;
Prm_StaffModel.LName = formData.LName;
Prm_StaffModel.Active = formData.Active;
}
}
db.SaveChanges();
ViewBag.UpdateRtrn = "Successfully Updated.";
return RedirectToAction("Parameters", new { param = "Staff Members" });
}
else
{
ViewBag.UpdateRtrn = "Failed ! Please try again.";
return RedirectToAction("Parameters", new { param = "Staff Members" });
}
}
return RedirectToAction("Parameters", new { param = "Staff Members" });
}
And, for good measure, the ViewModel itself:
public class Staff_Salutation_VM
{
public int ID { get; set; }
public int SalutationID { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public bool Active { get; set; }
public List<Prm_Salutation> AvailableSalutations { get; set; }
public List<Prm_Staff> AvailableStaffMembers { get; set; }
public Staff_Salutation_VM() { }
}
When triggered, no form values populate the ActionResult, resulting in a Object reference not set to an instance of an object. exception being thrown when the foreach (var formData in list) line is reached. Debugging shows list as being null. How can this be so? Or rather, what am I doing wrong?
EDIT: the list variable in my POST ActionResult is now getting data - or at least, is showing the various types in the class when debugged. How do I then iterate through it to save that data in the appropriate rows of the DB?

I totally missed the method signature, sorry! Your initial view load passes a model Staff_Salutation_VM but your UpdateStaff (form posted) is expecting List<Staff_Salutation_VM>. These are different animals. Change public ActionResult UpdateStaff(List<Staff_Salutation_VM> list) to public ActionResult UpdateStaff(Staff_Salutation_VM staff) just to see if you get past the null ref exception. Note, you'll need to remove your foreach since you don't have an IEnumerable coming in.

I hope this post will be helpful for you.
Model Binding To A List

Related

Count and Sum functions with help of ViewBag

I have a question how to solve my problem. There is a table with items. Each item has a status "open" or "closed". For instance, 9 items with "closed" status and 14 ones with "open". I need to find the difference between open and closed items (14 - 9 = 5). How can I do it with help of ViewBag? As I understood, it is required to write "count" function in controller and transmit the result to View via ViewBag. But I don't know how to write this code. The result should be shown on the View page.
Request.cs (Model):
public class Request
{
public int Id { get; set; }
public string Name { get; set; } = "";
public string Status { get; set; } = "";
}
Controller.cs:
public IActionResult Requests()
{
var Requests = _repo.GetAllRequests();
return View(Requests);
}
Repository:
public Request GetRequest(int id)
{
return _ctx.Requests.FirstOrDefault(c => c.Id == id);
}
public List<Request> GetAllRequests()
{
return _ctx.Requests.ToList();
}
View:
<div>
<table>
#foreach (var request in Model)
{
<tr>
<th>#request.Name</th>
<th>#request.Status</th>
</tr>
}
</table>
</div>
private StatisticScore()
{
var openCount =_ctx.Requests.Where(m=> m.Status == "Open").Count();
var closedCount = _ctx.Requests.Where(m=> m.Status == "Closed").Count();
ViewBag.Difference = openCount - closedCount
}
<label> Difference </label> #ViewBag.Difference
Also, I suggest you; Do not use status fields as strings. It will be easier for you if you keep it as an enum.
You would pass a predicate to Count to filter the requests by status:
public IActionResult Requests()
{
var requests = _repo.GetAllRequests();
ViewBag.OpenRequests = requests.Count(r => r.Status == "open");
ViewBag.ClosedRequests = requests.Count(r => r.Status == "closed");
return View(requests);
}
However, rather than using the ViewBag you could create a view model to hold all the information/data required by the view:
// ViewModel
public class RequestViewModel
{
public List<Request> Requests { get; set; }
public int OpenRequests { get; set; }
public int ClosedRequests { get; set; }
}
// Controller
public IActionResult Requests()
{
var requests = _repo.GetAllRequests();
var viewModel = new RequestViewModel();
viewModel.OpenRequests = requests.Count(r => r.Status == "open");
viewModel.ClosedRequests = requests.Count(r => r.Status == "closed");
viewModel.Requests = requests;
return View(viewModel);
}
// View: set the model for the view
#model Project.Namespace.RequestViewModel
...
<div>
<div>Open Requests: #model.OpenRequests</div>
<div>Closed Requests: #model.ClosedRequests</div>
<div>Difference/delta: #(model.OpenRequests - model.ClosedRequests)</div>
</div>

Add value to list

I am calling a API method that is returning some question and answer as List. I need show this list in View, not sure how to add value to the faq list. As I am sending this List that is part of Model to the View to show in on the screen.
Inside the foreach loop is where I have to add value of web api to the faq List.
This is my method which is returning the Model.
[HttpGet]
public async Task<ActionResult> ShowContact(int loanId)
{
HelpCenterViewModel helpCenterViewModel = new HelpCenterViewModel();
helpCenterViewModel.ContactInfo.loanId = loanId;
string json = string.Empty;
List<Faq> FaqObject = null;
var responseApi = await httpClient.GetAsync(string.Format("{0}/{1}",
CommonApiBaseUrlValue, "faqs"));
if (responseApi.IsSuccessStatusCode)
{
json = responseApi.Content.ReadAsStringAsync().Result;
FaqObject = new JavaScriptSerializer().Deserialize<List<Faq>>(json);
}
var response = new
{
success = FaqObject != null,
data = FaqObject
};
foreach (var faqitem in response.data)
{
//This is where I dont know how to add to faq list.
//helpCenterViewModel.Faq.Answer = faqitem.Answer;
//helpCenterViewModel.Faq.Category = faqitem.Category;
}
return View(helpCenterViewModel);
}
This is the Model that I am retunign it to view:
public class HelpCenterViewModel
{
public List<Faq> Faq { get; set; }
public ContactUsInfo ContactInfo { get; set; }
public HelpCenterViewModel()
{
this.Faq = new List<Faq>();
this.ContactInfo = new ContactUsInfo();
}
}
and this is the faq class:
public class Faq
{
public int Id { get; set; }
public string Category { get; set; }
public string Question { get; set; }
public string Answer { get; set; }
}
and this is my view:
#model IEnum erable<Carfinance.Loans.Web.ViewModels.HelpCenterViewModel>
#foreach (var item in Model)
{
<li>#Html.DisplayFor(faq => item.Faq)</li>
}
But It gave me this error.
The 'DelegatingHandler' list is invalid because the property 'InnerHandler' of 'CorsMessageHandler' is not null.
Parameter name: handlers
You need to create a new object for each of your items and add them to your list. This can be done in various ways, depending on how verbose you want your implementation to be:
foreach (var faqitem in response.data)
{
var faq = new Faq();
faq.Answer = faqitem.Answer;
faq.Category = faqitem.Category;
helpCenterViewModel.Faq.Add(faq);
}
OR
foreach (var faqitem in response.data)
helpCenterViewModel.Faq.Add(new Faq()
{
Answer = faqitem.Answer;
Category = faqitem.Category;
});
OR
helpCenterViewModel.Faq = response.data.Select(x => new Faq {
Answer = x.Answer,
Category = x.Category
}).ToList();
Cleaned up the code some, but you already have a List<Faq>, so just assign it to your model.
[HttpGet]
public async Task<ActionResult> ShowContact(int loanId)
{
string json = string.Empty;
List<Faq> FaqObject = null; // Should probably be new List<Faq>
var responseApi = await httpClient.GetAsync(string.Format("{0}/{1}", CommonApiBaseUrlValue, "faqs"));
if (responseApi.IsSuccessStatusCode)
{
json = responseApi.Content.ReadAsStringAsync().Result;
FaqObject = new JavaScriptSerializer().Deserialize<List<Faq>>(json);
}
var response = new
{
success = FaqObject != null,
data = FaqObject
};
return View(new HelpCenterViewModel
{
ContactInfo=new ContactInfo {loanId},
Faq=FaqObject
});
}
Not sure what you were doing with the response variable, so I just left it there, but it appears to do nothing useful and could be removed as well. Then you'd have this:
[HttpGet]
public async Task<ActionResult> ShowContact(int loanId)
{
var responseApi = await httpClient.GetAsync(string.Format("{0}/{1}", CommonApiBaseUrlValue, "faqs"));
if (responseApi.IsSuccessStatusCode)
{
return View(new HelpCenterViewModel
{
ContactInfo=new ContactInfo {loanId},
Faq=new JavaScriptSerializer().Deserialize<List<Faq>>(
responseApi.Content.ReadAsStringAsync().Result)
});
}
return View(new HelpCenterViewModel
{
ContactInfo=new ContactInfo {loanId},
Faq=new List<Faq>()
});
}
well, the Faq property on HelpCenterViewModel is really a List<Faq> (kind of misleading naming you have there), so use the Add method:
foreach (var faqitem in response.data)
{
var faq = new Faq();
faq.Answer = faqitem.Answer;
faq.Category = faqitem.Category;
helpCenterViewModel.Faq.Add(faq);
//^ this Faq is a List
}
You should pluralize your List<Faq>'s name to Faqs to prevent confusing yourself.

How to call ArrayList from Controller to view in MVC4?

i want to call Arraylist in view. I will explain my issue clearly.
My Controller Code
public ActionResult customerid()
{
List<Customer> n = (from c in db.Customers where c.IsDeleted == false select c).ToList();
var customertype = string.Empty;
for (var i = 0; i < n.Count; i++)
{
var objCustomerName = n[i].DisplayName;
var objCustomerID = n[i].CustomerID;
var objCusCreatedDate=n[i].CreatedDate;
var objNextDate = objCusCreatedDate.GetValueOrDefault().AddDays(120);
var salescount = (from sc in db.SalesOrders where sc.CustomerID==objCustomerID && sc.CreatedDate >= objCusCreatedDate && sc.CreatedDate<= objNextDate select sc.SalesOrderID).Count();
if (salescount <= 3&& salescount> 0)
{
customertype = "Exisiting Customer";
}
else if (salescount >= 3)
{
customertype = "Potential Customer";
}
else
{
customertype = "New Customer";
}
ArrayList obj = new ArrayList();
{
obj.Add(new string[] { objCustomerName, customertype, salescount.ToString()});
}
var details = obj;
}
return View();
}
My View Model
public class CustomerTypeViewModel
{
public System.Guid CustomerID { get; set; }
public string CustomerName { get; set; }
public DateTime CreatedDate { get; set; }
public string SalesCount { get; set; }
public string CustomerType { get; set; }
}
I want to call this array list in view. How I do that? That is i am generating one view based on controller code I need output same as like which is mentioned in the below image .
Wanted Output
Wanted Output
So i put all the fields (which i going to give as a column in View) in Array list. Now i want to call that Arraylist
obj.Add(new string[] { objCustomerName, customertype, salescount.ToString()});
in view . How I do that? I tried to explain my issue as per my level best. please understand my problem and tell me one solution. I am new to MVC so please help me to solve this problem.
In your controller:
List<CustomerTypeViewModel> obj = new List<CustomerTypeViewModel>();
obj.Add(new CustomerTypeViewModel(){
CustomerName = objCustomerName,
CustomerType = customertype,
SalesCount = salescount.ToString()
});
return View(obj);
In your view
#model IEnumerable<CustomerTypeViewModel>
and display values like this
#if (Model.Any()) {
foreach (var m in Model) {
#Html.DisplayFor(x => m.CustomerName)
#Html.DisplayFor(x => m.CustomerType)
}
}

I want to show viewbag list

in my class menu code and description name
namespace Test.Controllers
{
class menus
{
public string Idmenus { get; set; }
public string desname { get; set; }
}
}
in my controller I want to add data to object List
var viewdes = db.menudescriptions.Where(w => w.Idmenu == mids).ToList();
var desc = new List<menus>();
foreach (var b in viewdes) {
desc.Add(new menus { Idmenus = b.Iddesmenu });
desc.Add(new menus { desname = b.descriptionname });
}
if ((desc.Count != 0))
{
ViewBag.Id = desc.ToList();
}
I want to show ViewBag.Id To Viewpage?
#if (ViewBag.Id != null)
{
<td>
#foreach (var per in `enter code here`)
{
#Html.ActionLink(#per.ToString(), "detail", new { mides = per })
}
</td>
}
You basically just need to iterate your ViewBag.Id like what you normally do when using foreach
#foreach(var per in ViewBag.Id as List<menus>)
{
#Html.ActionLink(per.desname, "detail", new { mides = per })
}

Two dropdowns in one view, second dependent on what is selected on first

Just started messing around with MVC and have been trying to accomplish this by looking at this example:
http://forums.asp.net/t/1670552.aspx
I keep getting this error:
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Line 9: #using (Html.BeginForm("Index","Home",FormMethod.Post, new{id = "ID"})){
Line 10: #Html.DropDownListFor(m=>m.id, new SelectList(Model.list, "id","name"),"selectThis")
Line 11: }
Here is the code:
Model classes (stupid names, I know):
These are in a console application used only to store models.
namespace Model
{
public class Model
{
public int id { get; set; }
public string name { get; set; }
}
public class List
{
public int id { get; set; }
public List<Model> list = new List<Model>();
}
public class subModel
{
public int id { get; set; }
public int modId { get; set; }
public string name { get; set; }
}
public class subList
{
public List<subModel> list = new List<subModel>();
}
}
Controller: (was populating subList.list and List.list with methods in the class, but decided to try it this way now, was getting the same error)
namespace DropboxTest.Controllers
{
public class HomeController : Controller
{
//
// GET: /Model/
public ActionResult Index()
{
LoadModel();
return View();
}
[ValidateInput(false)]
[AcceptVerbs("POST")]
public ActionResult Index([Bind(Exclude = "id")]Model.Model model)
{
var modId = Request["id"];
LoadModel();
LoadSubCategory(Convert.ToInt32(modId));
return View();
}
public void LoadModel()
{
Model.List listM = new Model.List();
listM.id = 0;
Model.Model mod1 = new Model.Model();
mod1.id = 1;
mod1.name = "me";
Model.Model mod2 = new Model.Model();
mod2.id = 2;
mod2.name = "me";
listM.list.Add(mod1);
listM.list.Add(mod2);
ViewBag.Model = listM;
}
public void LoadSubCategory(int id)
{
Model.subList subList = new Model.subList();
Model.subModel sub1 = new Model.subModel();
Model.subModel sub2 = new Model.subModel();
sub1.id = 1;
sub1.name = "notme";
sub1.modId = 1;
sub2.id = 1;
sub2.name = "notme";
sub2.modId = 1;
subList.list.Add(sub1);
subList.list.Add(sub2);
List<Model.subModel> sel = new List<Model.subModel>();
foreach (var item in subList.list)
{
if (item.modId == id)
{
sel.Add(item);
}
}
ViewBag.SubModel = sel;
}
}
}
View: (I have no idea if anything for subModel dropdown is working as I haven't even gotten to that part yet, but w/e.)
#model Model.List
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
#using (Html.BeginForm("Index","Home",FormMethod.Post, new{id = "ID"})){
#Html.DropDownListFor(m=>m.id, new SelectList(Model.list, "id","name"),"selectThis")
}
#if (ViewBag.SubModel != null)
{
#Html.DropDownList("SubModel",ViewBag.SubModel as SelectList, "select one")
}
It's probably something really stupid but I've been stuck for a couple of hours trying different things.
PS: This is just a test app. After I see how it is done I will be doing one with and SQL DB, using models in ConsoleApplications to retrieve and store data from the DB and display it in views, so any advice on that will be also appreciated.
A big thank you to all that have read up to here and have a nice day.
You never pass a model to the view in the controller, you just store in ViewBag.Model.
Try something as follows:
[ValidateInput(false)]
[AcceptVerbs("POST")]
public ActionResult Index([Bind(Exclude = "id")]Model.Model model)
{
var modId = Request["id"];
//get model
var model = LoadModel();
//pass it to the view
return View(model);
}

Categories