How can i pass multiple radio button values to controller in ASP.NET MVC? - asp.net-mvc

I've a model that contains 3 tables in my view.
public class InExam
{
public AutoTests TheTest { get; set; }
public List<InTest> TheQuestions { get; set; }
public IEnumerable<Result> SingleQuee { get; set; }
}
First one made to get the detailed page, like "admin/AutoTests/id"
Second one made to get a list of questions linked to the page
Third one is to save radio button strings to post it back into the controller
my plan is to get (say) 20 questions that are linked with the detailed page, Adding 4 radio buttons for each question, and post back every selected button to the controller.
my view form :
#using (Html.BeginForm("Test", "Exams", new { id = Model.TheTest.id }, FormMethod.Post))
{
foreach (var item in Model.TheQuestions)
{
Kafo.Models.Result singleQuee = Model.SingleQuee.Where(x => x.Question == item.Question).FirstOrDefault();
<div class="container" style="padding-top:50px;direction:rtl;">
<h4 style="text-align:right;font-weight:bold;">#item.Question</h4>
<div class="container">
<div class="row" style="direction:rtl;">
<div class="col-lg-7" style="text-align:right;margin-right:10px;">
<div class="row">
#Html.RadioButtonFor(x => singleQuee.Question, new { #class = "form-control dot", #Name = singleQuee.Question, #Value = "1" })
<h5 style="padding-top:3px;padding-right:8px;">#item.RightAnswer</h5>
</div>
</div>
<div class="col-lg-7" style="text-align:right;margin-right:10px;">
<div class="row">
#Html.RadioButtonFor(x => singleQuee.Question, new { #class = "form-control dot", #Name = singleQuee.Question, #Value = "2" })
<h5 style="padding-top:3px;padding-right:8px;">#item.Answer2</h5>
</div>
</div>
<div class="col-lg-7" style="text-align:right;margin-right:10px;">
<div class="row">
#Html.RadioButtonFor(x => singleQuee.Question, new { #class = "form-control dot", #Name = singleQuee.Question, #Value = "3" })
<h5 style="padding-top:3px;padding-right:8px;">#item.Answer3</h5>
</div>
</div>
<div class="col-lg-7" style="text-align:right;margin-right:10px;">
<div class="row">
#Html.RadioButtonFor(x => singleQuee.Question, new { #class = "form-control dot", #Name = singleQuee.Question, #Value = "4" })
<h5 style="padding-top:3px;padding-right:8px;">#item.Answer4</h5>
</div>
</div>
#Html.HiddenFor(m => singleQuee.Question)
</div>
</div>
</div>
}
<button class="btn botton" type="submit" onclick="return confirm('');">END</button>
}
i used this line "Kafo.Models.Result singleQuee = Model.SingleQuee.Where(x => x.Question == item.Question).FirstOrDefault();" in my view because i can't use tuple foreach ( C# ver. 5 )
This is my controller code :
[HttpGet]public ActionResult Test(int? id)
{
using (KafoEntities db = new KafoEntities())
{
InExam model = new InExam();
model.TheTest = db.AutoTests.Where(x => x.id == id).FirstOrDefault();
model.TheQuestions = db.InTest.Where(x => x.UserEmail == currentUser.Email && x.ExamId == model.TheTest.id).OrderByDescending(x => x.id).Take(Convert.ToInt32(model.TheTest.QuestionsNumber)).ToList();
model.SingleQuee = db.Result.ToList();
return View(model);
}
}
[HttpPost]
public ActionResult Test(int? id, List<Result> singleQuee)
{
using (KafoEntities db = new KafoEntities())
{
int result = 0;
foreach (Result item in singleQuee)
{
Result sets = db.Result.Where(x => x.id == item.id).FirstOrDefault();
sets.Question = item.Question;
db.SaveChanges();
var check = db.InTest.Where(x => x.Question == item.Question).FirstOrDefault();
if (check != null)
{
if (item.Question == "1")
{
result++;
}
}
}
return RedirectToAction("Results", "Exams", new { Controller = "Exams", Action = "Results", id = done.id });
}
}
I first save the new string that came from the radio button value into the result record, then i call it back in the if condition to check it's value
The problem here is i get a
Object reference not set to an instance of an object.
when i post the test, it means that the list is empty, so i need to know what makes the radio buttons not working,
Thanks.

If you want to bind a List of object in Mvc, you should name the controller like "ModelName[indx].PropertyName". In your case it should be "singleQuee[0].Question".
Code Sample
var Indx = 0;
foreach (var item in Model.TheQuestions)
{
.....
var radioName = $"singleQuee[{Indx}].Question";
<div class="col-lg-7" style="text-align:right;margin-right:10px;">
<div class="row">
<input type="radio" name="#radioName" value="1" />
<h5 style="padding-top:3px;padding-right:8px;">#item.RightAnswer</h5>
</div>
</div>
.....
}
Action Method

Related

ASP.NET MVC - add to a viewmodel list and submit

I have an ASP.NET MVC program with an order/odc request form. I have a customer, order and order item model. What I want to do is allow the user to place an order for a list of items to be approved. I have the viewmodel being passed to the form/view with a few fields including a list of order item objects. I am able to dynamically add rows to the table which shows the list of order items but on submit there is nothing in the viewmodel list. What am I doing wrong? How do I pass the items entered into the table to the view so that I can submit to the database?
Controller
public ActionResult NewOdc()
{
var viewModel = new NewOdcViewModel()
{
OdcItems = new List<tblOdcItem>()
};
viewModel.OdcItems.Add(new tblOdcItem());
return View(viewModel);
}
I call this code from jQuery to add a new item to the list:
public ActionResult GetView(string rowCount)
{
tblOdcItem item = new tblOdcItem();
return PartialView("_OdcItemEditor", item);
}
And on submit I call this code:
[HttpPost]
public ActionResult NewOdcSubmit(NewOdcViewModel viewModel)
{
_context.tblOdcs.Add(new tblOdc());
...
I'm using a foreach to go through the list and create a partial for each item.
View:
#using (Html.BeginForm("NewOdcSubmit", "Odc", FormMethod.Post))
{
if (Model != null)
{
#Html.HiddenFor(m => m.OdcItems);
}
<div class="panel panel-info">
<div class="panel-heading">
<h2 class="panel-title">Enter New ODC</h2>
</div>
<div class="panel-body">
#Html.AntiForgeryToken()
<div class="form-group">
#Html.LabelFor(model => model.User.UserName, new { #class = "col-md-2 col-sm-1 control-label" })
<div class="col-md-2 col-sm-3">
#Html.TextBoxFor(model => model.User.UserName, new { #Value = ((PM_Portal2020.Models.tblUser)Session["User"]).UserName, #readonly = true })
</div>
#Html.LabelFor(model => model.User.Phone, new { #class = "col-md-2 col-sm-1 control-label" })
<div class="col-md-2 col-sm-3">
#Html.TextBoxFor(model => model.User.Phone, new { #Value = ((PM_Portal2020.Models.tblUser)Session["User"]).Phone })
</div>
</div>
<div class="form-group col-md-10 col-sm-12">
<label>Expenses</label>
<table id="submissionTable" class="table table-bordered">
<thead>
<tr>
<th>Qty</th>
<th>Description</th>
<th>Estimated Cost</th>
</tr>
</thead>
<tbody>
#foreach (PM_Portal2020.Models.tblOdcItem item in Model.OdcItems)
{
#Html.Partial("_OdcItemEditor", item)
}
</tbody>
</table>
<p>
<button id="add" type="button" class="btn btn-primary">Add</button>
</p>
</div>
<div class="form-group col-lg-10 col-sm-12">
#Html.LabelFor(model => model.Details, new { #class = "col-md-2 col-sm-1 control-label" })
<div class="">
#Html.TextAreaFor(model => model.Details, new { #class = "form-control" })
</div>
</div>
</div>
<div class="panel-footer">
<div class="">
<button type="submit" class="btn btn-success">Save</button>
#Html.ActionLink("Back", "Index")
</div>
</div>
</div>
}
PartialView in Shared folder:
#model PM_Portal2020.Models.tblOdcItem
<tr #Html.Id("tablerow" + Model.ID)>
<td>
<div class="editor-field">
#Html.TextBoxFor(model => model.Quantity, new { #class = "text-box single-line", name = "Quantity[" + Model.ID + "]", type = "text", value = "", required = "required" })
</div>
</td>
<td>
<div class="editor-field">
#Html.TextBoxFor(model => model.Description, new { #class = "text-box single-line", name = "Description[" + Model.ID + "]", type = "text", value = "", required = "required", id = "itemDesc" })
</div>
</td>
<td>
<div class="editor-field">
#Html.TextBoxFor(model => model.EstimatedCost, new { #class = "text-box single-line", name = "EstimatedCost[" + Model.ID + "]", type = "text", value = "", required = "required" })
</div>
</td>
<td>
<button type="button" class="btn btn-primary" onclick="removeTr(this);">
<span class="glyphicon glyphicon-trash"></span>
</button>
</td>
</tr>
View Model
public class NewOdcViewModel
{
public NewOdcViewModel()
{
}
public IList<tblOdcItem> OdcItems { get; set; }
public string Details { get; set; }
public int OdcId { get; set; }
public tblUser User { get; set; }
}
It submits to the controller but the odcitems list is always count = 0. Any help would be great. Thanks
Here is the javascript example, just use this function on add/delete operation to re-arrange name.
function RearangeName(){
var i = 0;
$("#submissionTable>tbody>tr").each(function () {
$(this).find("input").each(function () {
if ($(this).prop("name").indexOf('Quantity') > 0) {
$(this).attr('name', "OdcItems[" + i + "].Quantity");
}
if ($(this).prop("name").indexOf('Description') > 0) {
$(this).attr('name', "OdcItems[" + i + "].Description");
}
if ($(this).prop("name").indexOf('EstimatedCost') > 0) {
$(this).attr('name', "OdcItems[" + i + "].EstimatedCost");
}
});
i++;
});
}
the name should be matched with model property, so in partial view, you have set name as OdcItems[0].Quantity instead of Quantity[" + Model.ID + "].
#Html.TextBoxFor(model => model.Quantity, new { #class = "text-box single-line", name = "OdcItems[0].Quantity", type = "text", value = "", required = "required" })
eg.
OdcItems[0].Quantity
OdcItems[1].Quantity
OdcItems[2].Quantity
....
OdcItems[n].Quantity

How do I update a specific database entry with a view model as controller method attribute

I have an input table in my website which is connected to a View Model. In the controller method, I pass this View Model to the controller and vice versa, meaning the controller populates the view model with data from the data base and the view returns a view model populated with form data the user might have entered.
The problem is that once the view received the view model object, the "ID" attribute from the database is no longer there. When the Post method is called, there is no way to know which database entry must be updated.
My question is: How do I update a specific database entry when I pass a view model to the controller method?
Example Controller Method:
[HttpPost]
public ActionResult method(ViewModel vm)
{
DataContext.Context.Where(x => x.ID == vm.Object.ID) // this is where vm.Object.ID always returns "0", not the actual ID from the database entry
Context.SaveChanges();
return View(vm);
}
If you need more information, please let me know. Also, using jquery is not a viable option for this project. Thanks a lot for your help!
Edit:
View:
#model MyANTon.ViewModels.Q4_Answer_VM
#{
ViewBag.Title = "myANTon Anforderungserfassung";
ViewBag.HideNavBar = false;
}
#using (Html.BeginForm())
{
<div class="container">
<div class="jumbotron">
<hr />
<table class="grid" id="datatable">
<tr>
<th>Nr.</th>
<th>Last</th>
<th>Quelle</th>
<th>Ziel</th>
<th>Frequenz [/h]</th>
<th>Abstand [m]</th>
<th></th>
<th></th>
#{int i = 1; }
#for (var a = 0; a < Model.Matrix.Count; a++)
{
<tr>
<td>#(i++)</td>
<td>#Html.TextBoxFor(x => Model.Matrix[a].Load)</td>
<td>#Html.TextAreaFor(x => Model.Matrix[a].Source)</td>
<td>#Html.TextAreaFor(x => Model.Matrix[a].Goal)</td>
<td>#Html.TextAreaFor(x => Model.Matrix[a].Frequency)</td>
<td>#Html.TextAreaFor(x => Model.Matrix[a].Distance)</td>
<td><input type="submit" name="+" class="btn btn-default" value="+" /></td>
<td><input type="submit" class="btn btn-default" value="-" /></td>
</tr>
}
</table>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" name="Speichern" value="Speichern" />
<input type="submit" class="btn btn-default" value="Speichern und weiter" />
<input type="button" class="btn btn-default" value="Weiter zu Schritt 5" onclick="#("window.location.href='" + #Url.Action("Q_Fifthpage", "Home") + "'");" />
</div>
</div>
</div>
</div>
}
GET Method:
[HttpGet]
public ActionResult Q_FourthPage()
{
// get current Questionnaire ID
int CurrentQstID = Convert.ToInt32(Session["qstid"]);
// create vm object. Capacity is a column in the table.
var Q4ViewModel = new ViewModels.Q4_Answer_VM();
// look for existing input data columns for this questionnaire in db
if (db.Capacities.Any(x => x.Questionnaire_ID == CurrentQstID))
{
// answers exist
Q4ViewModel.Matrix.AddRange(db.Capacities.Where(x => x.Questionnaire_ID == CurrentQstID));
}
else
{
// new capacity matrix
Q4ViewModel.TMatrix = db.QuestionTexts.Where(x => x.ID == 21).FirstOrDefault();
Q4ViewModel.Matrix = new List<Models.Capacity>();
}
var tmpcapacity = new Models.Capacity();
tmpcapacity.Questionnaire_ID = Convert.ToInt32(Session["qstid"]);
Q4ViewModel.Matrix.Add(tmpcapacity);
db.Capacities.Add(tmpcapacity);
db.SaveChanges();
return View(Q4ViewModel);
}
POST Method:
[HttpPost]
public ActionResult Q_FourthPage(ViewModels.Q4_Answer_VM vm)
{
int currentQst = Convert.ToInt32(Session["qstid"]);
if (Request.Form["+"] != null)
{
var tmpcapacity = new Models.Capacity();
tmpcapacity.Questionnaire_ID = currentQst;
vm.Matrix.Add(tmpcapacity);
db.Capacities.Add(tmpcapacity);
db.SaveChanges();
return View(vm);
}
if (Request.Form["Speichern"] != null)
{
// save data
if (!ModelState.IsValid) return View("~/Views/Shared/Error.cshtml");
var tmpcapacity = new Models.Capacity();
for (var a = 0; a < vm.Matrix.Count; a++)
{
var current = vm.Matrix[a];
current.ID = vm.Matrix[a].ID;
if (db.Capacities.Any(x => x.ID == current.ID))
// if clause never triggers true
// vm does not contain capacity ID
{
// column exists and is changed (or not)
tmpcapacity.Distance = vm.Matrix[a].Distance;
tmpcapacity.Frequency = vm.Matrix[a].Frequency;
tmpcapacity.Source = vm.Matrix[a].Source;
tmpcapacity.Goal = vm.Matrix[a].Goal;
tmpcapacity.Load = vm.Matrix[a].Load;
Models.Capacity c = db.Capacities.Where(x => x.ID == current.ID).FirstOrDefault();
c = tmpcapacity;
db.SaveChanges();
}
else
{
// new column
tmpcapacity.Distance = vm.Matrix[a].Distance;
tmpcapacity.Frequency = vm.Matrix[a].Frequency;
tmpcapacity.Source = vm.Matrix[a].Source;
tmpcapacity.Goal = vm.Matrix[a].Goal;
tmpcapacity.Load = vm.Matrix[a].Load;
tmpcapacity.Questionnaire_ID = currentQst;
db.Capacities.Add(tmpcapacity);
db.SaveChanges();
}
}
db.SaveChanges();
}
return View(vm);
}
If you need to bind the ID to the Model then you need to use hidden filed under the form when you are using Razor.
#Html.HiddenFor(model => model.Id)
For more details
#using (Html.BeginForm("method", "ControllerName", FormMethod.Post))
{
#Html.HiddenFor(Model=>Model.ID)
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Button" />
</div>
</div>
}
Now you can access ID at your controller action method.
If you want to "save" the object ID and get it back when the post occurs, you need to store it into a hidden field using the .HiddenFor() HTML helper - something like this:
#using (Html.BeginForm())
{
#Html.HiddenFor(m => m.Object.Id);
<div class="container">
<div class="jumbotron">
Then, upon your POST, you should get back the Object.ID in your post body and you should be able to tell which object this is for.

my filtering options doesn't work but in the first page

I've written some ActionLinks to filter the data on a movieshop base on genre while using PagedList.Mvc for paging.
The problem is that the ActionLinks work properly,but only filter the movies existing on the first page. What can I do?
View:
#using PagedList.Mvc
#using Shop.CustomHtmlHelpers
#using Shop.Domain.Entities
#model PagedList.IPagedList<Shop.Domain.Entities.Movie>
#{
ViewBag.Title = "MovieDisplay";
}
<h2>MovieDisplay</h2>
#using (#Html.BeginForm("MovieDisplay", "Movies", FormMethod.Get))
{
<div class="container">
<div class="row">
<div class="col-md-10">
#foreach (Product p in Model)
{
var item = (Movie)p;
<div class="col-lg-3 col-md-3 col-sm-4 col-xs-6">
<div class="tile">
<br />
<b>#item.Title</b>
<br />
#item.Year
<br/>
#item.Genre
<br/>
#item.Director.Name
#Html.Image(#item.Image,"200")
<br />
$ #item.Price
<br/>
<br />
<button onclick="location.href = '#Url.Action("AddtoCart", "ShoppingCart", new {id = p.Id})'" type="button" class="btn btn-success btn-su btn-sm ">
<span> <i class="fa fa-shopping-basket" aria-hidden="true"></i></span> AddtoCart
</button>
<br />
<br /><br />
</div>
</div>
}
</div>
</div>
</div>
}
#Html.ActionLink("Horror", "MovieDisplay", new { Genre = "Horror" } )
#Html.ActionLink("Action", "MovieDisplay", new { Genre = "Action" })
#Html.ActionLink("Drama", "MovieDisplay", new { Genre = "Drama" })
#Html.ActionLink("Animation", "MovieDisplay", new { Genre = "Animation" })
#Html.ActionLink("Comedy", "MovieDisplay", new { Genre = "Comedy" })
#Html.ActionLink("Crime", "MovieDisplay", new { Genre = "Crime" })
#Html.ActionLink("Sci-Fi", "MovieDisplay", new { Genre = "Sci-Fi" })
#Html.ActionLink("Fantasy", "MovieDisplay", new { Genre = "Fantasy" })
#Html.ActionLink("Historical", "MovieDisplay", new { Genre = "Historical" })
#Html.ActionLink("Musical", "MovieDisplay", new { Genre = "Musical" })
#Html.PagedListPager(Model, page => Url.Action("MovieDisplay", new { page, searchTerm = Request.QueryString["searchTerm"], Genre = "Genre" }))
Related ActionResult:
public ActionResult MovieDisplay(string searchTerm, int? page , string genre)
{
MediaContext mc = new MediaContext();
var movies = mc.Movies.ToList().ToPagedList(page ?? 1, 6);
if(genre !=null)
movies = movies.Where(m => m.Genre == genre).ToList().ToPagedList(page ?? 1, 6);
if (string.IsNullOrEmpty(searchTerm))
{ }
else
movies = mc.Movies.Where(x => x.Title.Contains(searchTerm)).ToList().ToPagedList(page ?? 1, 6);
return View(movies);
}
The problem was nothing but a silly mistake I made in the ActionResult :
movies = movies.Where(m => m.Genre == genre).ToList().ToPagedList(page ?? 1, 6);
Here I actually filter the existing movies ! I should have added the whole movies to the list just like I did for the searchTerm (that's why the search worked properly for all the pages)
movies = mc.Movies.Where(m => m.Genre == genre).ToList().ToPagedList(page ?? 1, 6);

How to check if any model item is assigned a value in MVC?

I have a model which have properties.And, i want to check that if any model item has some value or not.Also,no property is set to mandatory or optional using data-annotations.If no property is assigned and any value then i should set some model error e.g "Please specify some search criteria."
#using (Html.BeginForm("GetAdvanceSearchData", "Home", FormMethod.Post)){
<div class="rTableCell" style="border:none !important">
#Html.TextBoxFor(m => m.MessageStatus, new { placeholder = Html.DisplayNameFor(n => n.MessageStatus), #class = "fieldtextbox", #style = "height: 25px !important" })
#Html.ValidationMessageFor(m => m.MessageStatus)
</div>
<div class="rTableCell" style="border:none !important">
#Html.TextBoxFor(m => m.RequestType, new { placeholder = Html.DisplayNameFor(n => n.RequestType), #class = "fieldtextbox", #style = "height: 25px !important" })
#Html.ValidationMessageFor(m => m.RequestType)
</div>
<div class="rTableCell" style="border:none !important">
</div>
<div class="rTableCell" style="border:none !important">
<p class="submit">
<button type="submit" name="submit">
<i class="fa fa-arrow-right" aria-hidden="true"></i>
</button>
</p>
</div>
}
These are only few properties for the model.
In action method GetAdvanceSearchData you can do your own validity checks, in addition to validation attributes, or instead of them.
If you add an entry to ModelState then ModelState.IsValid will become false, and the added entry will show in the output of Html.ValidationMessageFor(...) or Html.ValidationSummary().
Example:
[HttpPost]
public ActionResult GetAdvanceSearchData(YourModel vm)
{
if (vm == null || (string.IsNullOrEmpty(vm.MessageStatus) && string.IsNullOrEmpty(vm.RequestType)))
{
ModelState.AddModelError("", "Please specify some search criteria")
// Using "" as Key will only show when you use #Html.ValidationSummary().
// Using "myErr" as Key will show when you use #Html.ValidationMessage("myErr").
// Using a property name as Key will show it next to the property if you use #Html.ValidationMessageFor(m => m.property).
}
if (ModelState.IsValid)
{
var results = ...
return View("ResultsView", results);
}
else
{
return View(vm);
}
}

Postback Contains No Model Data

I have a form that was not receiving any of my model information on the postback. I have tried to comment out more and more to make it simple so I can see when it works and so far I am having no luck. I have commented out most of the complex parts of the form and model so I do not know why I am having issues.
Below is the controller functions to show the form and to post it
public ActionResult MassEmail()
{
IEmailTemplateRepository templates = new EmailTemplateRepository();
IEmailFromAddressRepository froms = new EmailFromAddressRepository();
IEmployeeRepository emps = new EmployeeRepository();
List<ProductVersion> vers = new List<ProductVersion>();
MassEmailViewModel vm = new MassEmailViewModel();
vers = productVersionRepository.All.OrderBy(o => o.Description).ToList();
foreach (Employee e in emps.Employees.Where(o => o.Department == "Support" || o.Department == "Professional Services").OrderBy(o => o.Name))
{
if (e.Email != null && e.Email.Trim() != "")
{
vm.BCCAddresses = vm.BCCAddresses + e.Email + ",";
}
}
if (vm.BCCAddresses != "")
{
vm.BCCAddresses = vm.BCCAddresses.Substring(0, vm.BCCAddresses.Length - 1);
}
ViewBag.PossibleCustomers = customerRepository.All.OrderBy(o => o.CustomerName);
ViewBag.PossibleTemplates = templates.All.OrderBy(o => o.Description);
ViewBag.PossibleFromAddresses = froms.All.OrderBy(o => o.Description);
ViewBag.PossibleClasses = scheduledClassRepository.All.OrderByDescending(o => o.ClassDate).ThenBy(o => o.ClassTopic.Description);
vm.CCAddresses = "bclairmont#harrisworld.com";
//vm.Attachments = "";
vm.Body = "";
vm.Subject = "";
vm.ToAddresses = "";
vm.EmailFromAddressID = 1;
return View(vm);
}
[HttpPost]
public ActionResult MassEmail(MassEmailViewModel vm)
{
IEmailFromAddressRepository froms = new EmailFromAddressRepository();
System.Net.Mail.MailMessage message = new System.Net.Mail.MailMessage();
message.From = new System.Net.Mail.MailAddress(froms.Find(vm.EmailFromAddressID).Email);
string[] toAddresses = vm.ToAddresses.Split(',');
for (int i = 0; i < toAddresses.GetUpperBound(0); i++)
{
message.To.Add(new System.Net.Mail.MailAddress(toAddresses[i]));
}
string[] CCAddresses = vm.CCAddresses.Split(',');
for (int i = 0; i < CCAddresses.GetUpperBound(0); i++)
{
message.To.Add(new System.Net.Mail.MailAddress(CCAddresses[i]));
}
string[] BCCAddresses = vm.BCCAddresses.Split(',');
for (int i = 0; i < BCCAddresses.GetUpperBound(0); i++)
{
message.To.Add(new System.Net.Mail.MailAddress(BCCAddresses[i]));
}
message.IsBodyHtml = true;
message.BodyEncoding = Encoding.UTF8;
message.Subject = vm.Subject;
message.Body = vm.Body;
for (int i = 0; i < Request.Files.Count; i++)
{
HttpPostedFileBase file = Request.Files[i];
message.Attachments.Add(new Attachment(file.InputStream, file.FileName));
}
System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient();
client.Send(message);
return RedirectToAction("MassEmail");
}
Next is the code for my View
#model TRIOSoftware.WebUI.Models.MassEmailViewModel
#{
ViewBag.Title = "MassEmail";
}
#using (Html.BeginForm())
{
<h1 class="align-right">Mass E-Mail</h1>
<br />
<br />
<div>
<div class="editor-label" style="float:left; width:90px">
From
</div>
<div class="editor-field" style="float:left">
#Html.DropDownListFor(model => model.EmailFromAddressID,
((IEnumerable<TRIOSoftware.Domain.Entities.EmailFromAddress>)
ViewBag.PossibleFromAddresses).OrderBy(m => m.Description).Select(option => new
SelectListItem
{
Text = option.Description.ToString(),
Value = option.ID.ToString(),
Selected = (Model != null) && (option.ID == Model.EmailFromAddressID)
}), "Choose...")
</div>
</div>
<div class= "TagitEmailAddress" style="width:100%">
<div class="editor-label" style="float:left; clear:left; width:90px">
To
</div>
<div class="editor-field" style="float:left; width:88%">
#Html.TextBoxFor(model => model.ToAddresses, new { #class = "TagTextBox" })
</div>
</div>
<div class= "TagitEmailAddress" style="width:100%">
<div class="editor-label" style="float:left; clear:left; width:90px">
CC
</div>
<div class="editor-field" style="float:left; width:88%">
#Html.TextBoxFor(model => model.CCAddresses, new { #class = "TagTextBox" })
</div>
</div>
<div class= "TagitEmailAddress" style="width:100%">
<div class="editor-label" style="float:left; clear:left; width:90px">
<input type="button" id="BCC" value="BCC" class="btn"/>
</div>
<div class="editor-field" style="float:left; width:88%">
#Html.TextBoxFor(model => model.BCCAddresses, new { #class = "TagTextBox" })
</div>
</div>
<div style="width:100%">
<div style="float:left; clear:left; width:90px">
<input type="button" id="Subject" value="Subject" class="btn"/>
</div>
<div style="float:left; width:88%">
#Html.TextBoxFor(model => model.Subject, new { id = "SubjectText", style =
"width:100%" })
</div>
</div>
<div style="width:100%">
<div style="clear:left; float:left; width:100%;">
<div class="editor-field" style="float:left; width:100%;">
#Html.TextAreaFor(model => model.Body, new { id = "BodyText" })
</div>
</div>
</div>
<br />
<br />
<br />
<p style="clear:both">
<input type="submit" value="Send E-Mail" class="btn btn-primary"/>
</p>
<div id="DefaultEmailText">
<div class="editor-label" style="float:left; width:150px">
E-Mail Template
</div>
<div class="editor-field" style="float:left; padding-left:10px">
#Html.DropDownList("EmailTemplate",
((IEnumerable<TRIOSoftware.Domain.Entities.EmailTemplate>)
ViewBag.PossibleTemplates).Select(option => new SelectListItem
{
Text = option.Description,
Value = option.ID.ToString(),
Selected = false
}), "Choose...", new { ID = "Template", style = "width:200px" })
</div>
</div>
}
#section sidemenu {
#Html.Action("EmailsSideMenu", "Admin")
}
<script type="text/javascript">
var TemplateSubject = "";
var TemplateBody = "";
$(document).ready(function () {
$('#attach').MultiFile({
STRING: {
remove: '<i style="color:Red" class="icon-remove-sign"></i>'
}
});
$(".TagTextBox").tagit();
$("#BodyText").cleditor({
width: 800,
height: 400
});
$("#DefaultEmailText").dialog({
autoOpen: false,
height: 150,
width: 250,
title: "Default Subject / Body",
modal: true,
buttons: {
OK: function () {
var selectedTemplate = $("#DefaultEmailText #Template").val();
if (selectedTemplate != null && selectedTemplate != '') {
$.getJSON('#Url.Action("GetTemplate", "EmailTemplates")', { id:
selectedTemplate }, function (template) {
$("#SubjectText").val(template[0].Subject);
$("#BodyText").val(template[0].Body).blur();
});
}
$(this).dialog("close");
},
Cancel: function () {
$(this).dialog("close");
}
}
});
$('#Subject').click(function () {
$("#DefaultEmailText").dialog("open");
});
});
</script>
When I submit I get all null values except for the EmailFromAddressID which is 0 even though ti gets defaulted ot 1 when the view loads.
Any ideas?
EDIT____________________________________
I looked in DevConsole of Chrome and under network I coudl see my post request. Below is the detailed informaiton it contained. It looks to me liek the data did get sent to the server so I do not knwo why the server cant fill in my Model class
Request URL:http://localhost:53730/Customers/MassEmail
Request Headersview source
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Content-Type:application/x-www-form-urlencoded
Origin:http://localhost:53730
Referer:http://localhost:53730/Customers/MassEmail
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko)
Chrome/24.0.1312.52 Safari/537.17
Form Dataview sourceview URL encoded
EmailFromAddressID:1
ToAddresses:
CCAddresses:bclairmont#harrisworld.com
BCCAddresses:adunn#harrisworld.com,bclairmont#harrisworld.com,
bkelly#harrisworld.com,bhackett#harrisworld.com,jwade#harrisworld.com,
krichter#harrisworld.com,mroy-waters#harrisworld.com,
nburckhard#harrisworld.com,rlibby#harrisworld.com
Subject:Testing
Body:
Here is the class that gets passed back and forth from the clien tto server in case that helps
public class MassEmailViewModel
{
//public MassEmailViewModel()
//{
// ComplexQuery = new CustomerQueryViewModel();
//}
public int EmailFromAddressID;
// public CustomerQueryViewModel ComplexQuery;
public string ToAddresses;
public string CCAddresses;
public string BCCAddresses;
public string Subject;
public string Body;
//public string Attachments;
}
The DefaultModelBinder needs public properties not public fields.
Change your fields to properties and it should work:
public class MassEmailViewModel
{
public int EmailFromAddressID { get; set; }
public string ToAddresses { get; set; }
public string CCAddresses { get; set; }
public string BCCAddresses { get; set; }
public string Subject { get; set; }
public string Body { get; set; }
}
1) Have you tried specifing the route of the controller to which the model will be submited?. I mean, declaring the form like this:
#using (Html.BeginForm("YourAction","YourController", FormMethod.Post))
2) Why dont you just create a simple "Get" action that returns the strongly typed view and a "Post" action that receives the same model with the information you added in the view. Once you make work that, you can begin adding extra code so it is easy to trobleshoot the problem.
3) Make sure all of your helpers are inside the form.
4) Have you configured routing rules that can be making your post being redirected to another area, controller or action?

Resources