Looping through array and assemble a string - c#

public ActionResult Create(RecurringTask recurringTask, FormCollection collection, ICollection<string> dayOfTheWeek)
I am trying to loop through the dayOfTheWeek (which is a group of checkboxes) and I am trying to find out which one is true so than I can use that to assemble a string ex:Monday, Tuesday, etc.
I am just having trouble finding a way of looping through my collection to do it. I keep getting can't apply == to of type string to bool error.
var days = dayOfTheWeek.ToString();
foreach (string day in dayOfTheWeek)
{
if(day == true)
{
}
}
recurringTask.DaysOfTheWeek = days;
This is what I am thinking on how to do it. But I imagine someone out there has a way better idea than I do. The day == true gives me that string to bool error and its obvious to why its happening, I just don't know how to get around it.
My view is this:
<input type="checkbox" name="dayOfTheWeek" value="Monday" />
<input type="checkbox" name="dayOfTheWeek" value="Tuesday" />
<input type="checkbox" name="dayOfTheWeek" value="Wednesday" />
<input type="checkbox" name="dayOfTheWeek" value="Thursday" />
<input type="checkbox" name="dayOfTheWeek" value="Friday" />
<input type="checkbox" name="dayOfTheWeek" value="Saturday" />
<input type="checkbox" name="dayOfTheWeek" value="Sunday" />

public ActionResult Create(RecurringTask recurringTask, FormCollection collection, ICollection dayOfTheWeek)
Sorry to say it but that's probably one of the worst action signatures I have ever seen. A mixture of a domain model, a FormCollection and some ICollection<string>.
Use view models, strongly typed views and editor templates (that's probably the 10^4th time I am writing this sentence on StackOverflow in response to questions in the asp.net-mvc tag)! They will make your life so much easier. So a list of days and a corresponding boolean property to indicate whether this day is selected:
public class MyViewModel
{
public IEnumerable<DayOfWeekViewModel> DaysOfWeek { get; set; }
... put any other properties that you consider useful for this view
}
public class DayOfWeekViewModel
{
public string DayOfWeek { get; set; }
public bool IsSelected { get; set; }
}
then a controller:
public class HomeController : Controller
{
public ActionResult Index()
{
var model = new MyViewModel
{
DaysOfWeek = CultureInfo
.CurrentCulture
.DateTimeFormat
.DayNames
.Select(x => new DayOfWeekViewModel
{
DayOfWeek = x,
})
};
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// model.DaysOfWeek will contain all you need here
// TODO: do some processing
// here you can loop through model.DaysOfWeek to identify which
// days have been selected and take respective actions
// ...
// once you have finished processing you could redirect
return RedirectToAction("success");
}
}
then a corresponding view:
#model MyViewModel
#using (Html.BeginForm())
{
... you could put any other fields from your view model that
will be used by this form here
#Html.EditorFor(x => x.DaysOfWeek)
<input type="submit" value="OK" />
}
and the corresponding editor template (~/Views/Home/EditorTemplates/DayOfWeekViewModel.cshtml):
#model DayOfWeekViewModel
<div>
#Html.CheckBoxFor(x => x.IsSelected) #Html.DisplayFor(x => x.DayOfWeek)
#Html.HiddenFor(x => x.DayOfWeek)
</div>

The error message is revealing. You are trying to compare a string day to true or false. What does it mean for a string to be true or false?
You really want to see if the checkboxes are checked. You claim that dayOfTheWeek is a group of CheckBoxes, but you are calling ToString() on it, which would convert it to a list of strings. What is the code before var days = dayOfTheWeek.ToString(); Where are you declaring dayOfTheWeek?
Once you really have a List<Checkbox>, you really want to iterate through that list to see if each element is checked.
foreach(CheckBox cb in dayOfTheWeek)
{
if(cb.Checked)
{
// Logic
}
}

If you named your checkboxes "dayOfTheWeek", ICollection<string> dayOfTheWeek only contains the selected checkboxes.
So you could just take this list as "result", but I would encourage you to filter the list of days with a list of valid values to prevent malicious attacks.

Related

what should be parameters of action method when there is foreach loop in your form in view mvc

I am working on a project "Online examination system". User can give MCQ test here.
Now in my database I have a table named "Question" which contains questions of every subject in the database. When the user selects a subject for an exam, the questions of that subject are stored in var a by where query. Now that var a is passed to return view.
Then in the Exam view, the name of every field is dynamic and differs by ID column in table which is auto increment primary key.
Every MCQ is submitted to Exam_Result() Action method for Checking that its right or wrong.
Now the confusion is in Exam_Result() Action method's parameters... say 20 questions are submitted to Exam_Result, andn how should I handle dynamic names in the parameter of Exam_Result() ?
Exam() Action method in home controller:
public ActionResult Exam(string sname)
{
ProjectDatabaseEntities7 obj = new ProjectDatabaseEntities7();
Question q = new Question();
try
{
var a = obj.Questions.Where(s=>s.Subject_Name.Equals(sname));
return View(a);
}
catch
{
}
return View();
}
Exam.cshtml View:
<form action="/User/Exam_Result">
#foreach (var s in Model)
{
<div class="col-md-12 well form-group">
<label>#s.Question1</label><br>
<input type="text" name="question{#s.Id}" value="#s.Question1" hidden/>
<input type="radio" name="option{#s.Id}">#s.Option1<br />
<input type="radio" name="option{#s.Id}">#s.Option2<br />
<input type="radio" name="option{#s.Id}">#s.Option3<br />
<input type="radio" name="option{#s.Id}">#s.Option4<br />
</div>
}
<input type="submit" value="Submit" class="btn btn-success btn-group-justified" />
</form>
Exam_result() Action Method where the form above is submitting:
public ActionResult Exam_Result(string question, string option)
{
ProjectDatabaseEntities7 obj = new ProjectDatabaseEntities7();
Question q = new Question();
try
{
q = obj.Questions.First(x=> x.Question1.Equals(question));
if(q!=null)
{
if (q.Answer == option)
ViewBag.ans = "right ans";
else
ViewBag.ans = "wrong ans";
}
}
catch
{
return View();
}
return View();
}
Database table Question:
Exam_Result can accept your model as a parameter, allowing it to accept anything that your model defines. When you call into your exam function, and you give it your model, you're giving it all of the properties that it needs at once.
public ActionResult Exam_Result(YourModelClass model)
In your model, you'll just have a property that contains a list of the property that you need N of.
public class YourModelClass
{
public int ExamId {get; set;}
public List<Type> ListName { get; set; }
}
You can access the list as it is a property of the model in your view:
#foreach(var listItem in model.ListName)
{
#listItem
}
To send this information back to the view, you can just return it explicity:
return View("ViewName", model);
Since you're using Razor, all you need to do to define the model in your view is add this to the top of the page:
#model Your.Namespace.YourModelClass
For your comment about having different names and values:
public class YourCustomType
{
public string Name {get; set;}
public var WhateverElse { get; set; }
}
#foreach(YourCustomType item in model.YourList)
{
//item.Name
//item.WhateverElse
}
You model binding is wrong.
First of all don't use entity objects in View page, instead create a custom View model and map entity objects and bind it to view page.
You form <form action="/User/Exam_Result"> submits a list of Model (question) but your action only accepts one question (question/option parameters) which is wrong. You should change Exam_Result action parameter to accept a list of questions

List is NULL while POST from View

I use the below Action to allow the user to see a preview of Excel import
[HttpGet]
[Authorize]
public ActionResult ImportVerify()
{
string temp_sessionname = "ImportedData_" + User.Identity.Name;
List<ProjectImportModel> view_model = (List<ProjectImportModel>)TempData[temp_sessionname];
return View(view_model);
}
[HttpPost]
[Authorize]
public ActionResult ImportVerify(List<ProjectImportModel> model)
{
return View(model);
}
And on View i am using a table to show the List of imported data from excel and ask user to confirm the action of import
My view is like this
<h2>Import Verify</h2>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
//table with all details and a submit button in the end
<div class="form-group">
<div class="col-md-10" style="text-align:center;">
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
</div>
}
And model is
public class ProjectImportModel
{
public string Page { get; set; }
public string Author { get; set; }
public string Translator { get; set; }
public string Holder { get; set; }
public string Title { get; set; }
public string TrTitle { get; set; }
//and similar 20 more properties of string type
}
But on POST the list is null
Is any way to get the list back at POST event. My intension is just to allow the preview to user
Or do i need to refill List from TempData # post as well?
In order to post a collection back you need to index the properties, if they're readonly you can just use HiddenFor with a model.
If you want the user to edit them, change them to TextBoxFor's instead or the control that you data requires.
#model List<ProjectImportModel>
<h2>Import Verify</h2>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
//table with all details and a submit button in the end
<div class="form-group">
<div class="col-md-10" style="text-align:center;">
#for(var i = 0 ; i < Model.Count; i++)
{
#Html.HiddenFor(m => m[i].Foo)
#Model[i].Foo <br/>
}
<input type="submit" value="Submit" class="btn btn-primary" />
</div>
</div>
}
I just used a dummy property of Foo without seeing your model.
Obviously you would want to display the data too.
Model Binding To A List
I don't see the snippet code that set your TempData. So I intend that you set it in another Action and then redirect to the ImportVerify Action
TempData keep the information for the time of an HTTP Request. This mean only from one page to another. It's mean that after redirect to your ImportVerify Get Action the data is expired. If you want to keep the data you can try the following ways:
Create a hidden List in your page
Use Session instead of TempData
There are some requirements to post a list back to a controller. Specifically, indexes must be 0-based and unbroken (example, you can bind a list with indexes [0], [1], [2] but not one with [0], [1], [3] or [1], [2], [3].
Alternatively, you could write a custom model binder to parse the request body the way you like.
More on this here: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/
EDIT:
Here is an example on how to do it:
Given the following model
public class ExampleModel
{
public int Field1 {get; set;}
public string Field2 {get; set;}
}
And the following actions
[HttpGet]
[Authorize]
public ActionResult ImportVerify()
{
List<ExampleModel> model = //populate the list somehow
return View(model);
}
[HttpPost]
[Authorize]
public ActionResult ImportVerify(List<ExampleModel> model)
{
//do something
}
The example view "ImportVerify.cshtml" would be:
#model List<ExampleModel>
#using(Html.BeginForm())
{
for(var i = 0; i < Model.Count; i++)
{
<div>
#Html.HiddenFor(m => m[i].Field1);
#Html.HiddenFor(m => m[i].Field2);
<p>
Value #i : Field1 = #m[i].Field1 , Field2 = #m[i].Field2
</p>
</div>
}
<input type="submit" value="Send"/>
}
Also, I would revise your logic a bit, to avoid the use of TempData (generally bad practice) and to allow strongly typed views.

ModelView data not passed from View to Controller

My problem is that strongly typed data passed from my Controller to my view comes out empty (all it's properties are null).
I would also like to bind selected value in radiobuttons (marked as QUESTION2) to model property "GivenAnwser" but it doesn't seem to work either.
Type passed around is a ViewModel
public class HomeController : Controller
{
[HttpGet]
public ActionResult Index()
{
QuestionViewModel question = Manager.GetQuestion();
return View(question);
}
[HttpPost]
public ActionResult Index(QuestionViewModel question,Anwser givenAnwser)
{
//QuestionViewModel is returned but all it's properties are null.
return View(question);
}
}
VIEW
#model Quiz.ViewModels.QuestionViewModel
#{
ViewBag.Title = "Home Page";
}
#Html.Label("Question:")
#if (Model.CorrectAnwser != null)
{
//some code
}
#Html.DisplayFor(model => model.Question.Text)
//I have tried with Hidden fields and without them
#Html.HiddenFor(model => model.Question)
#Html.HiddenFor(model => model.Anwsers)
#using (Html.BeginForm("Index", "Home"))
{
foreach (var anwser in Model.Anwsers)
{
//QUESTION 2
<input type="radio" name="givenAnwser" value="#anwser" />
<label>#anwser.Text</label>
<br />
}
<input type="submit" value="Check!" />
}
QuestionViewModel
public class QuestionViewModel
{
public QuestionViewModel()
{
this.Anwsers = new List<Anwser>();
}
public Question Question { get; set; }
public List<Anwser> Anwsers { get; set; }
public Anwser GivenAnwser { get; set; }
public bool CorrectAnwser { get; set; }
}
EDIT:
ModelState contains an error:
"The parameter conversion from type 'System.String' to type 'Quiz.Models.Anwser' failed because no type converter can convert between these types."
<input type="radio" name="givenAnwser" value="#anwser" />
this line is setting a complex type "#answer" as the value of the radio button.
this might just do a ToString() of the type during rendering.
When you post it back, MVC might be trying to convert this string value back to
Quiz.Models.Anwser
and failing.
you should probably render
<input type="radio" name="givenAnwser" value="#anwser.SomeBooleanValue" />
p.s. also, why not use the Html Extension to render the radio button.
You can't bind a complex type (Question) to a Hidden field. You would need to bind to the separate child properties.
Also, for the answers, don't use a foreach, use a for loop. Like:
#for(var i=0;i<Answers.Count;i++)
{
<input type="radio" name="#Html.NameFor(a=>a.Answers[i].answer.Value)" value="#Model.Answers[i].anwser.Value" />
}
or
#for(var i=0;i<Answers.Count;i++)
{
#Html.RadioButtonFor(a=>a.Answers[i].answer,Model.Answers[i].answer.Value)
}
Although, that may not be correct either because Answers is a collection of a complex type as well, and you didn't share it's definition.
All in all, I don't think you really need (or want) to post back the entire Model back anyhow. Why not just post back the question ID, and the selected Answer?

Obtaining values for Dynamic checkboxes

I'm pretty new at web development. So, sorry if this I'm asking dumb questions. I'm building a list of checkboxes based on available filter criteria pulled from a database. The model i pass to my view has a property
public List<string> ServicesList{ get; set; }
My view code contains a loop to create a checkbox for each item in the list.
#foreach (string svc in Model.ServicesList)
{
if (svc != "")
{
<input type="checkbox" name="SelectedServices" title="#svc" value="#svc" checked="checked" /> #svc
<br />
}
}
My Controller Action looks like this:
public ActionResult ServiceListExplorer(string[] SelectedServices, FormCollection fc)
{
}
This works as far as displaying the list of services as checkboxes and having access inside the controller action to which ones are checked by the user once the httppost occurs. But, I have 2 questions:
How can I pass which items should be checked initially via the Model? This would allow me to save off their filter criteria and pre-select the services. I was thinking maybe I need to use a SelectList instead of List but not really sure how.
How can I make the "checked" attribute dynamic by binding it to a value in the model?
Instead of creating a list of string objects, you should define a class for e.g.
public class ServiceObject
{
public string Name{get;set;}
public bool IsChecked{get;set;}
}
then your code will become-
public List<ServiceObject> ServicesList{ get; set; }
what you have to fill is the IsChecked property to true if your checkbox is to be selected:
then this line will become-
<input type="checkbox" name="SelectedServices" title="#svc" value="#svc" checked=Model.IsChecked />
First of all instead of ServicesList should be list of objects not list of string :
public class Service
{
public string ServiceName {get; set;}
public bool isChecked {get;set;}
}
....
public List<Service> ServicesList{ get; set; }
....
//that controller will collect data posted from view
//(your form will post only checked checkboxes)
[HttpPost]
public JsonResult Update(FormCollection services)
{
foreach (string item in services)
{
System.Diagnostics.Debug.WriteLine(item);
}
return Json(services);
}
not in your view :
#using (Html.BeginForm("Update", "Home", FormMethod.Post)) {
foreach (MvcMusicStore.Models.Service svc in Model)
{
#svc.ServiceName #Html.CheckBox(svc.ServiceName, svc.isChecked);
<br/>
}
<input type="submit" value="submit"/>
}

asp net MVC3 submit List of object is null when post back

I use asp net MVC 3 one of my project.I use partial view for my coding. I want to list all customers in a list and submit their information as a list. When I try to submit my list in post back, it sends my list is null. You can find my code as in the below:
My controller method is:
[HttpPost]
public ActionResult ConfirmUsers(ICollection<Career.DomainModel.UserApprovalDto> collection)
{
string bas = "";
//if (collection != null)
if (ModelState.IsValid)
{
bas = "bas";
}
return RedirectToAction("Index");
}
My partial view is:
#model List<Career.DomainModel.UserApprovalDto>
#using (Html.BeginForm("ConfirmUsers", "ManageUsers", new { area = "" }, FormMethod.Post))
{
<table>
<tr>
<th>
Name
</th>
<th>
Is Reported
</th>
</tr>
#for (int i = 0; i < Model.Count(); i++)
{
<tr>
<td>
#Html.DisplayFor(modelItem => Model[i].FirstName)
</td>
<td>
#Html.CheckBox("IsReported", Model[i].IsReported.HasValue ? Model[i].IsReported.Value : false)
#*#Html.CheckBoxFor(modelItem => Model[i].IsReported.Value);*# #* #if (Model[i].IsReported != null)
{
#Html.CheckBoxFor(modelItem => Model[i].IsReported.Value);
}
else
{
#Html.CheckBoxFor(modelItem => Model[i].IsReported.Value);
}*#
</td>
<td>
</td>
</tr>
}
</table>
<div>
<input name="submitUsers" type="submit" value="Save" />
</div>
}
Thanks in advance.
Kerem
I would use Editor template to handle this. Have your View Model like this to represent the CheckBox item.
public class ReportedUserViewModel
{
public string FirstName { set;get;}
public int Id { set;get;}
public bool IsSelected { set;get;}
}
Now in yout main view model, add a property which is a collection of the above class
public class ConfirmUserViewModel
{
public List<ReportedUserViewModel> ReportedUsers{ get; set; }
//Other Properties also here
public ConfirmUserViewModel()
{
ReportedUsers=new List<ReportedUserViewModel>();
}
}
Now in your GET Action, you will fill the values of the ViewModel and sent it to the view.
public ActionResult ConfirmUser()
{
var vm = new ConfirmUserViewModel();
//The below code is hardcoded for demo. you mat replace with DB data.
vm.ReportedUsers.Add(new ReportedUserViewModel { Name = "Test1" , Id=1});
vm.ReportedUsers.Add(new ReportedUserViewModel { Name = "Test2", Id=2 });
return View(vm);
}
Now Let's create an EditorTemplate. Go to Views/YourControllerName and Crete a Folder called EditorTemplate and Create a new View there with the same name as of the Property Name(ReportedUsers.cshtml)
Add this code to the newly created editor template.
#model ReportedUserViewModel
<p>
<b>#Model.FirstName </b> :
#Html.CheckBoxFor(x => x.IsSelected) <br />
#Html.HiddenFor(x=>x.Id)
</p>
Now in your Main View, Call your Editor template using the EditorFor Html Helper method.
#model ConfirmUserViewModel
#using (Html.BeginForm())
{
<div>
#Html.EditorFor(m=>m.ReportedUsers)
</div>
<input type="submit" value="Submit" />
}
Now when You Post the Form, Your Model will have the ReportedUsers Collection where the Selected Check boxes will be having a True value for the IsSelected Property.
[HttpPost]
public ActionResult AddAlert(ConfirmUserViewModel model)
{
if(ModelState.IsValid)
{
//Check for model.ReportedUsers collection and Each items
// IsSelected property value.
//Save and Redirect(PRG pattern)
}
return View(model);
}
With the code you wrote, MVC model binder mechanism does not know how to map those inputs into List of object.
Do this little trick instead:
#Html.CheckBox("[" + i + "]." + "IsReported", Model[i].IsReported.Value);
This will result the name of input field as [0].IsReported for the first item in the list, [1].IsReported for next item.
That should work.
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
I'm a little late to the party, but it is easy enough to just refer to the list if you embed it in the model--
#Html.CheckBoxFor(modelItem => Model.List[i].Selected)
That will post back for each item in the iterator.
#Html.CheckBox("[" + i + "]." + "IsReported", Model[i].IsReported.Value);
worked perfectly for me.
Make sure your post method contains parameter for the list.
e.g public ActionResult Index(ConfigViewModel model, List configurationList)
Here in my case I have one view model (model) which contains list object.
If you specify view model in your post method as it is then you will get null value for the list (here model object is null). But if you add specific list parameter (configurationList) in the action then you can get all of the list values in the controller.
i run into same problem last week.
I realize that checkbox has three value(true/false/null) when i get it from database because i let the checkbox value nullable when i desingned database. i redesinged db and the problem was solved.
you didnt post models so i dont realy sure if this is the case. just look at the model, if it's writing Nullable above your Ischeck property, go to database and redesign. remember isCheck, isSelected properties have to have just two values(true/false).

Categories