Populate ArrayList based on checkbox - c#

I'm trying to find a way to send an email to selected recipients based on whether or not their email has been checked. We have a database with the emails in, and I've manually added a checkbox to resultant table. On clicking "Send", I want the email to send to those people based on whether or not they've been checked.
I thought the best way to do this would be to create an ArrayList, and then use message.CC.Add(emailArray), but that gives invalid arguments.
I then tried
string Email = emailArray.ToString()
//and then
message.CC.Add(email)
which didn't give errors, but it only sends to whomever clicks the button, IE myself or another colleague, and doesn't add the CCs. SMTP etc is all correct, as the email will send, just not to the ticked recipients.
ArrayList emailArray = new ArrayList();
if (Request.Form["chkBox"].Equals(true))
{
emailArray.Add(db.tblMailRecipients.Include(t => t.Email));
}
string email = emailArray.ToString();
message.To.Add(email);
smtp.Send(message);
Response.Redirect("~/Home/Index");
The above code shows where I'm trying to get the emails and put it into the Arraylist.
Is it to do with how I'm getting the checkbox value and then relating (or not?) that to the row in the table?
We're using ASP.NET MVC with C#.
Any help would be appreciated :).
Thanks
Update
The following code is for the page listing recipients with the checkboxes:
#using (Html.BeginForm("SendEmail", "BulkMail", FormMethod.Post))
{
<table class="table">
<tr>
<th>
#Html.DisplayNameFor(model => model.LastName)
</th>
<th>
#Html.DisplayNameFor(model => model.FirstName)
</th>
<th>
#Html.DisplayNameFor(model => model.Email)
</th>
<th>
#Html.DisplayNameFor(model => model.Company)
</th>
<th>
#Html.DisplayNameFor(model => model.LastEmailDate)
</th>
<th>
Check
</th>
<th></th>
</tr>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Email)
</td>
<td>
#Html.DisplayFor(modelItem => item.Company)
</td>
<td>
#Html.DisplayFor(modelItem => item.LastEmailDate)
</td>
<td>
<input id="chkBox" name="chkBox" type="checkbox" />
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=item.MailRecipientId }) |
#Html.ActionLink("Details", "Details", new { id=item.MailRecipientId }) |
#Html.ActionLink("Delete", "Delete", new { id=item.MailRecipientId })
</td>
</tr>
}
</table>
<input type="submit" value="Submit" />
}
The message is hardcoded in the send mail function at the moment.

You have:
<input id="chkBox" name="chkBox" type="checkbox" />
Inside a foreach loop, which will repeat the id="chkBox", generating invalid HTML.
What you should do is create a Property in your Model. e.g.
public bool isChecked {get;set;}
Then display your Model using forloop: MVC Model binder requires the fields to be in the form: [0].PropertyName
#for(var i =0; i < Model.Count(); i++) {
<tr>
<td>
#Html.DisplayFor(m => m[i].LastName)
</td>
...... Removed HTML
<td>
#Html.CheckBoxFor(m => m[i].isChecked)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id=Model[i].MailRecipientId }) |
..... Removed HTML
</td>
</tr>
}
When you Submit the Form:
[HttpPost]
public ActionResult SendEmail(List<CLASS_NAME> model)
{
var emails = model.Where(s => s.isChecked).Select(s => s.Email).ToArray();
............/////
}

Apologies for the lack of interaction with this thread, had other stuff come up which was urgently needed. Firstly, thanks for all your help. I had a look today and came up with the following solution:
Add
<input type="checkbox" name="chkBox" value="#item.Email" />
into the view where emails etc can be selected. I then added:
message.Bcc.Add(Request.Form["chkBox"])
To the controller for the SMTP etc, and it seems to work pretty well :).
Thanks

Related

Action based redirect ASP.Net Core Razor

Synopsis of the place I am at:
In my program on page 1 they select a printer and click a button which submits a service call and loads the next page, machine information. The redirect action calls the following method:
public async Task<IActionResult> OnGetSelectThisPrinter(int? printerID)
{
var printerServiceCall = new Service_Calls
{
PrinterID = (int)printerID,
Time = DateTime.Now,
Date = DateTime.Now
};
_context.Service_Calls.Add(printerServiceCall);
await _context.SaveChangesAsync();
var ServiceCalls = from m in _context.Service_Calls
select m;
Service_Calls ServiceCall = ServiceCalls.Last();
return RedirectToPage("MachineInformaion?id=" + ServiceCall.ID);
//return RedirectToPage("./Index");
}
In this code the printerID = 1 is a placeholder until I work out how to pass in a specific machines details (any help on passing through that would be helpful).
The HTML for this page, with the buttons, is as follows:
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Printer[0].MachineID)
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.LogSortParam">#Html.DisplayNameFor(model => model.Printer[0].Log_ID)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.LeaseSortParam">#Html.DisplayNameFor(model => model.Printer[0].Lease_ID)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.SerialSortParam">#Html.DisplayNameFor(model => model.Printer[0].Serial_Number)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.SolutionSortParam">#Html.DisplayNameFor(model => model.Printer[0].Solution)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.AdditionalSortParam">#Html.DisplayNameFor(model => model.Printer[0].Additional_Info)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.InstallationSortParam">#Html.DisplayNameFor(model => model.Printer[0].InstallationDate)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.MonoClickSortParam">#Html.DisplayNameFor(model => model.Printer[0].Mono_Click)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.ColourCLickSortParam">#Html.DisplayNameFor(model => model.Printer[0].Colour_Click)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.MinimumSortParam">#Html.DisplayNameFor(model => model.Printer[0].Minimum)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.PartsSortParam">#Html.DisplayNameFor(model => model.Printer[0].Parts_Warranty)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.ITSortParam">#Html.DisplayNameFor(model => model.Printer[0].IT_Support)</a>
</th>
<th>
<a asp-page="./SelectPrinter" asp-route-sortOrder="#Model.ContractSortParam">#Html.DisplayNameFor(model => model.Printer[0].Contract_Type)</a>
</th>
<th>Select Printer</th>
</tr>
</thead>
<tbody>
#foreach (var item in Model.Printer) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.MachineID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Log_ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Lease_ID)
</td>
<td>
#Html.DisplayFor(modelItem => item.Serial_Number)
</td>
<td>
#Html.DisplayFor(modelItem => item.Solution)
</td>
<td>
#Html.DisplayFor(modelItem => item.Additional_Info)
</td>
<td>
#Html.DisplayFor(modelItem => item.InstallationDate)
</td>
<td>
#Html.DisplayFor(modelItem => item.Mono_Click)
</td>
<td>
#Html.DisplayFor(modelItem => item.Colour_Click)
</td>
<td>
#Html.DisplayFor(modelItem => item.Minimum)
</td>
<td>
#Html.DisplayFor(modelItem => item.Parts_Warranty)
</td>
<td>
#Html.DisplayFor(modelItem => item.IT_Support)
</td>
<td>
#Html.DisplayFor(modelItem => item.Contract_Type)
</td>
<td>
<form method="get" asp-page-handler="OnGetSelectThisPrinter" asp-route-id="#item.MachineID">
<button value="Select Printer" />
</form>
</td>
</tr>
}
</tbody>
</table>
However, at the moment the buttons don't do anything. It looks like they aren't going into the OnGetSelectThisPrinter Method. Any help would be greatly appreciated.
I suggest you can use <a> tag to access the handler, since you only need to pass a parameter.
<a asp-page="/Printer" asp-page-handler="SelectThisPrinter" asp-route-printerID="#item.MachineID">SelectThisPrinter</a>
Handler in Printer page:
public IActionResult OnGetSelectThisPrinter(int printerID)
{
...
}
To start, this tutorial gives a much more in depth discussion of the answer I'm about to give. Check it out: https://www.learnrazorpages.com/razor-pages/handler-methods
Hi there! Let's start with making the button work. In order to redirect the user to a particular action of the page, we can use the asp-page-handler attribute to specify the method that handles the request. Additionally, we use the asp-route-id attribute to describe which printer we have selected. Finally, we wrap this all up in a form. So, we replace
<input type="button" onclick="SelectThisPrinter()" value="Select Printer" />
with
<form method="get" asp-page-handler="selectThisPrinter" asp-route-id="#item.MachineID">
<button value="Select Printer" />
</form>
Then, in your code-behind, we can perform some simple changes to your handler. We change
public async Task<IActionResult> SelectThisPrinter()
{
int printerID = 1;
...
}
to
public async Task<IActionResult> OnGetSelectThisPrinter(int? printerId)
{
...
}
I hope this helps. Let me know if you have any further questions.

How can I filter data in a Razor view with a dropdown

Hello I'm new to MVC and I'm trying to do a filtering for my index page, I want to be able to filter the graduation Status.
So when I go into the index I will see every status and I want to filter for example only the person with the graduated Status or the Pass/failed Status
Thank you in advance!
Index Page
Controller:
var graduates = db.Graduated_Students;
return View(graduates.ToList());
View:
<div class="content-body">
<div class="row">
<form action="#" method="post">
<div class="col-xs-12 col-sm-9 col-md-12">
<table class="table">
<tr>
<th>
#Resource.FirstName
</th>
<th>
#Resource.LastName
</th>
<th>
#Resource.CohortNumber
</th>
<th>
Placements
</th>
<th>
#Resource.GraduationStatus
</th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem =>
item.FirstName)
</td>
<td>
#Html.DisplayFor(modelItem =>
item.LastName)
</td>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
#Html.DisplayFor(modelItem =>
item.PartnerName)
</td>
<td>
#Html.DisplayFor(modelItem =>
item.GraduationStatus)
</td>
You could use linq in the View to filter the data
In the View
#foreach (var item in Model.Where(t=> t.GraduationStatus == <the graduation status selected in the dropdown> );
This approach Gets all the data from the database and then performs the filtering
That approach would work however a better approach would be to send the Selected GraduationStatus to the controller as a parameter and then perform the filtering directly on the db variable
In the Controller
public IActionResult GeStudents(GraduationStatus selectedGraduationStatus)
{
var graduates = db.Graduated_Students.Where(t=> t.GraduationStatus == selectedGraduationStatus);
return View(graduates.ToList());
}
This way you don't get all of the students from the database but only the ones which match the filter

How to add a where clause when returning a list in a view Mvc5

Is it possible to add a where clause in the view rather than the controller as I don't want to change the retrieval of information in the controller. I currently am retrieving a list of restaurants but want to only show restaurants where the logged in users email is the same as the restaurants email.
<div class="col-xs-12">
<table class="table table-condensed table-striped">
<tr>
<th>
#Html.DisplayNameFor(model => model.Rating)
</th>
<th>
#Html.DisplayNameFor(model => model.RestaurantName)
</th>
<th>
#Html.DisplayNameFor(model => model.County)
</th>
<th>
#Html.DisplayNameFor(model => model.RestaurantType)
</th>
<th></th>
</tr>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Rating)
</td>
<td>
#Html.DisplayFor(modelItem => item.RestaurantName)
</td>
<td>
#Html.DisplayFor(modelItem => item.County)
</td>
<td>
#Html.DisplayFor(modelItem => item.RestaurantType)
</td>
<td>
#Html.ActionLink("Edit", "Edit", new { id = item.RestaurantID }) |
#Html.ActionLink("Details", "Details", new { id = item.RestaurantID }) |
#Html.ActionLink("Delete", "Delete", new { id = item.RestaurantID })
</td>
</tr>
}
</table>
</div>
If you really don't want to change the logic for retrieving the list, you could use a ViewModel with a List property, returning the specified list using the Getter.
public List<Restaurant> MyRestaurants
{
get { return Restaurants.Where(x => x.RestaurantEmail == UserEmail); }
}

C# MVC4 table with multiple submit buttons - always sends the same data

I have a table inside my view that lists case details in each row. Every row has a submit button called "View Details". I have two hidden fields, TicketNumber and CaseId that are submitted when the user clicks the "View Details" button.
The problem is: it always sends the TicketNumber and CaseId of the first case in the table no matter which "View Details" button is pressed.
Here is the code of the view:
#model IEnumerable<Models.Case>
#{
ViewBag.Title = "AbandonedVehiclesLandingPage";
}
<h2>AbandonedVehiclesLandingPage</h2>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.TicketNumber)
</th>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
<th>
#Html.DisplayNameFor(model => model.Status)
</th>
<th>
#Html.DisplayNameFor(model => model.SubmittedOn)
</th>
<th></th>
</tr>
</table>
#using (Html.BeginForm("ViewCase", "Home",FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<table>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.TicketNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Status)
</td>
<td>
#Html.DisplayFor(modelItem => item.SubmittedOn)
</td>
<td>
<input type="hidden" value="#item.TicketNumber" name="TicketNumber" />
<input type="hidden" value="#item.CaseId" name="CaseId" />
<input type="submit" value="View Details" />
</td>
</tr>
}
</table>
}
Here is the receiving Action:
[HttpPost]
public ActionResult ViewCase(string TicketNumber, string CaseId)
{
string token = (string)Session["token"];
if(token!=null)
{
if (provider.ValidateUser(Session["token"].ToString(), ""))
{
CaseService service = new CaseService("");
CaseNote caseInfo = service.fetchSingleCase(TicketNumber, CaseId);
return View("ViewCase", caseInfo);
}
}
return Redirect(HttpContext.Application["connectUrl"].ToString()
+ HttpContext.Application["redirectUrl"].ToString());
}
Last thing to say, it worked up until the point I lost the original View code and had to re-write it again. It feels like something small I am missing here.
Change your table as follows:
<table>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.TicketNumber)
</td>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.Status)
</td>
<td>
#Html.DisplayFor(modelItem => item.SubmittedOn)
</td>
<td>
#using (Html.BeginForm("ViewCase", "Home",FormMethod.Post))
{
#Html.AntiForgeryToken()
<input type="hidden" value="#item.TicketNumber" name="TicketNumber" />
<input type="hidden" value="#item.CaseId" name="CaseId" />
<input type="submit" value="View Details" />
}
</td>
</tr>
}
</table>

Model Properties passing as nulls to Action

I am trying to pass an item with the type "EmployeeDocument" to my action but all of values are coming back as nulls and I am not sure why. I have tried passing the entire model as well as just pieces and they are all null and I am not sure why this is happening.
Here is what my view looks like:
<table id="results-table" class="table table-striped table-bordered table-condensed">
<thead>
<tr>
<th>
<u>#Html.DisplayName("Title")</u>
</th>
<th>
<u>#Html.DisplayName("Document Type")</u>
</th>
<th>
<u>#Html.DisplayName("Created By")</u>
</th>
<th>
<u>#Html.DisplayName("Created Date")</u>
</th>
<th style="width: 180px;"></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Title)
</td>
<td>
#Html.DisplayFor(modelItem => item.DocumentType)
</td>
<td>
#Html.DisplayFor(modelItem => item.CreatedBy)
</td>
<td>
#Html.DisplayFor(modelItem => item.CreatedDate)
</td>
<td>View | #Html.ActionLink("Replace", "ReplaceEmployeeDocument", "Employee",new {title = item.Title, doctype = item.DocumentType, createdDate = item.CreatedDate,createdBy = item.CreatedBy, fullUrl = item.FullUrl}) | #Html.ActionLink("Delete", "DeleteEmployeeDocument",new {fileName = item.FullUrl, employeeNo = item.EmployeeNumber})</td>
</tr>
}
</tbody>
</table>
I am focusing on the replace action link in the table.
This is what my action looks like:
[HttpGet]
public ActionResult ReplaceEmployeeDocument(string title, string doctype, DateTime createdDate, string createdBy, string fullUrl)
{
var doc = new EmployeeDocument();
return PartialView(doc);
}
All of the parameters in the action are null. Is there a reason why these are like that?
You are trying to post back a collection of objects, in order for this to work you need to use a for loop and index the properties with hidden inputs as follows:
#using (Html.BeginForm("ReplaceEmployeeDocument", "Controller"))
{
#for(var i = 0; i < Model.Count(); i++)
{
<tr>
<td>
#Html.HiddenFor(m => m[i].Title)
#Html.DisplayFor(m => m[i].Title)
</td>
<td>
#Html.HiddenFor(m => m[i].DocumentType)
#Html.DisplayFor(m => m[i].DocumentType)
</td>
<td>
#Html.HiddenFor(m => m[i].CreatedBy)
#Html.DisplayFor(m => m[i].CreatedBy)
</td>
<td>
#Html.HiddenFor(m => m[i].CreatedDate)
#Html.DisplayFor(m => m[i].CreatedDate)
</td>
<td>View | <input type="submit" value="Replace"/></td>
</tr>
}
}
You also need a corresponding post method that accepts the model being passed back:
[HttpPost]
public ActionResult ReplaceEmployeeDocument(EmployeeDocument model)
{
var doc = new EmployeeDocument();
return PartialView(doc);
}
You dont seem to be using any #Html.EditorFor which would generate input fields, and you dont have any form or javascript that would send your arguments in either GET or POST method. Therefore none of your fields are sent to the method in the controller. You should wrape the code inside the foreach in a
#Html.BeginForm() {}

Categories