MVC3 #Html.RadioButtonfor Pass data from view to controller - asp.net-mvc-3

Basically what I am trying is to create a feedback form with a question which has four answers (Radio Button) using MVC.
In View: I am able to get questions and answers in view with radiobutton to each answer.
In Controller: I am confused here.
I would like to send selected question & there answers from View to controller.
My view :
#model IEnumerable SQLOperation.Models.QuestionClass.Tabelfields
#{int i = 0;}
#foreach (var item in Model)
{
using (Html.BeginForm("Question", "home", new {email=item.Email}))
{
#Html.DisplayFor(modelItem => item.QuestionName,item)
<br /><br />
if (item.Option1 != "")
{
#Html.RadioButtonFor(modelItem =>item.SelectedOption, item.Option1, item)
#Html.DisplayFor(modelItem => item.Option1)
<br /><br />
}
if (item.Option2 != "")
{
#Html.RadioButtonFor(modelItem => item.SelectedOption, item.Option2)
#Html.DisplayFor(modelItem => item.Option2)
<br /><br />
}
if (item.Option3 != "")
{
#Html.RadioButtonFor(modelItem =>item.SelectedOption, item.Option3)
#Html.DisplayFor(modelItem => item.Option3)
<br /><br />
}
if (item.Option4 != "")
{
#Html.RadioButtonFor(modelItem =>item.SelectedOption, item.Option4)
#Html.DisplayFor(modelItem => item.Option4)
<br /><br />
}
i = (Int16)i + 1;
if (Model.Count() == i)
{
<input name="btnsumbit" type="submit" value="Submit Feedback"
style="font-family:Segoe UI Light;font-size:medium;"/>
}
}
}
My Controller :
[HttpGet]
public ActionResult Question(string email)
{
var tf = new QuestionClass.Tabelfields();
IList<QuestionClass.Tabelfields> viewmodel = new List<QuestionClass.Tabelfields>();
var q = QuestionClass.getallQuestion(email).ToList();
foreach (SQLOperation.Models.Question item in q)
{
QuestionClass.Tabelfields viewItem = new QuestionClass.Tabelfields();
viewItem.Email = item.Email;
viewItem.QuestionID = item.QuestionID;
viewItem.QuestionName = item.QuestionName;
viewItem.Option1 = item.Option1;
viewItem.Option2 = item.Option2;
viewItem.Option3 = item.Option3;
viewItem.Option4 = item.Option4;
viewmodel.Add(viewItem);
}
return View(viewmodel);
}
[HttpPost, ActionName("Question")]
public void Question(string Email,QuestionClass.Tabelfields tf)
{
}
My Model:
public class QuestionClass
{
public static FeedbackDatabaseDataContext context = new FeedbackDatabaseDataContext();
public class Tabelfields : Question
{
//public decimal QuestionID { get; set; }
//public string Email { get; set; }
//public string QuestionName { get; set; }
//public string Option1 { get; set; }
//public string Option2 { get; set; }
//public string Option3 { get; set; }
//public string Option4 { get; set; }
public int SelectedOption { get; set; }
}
public static List<Question> getallQuestion(string email)
{
var list = (from q in context.Questions where q.Email == #email select q);
return list.ToList();
}
}
I didn't get the question and it's selected option with appropriate Email in controller.
How can I get it in controller?

To, start with include a breakpoint in your view and check if the values are being passed or not.
Next, change your method signature from
public void Question(string Email,QuestionClass.Tabelfields tf)
to
public void Question(string email, QuestionClass.Tabelfields tf)
Also, I see you have used some strange syntax ( considering m also new to MVC ) where you could have simply used this
#Html.DisplayFor(modelItem => item.QuestionName)
instead of this
#Html.DisplayFor(modelItem => item.QuestionName,item)
and also, I have seen you profile, I know you are new to StackOverflow, so Welcome to StackOverflow ! you might want to read this & this as well. Cheers !
Update :
You are using this for displaying a radio button...
#Html.RadioButtonFor(modelItem =>item.SelectedOption, item.Option1, item)
what is item.Option1, I can see you have commented out Opion1,2,3,4. Or are you still using them ?
A very simple way of implementing this would be something like this
#Html.RadioButtonFor(modelItem =>item.SelectedOption, "Option1")
#Html.RadioButtonFor(modelItem =>item.SelectedOption, "Option2")
#Html.RadioButtonFor(modelItem =>item.SelectedOption, "Option3")
or you can also use,
#Html.RadioButtonFor(modelItem =>item.SelectedOption, item.Option1)
#Html.RadioButtonFor(modelItem =>item.SelectedOption, item.Option2)
#Html.RadioButtonFor(modelItem =>item.SelectedOption, item.Option3)
provided values exist in item.Option1/2/3/4 and are all of them are different.

Related

Adding items to list in model dynamically via ajax

I have the following code and I am trying to add the selected value to the model.SelectedPayCodes list everytime the user makes a selection from the dropdown and clicks on "Add"
CONTROLLER
[HttpPost]
public PartialViewResult AddPayCode(ReferralModel model, string SelectedPayCode)
{
var payCode = _employeeService.GetPayCodeById(Convert.ToInt32(SelectedPayCode));
model.Add(payCode);
return PartialView("_PayCodesPartial",model);
}
MODEL
public class ReferralModel
{
public Customer Customer { get; set; }
public Employee Employee { get; set; }
public List<PayCode> PayCodes { get; set; } // List of paycodes
public List<PayCode> PayCodesList { get; set; } // List of 'selected' paycodes
public SelectListItem SelectedPayCode { get; set; } // current selected paycode
public Referral Referral { get; set; }
public ReferralModel()
{
PayCodesList = new List<PayCode>();
}
// Step 3 - Add Paycode is done here.
public void Add(PayCode payCode)
{
PayCodesList.Add(payCode);
}
}
VIEW - Create.cshtml
#using (Ajax.BeginForm("AddPayCode", "Referral",
new AjaxOptions()
{
HttpMethod = "POST",
InsertionMode = InsertionMode.InsertAfter,
UpdateTargetId = "PayCodes",
}))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<!-- payCodes input-->
<div class="control-group col-lg-6">
<label class="control-label">Product</label>
<div class="controls">
<!-- Step 1 + Choose PayCode Here -->
#Html.DropDownListFor(model => model.SelectedPayCode, new SelectList(Model.PayCodes.ToList(), "Id", "Description"), "- Select -")
<input type="submit" value="Add" />
</div>
</div>
<!-- pay codes list -->
<div id="PayCodes">
</div>
}
VIEW - _PayCodesPartial.cshtml
#model Zenwire.Models.ReferralModel
#if (Model.PayCodesList != null)
{
foreach (var item in Model.PayCodesList)
{
string.Format("{0} - {1}", item.Code, item.Description);
}
}
The issue seems to be whenever a new item is added the list is empty again and does not retain it's previous selection.
Try this. I used Session State
public PartialViewResult AddPayCode(ReferralModel model, string SelectedPayCode)
{
var payCode = _employeeService.GetPayCodeById(Convert.ToInt32(SelectedPayCode));
model.PayCodesList = GetPayCodes();
model.Add(payCode);
Session["paycodes"] = model.PayCodesList;
return PartialView("_PayCodesPartial",model);
}
private List<PayCode> GetPayCodes()
{
List<PayCode> payCodes = (List<PayCode>)Session["paycodes"];
if (payCodes == null )
{
payCodes = new List<PayCode>();
Session["paycodes"] = paycode;
}
return payCodes;
}

MVC3 #html.radiobuttonfor

Here is my class :
public class QuestionClass
{
public static FeedbackDatabaseDataContext context = new FeedbackDatabaseDataContext();
public class Tabelfields : Question
{
//public int QuestionID { get; set; }
//public string Email { get; set; }
//public string QuestionName { get; set; }
//public string Option1 { get; set; }
//public string Option2 { get; set; }
//public string Option3 { get; set; }
//public string Option4 { get; set; }
public string SelectedOption { get; set; }
}
public static List<Question> getallQuestion(string email)
{
var list = (from q in context.Questions where q.Email==#email select q).ToList();
return list.ToList();
}
}
My view :
#model IEnumerable SQLOperation.Models.QuestionClass.Tabelfields
<p> Question</p>
#foreach (var item in Model)
{
using (Html.BeginForm("Question", "home", new {email=item.Email,item}))
{
#Html.DisplayFor(modelItem => item.QuestionName)
<br /><br />
if (item.Option1 != "")
{
#Html.RadioButtonFor(modelItem =>item.SelectedOption, item.Option1, item)
#Html.DisplayFor(modelItem => item.Option1)
<br /><br />
}
if (item.Option2 != "")
{
#Html.RadioButtonFor(modelItem => item.SelectedOption, item.Option2)
#Html.DisplayFor(modelItem => item.Option2)
<br /><br />
}
if (item.Option3 != "")
{
#Html.RadioButtonFor(modelItem =>item.SelectedOption, item.Option3)
#Html.DisplayFor(modelItem => item.Option3)
<br /><br />
}
if (item.Option4 != "")
{
#Html.RadioButtonFor(modelItem =>item.SelectedOption, item.Option4)
#Html.DisplayFor(modelItem => item.Option4)
<br /><br />
}
i = (Int16)i + 1;
if (Model.Count() == i)
{
<input name="btnsumbit" type="submit" value="Submit Feedback"
style="font-family:Segoe UI Light;font-size:medium;"/>
}
}
}
Here Is my controller
public ActionResult Question(string email)
{
return View(QuestionClass.getallQuestion(email));
}
[HttpPost, ActionName("Question")]
public void Question(string Email,List<QuestionClass.Tabelfields> q)
{
}
In class i.e. "Tabelfields" I create new property i.e. SelectedOption. I inherite the base class i.e. Question. Where Question is a table in Sql server Database.
I create strongely type view by using this
#model IEnumerable SQLOperation.Models.Question
If I change strongely type view as
#model IEnumerable SQLOperation.Models.QuestionClass.Tabelfields
I get this error
"The model item passed into the dictionary is of type 'System.Collections.Generic.List1[SQLOperation.Models.Question]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable1[SQLOperation.Models.QuestionClass+Tabelfields]'."
Why should I get this error and how can I solve this ?
Thank you,
ajay
You need to change:
#model IEnumerable SQLOperation.Models.QuestionClass.Tabelfields
to this:
#model List<SQLOperation.Models.Question>
That should fix the error.
Hope it helps.
Change your getallQuestion in model to this
public static IEnumerable<Question> getallQuestion(string email)
{
var list = (from q in context.Questions where q.Email==#email select q).ToList();
return list.AsEnumerable(); //just remove `ToList()` and place `AsEnumerable()`.
}
Try this. This should work for you.

Model Binding a List MVC3 not reading vaules

I have read some posts, but I still find it difficult to solve this. My problem is that my action only reads some of the values from the binded list. This is how I send the list to the view:
public ActionResult RegisterSurvey()
{
RegisterSurveyModel model = new RegisterSurveyModel();
var questions = new List<QuestionModel>();
var survey = EFSurvey.Survey.FirstOrDefault();
survey.QuestionSurvey
.Where(x => x.AuditingDeleted == false)
.Where(x => x.Active == true).ToList().ForEach((item) =>
{
var questionModel = new QuestionModel();
ModelCopier.CopyModel(item, questionModel);
questionModel.Answer = string.Empty;
questions.Add(questionModel);
});
model.Questions = questions;
return View(model);
}
This is my model:
public class RegisterSurveyModel
{
public List<QuestionModel> Questions { get; set; }
}
public class QuestionModel
{
public int QuestionSurveyID { get; set; }
public string Question { get; set; }
public string Answer { get; set; }
public bool Suggestion { get; set; }
}
This is my view:
<div class="SiteSurveyContainer">
#using (Html.BeginForm())
{
<div class="SurveyUp">
#for (int i = 0; i < Model.Questions.Count(); i++)
{
if (!Model.Questions[i].Suggestion)
{
<p>#Model.Questions[i].Question</p>
#Html.HiddenFor(x => Model.Questions[i].QuestionSurveyID);
#Html.TextBoxFor(x => Model.Questions[i].Answer, new { #class = "surveyBox" });
}
}
</div>
<div class="SurveyBottom">
<div class="line">
</div>
<p>
Suggestions</p>
#for (int i = 0; i < Model.Questions.Where(x => x.Suggestion == true).Count(); i++)
{
#Html.HiddenFor(x => Model.Questions[i].QuestionSurveyID);
#Html.TextAreaFor(x => Model.Questions[i].Answer, new { #class = "surveyTextArea" })
}
</div>
<div class="surveyBottomButton">
<input type="submit" value="Submit Results" />
</div>
}
So far so good. Anyway, when I answer all of the survey questions, I only get the first 4 answers... Weird. Anyone knows why is that happening?
You have multiple input controls with within the same form with the same name.
Suggested questions are a sub set of all questions, so they are being repeated twice on the same form. That will throw off the ModelBinder, so your receiving action is probably only seeing the questions that have not been repeated.

how to get label value in mvc 3?

In Model:
public class DataViewModel
{
public IList<RowsCollection> Rows { get; set; }
public PaiementMethod PaiementMethod { get; set; }
}
public class RowsCollection
{
public string ID { get; set; }
public string Question { get; set; }
}
public enum PaiementMethod
{
Cash,
CreditCard,
}
In the Controller - Index ActionResult I have return my Model and render its into view page something like :
#model WebNexpo.Controllers.DataViewModel
#using (Html.BeginForm("Save", "page", FormMethod.Post, new { id = "saves"}))
{
foreach (var item in Model.Rows)
{
#Html.Label(item.Question)
<label for="paiement_cash">
Cash</label>
#Html.RadioButtonFor(m => m.PaiementMethod, "Cash", new { name = "paiement_cash" + #item.ID + "", id = "radioID" + #item.ID + "", Group = "Group" + #item.ID + "" })
<label for="paiement_cc">
Credit card</label>
#Html.RadioButtonFor(m => m.PaiementMethod, "CreditCard", new { name = "paiement_cc" + #item.ID + "", id = "radioname" + #item.ID + "", Group = "Group" + #item.ID + "" })
}
<input id="Saveser" type="submit" value="" class="button1" />
}
in submit form Action Event :
[HttpPost]
public ActionResult Save(DataViewModel model)
{
if (ModelState.IsValid)
{
//want to read all the label which selected rediobutton.
means suppose 4 question render on page and user have selected only 2
question of the answer.so How can accomplish here?
}
return RedirectToAction("Index", new {value = "123"});
}
There's some inconsistency here. You are rendering 2 radio buttons for each row so you probably want to reorganize your view model into:
public class DataViewModel
{
public IList<RowsCollection> Rows { get; set; }
}
public class RowsCollection
{
public string ID { get; set; }
public string Question { get; set; }
public PaiementMethod PaiementMethod { get; set; }
}
and then:
#model DataViewModel
#using (Html.BeginForm("Save", "page", FormMethod.Post, new { id = "saves"}))
{
for (var i = 0; i < Model.Rows.Count; i++)
{
<div>
#Html.HiddenFor(x => x.Rows[i].ID)
#Html.LabelFor(x => x.Rows[i].Question)
#Html.EditorFor(x => x.Rows[i].Question)
#Html.Label("payment_cash" + i, "Cash")
#Html.RadioButtonFor(m => m.Rows[i].PaiementMethod, "Cash", new { id = "payment_cash" + i })
#Html.Label("payment_cc" + i, "Credit card")
#Html.RadioButtonFor(m => m.Rows[i].PaiementMethod, "CreditCard", new { id = "payment_cc" + i })
</div>
}
<input id="Saveser" type="submit" value="" class="button1" />
}
and finally:
[HttpPost]
public ActionResult Save(DataViewModel model)
{
if (ModelState.IsValid)
{
// model.Rows[0].PaiementMethod will contain the selected payment method for the first question
// model.Rows[1].PaiementMethod will contain the selected payment method for the second question
// ...
}
return RedirectToAction("Index", new { value = "123" });
}
or if you want a single payment method you could keep your view model as is but then leave the radio buttons outside of the loop in your view. Like that:
#using (Html.BeginForm("Save", "page", FormMethod.Post, new { id = "saves" }))
{
for (var i = 0; i < Model.Rows.Count; i++)
{
<div>
#Html.HiddenFor(x => x.Rows[i].ID)
#Html.LabelFor(x => x.Rows[i].Question)
#Html.EditorFor(x => x.Rows[i].Question)
</div>
}
#Html.Label("payment_cash", "Cash")
#Html.RadioButtonFor(x => x.PaiementMethod, "Cash", new { id = "payment_cash" })
#Html.Label("payment_cc", "Credit card")
#Html.RadioButtonFor(x => x.PaiementMethod, "CreditCard", new { id = "payment_cc" })
<input id="Saveser" type="submit" value="" class="button1" />
}

Custom Validation MVC 3 with Entity Data Model

I'm working on a project using MVC3. I've first created a database (with the necessary constraints like PK and FK's) and added this database to my webapplicatie using the ADO.NET Entity Data Model. Everything seems to work fine but I can't make validation flexible. Here some code to clarify my question.
Edit: Added the View + correct models. This version is without importing a database but results the same.
--Models----
namespace CustomValidation.Models
{
public class Person : IValidatableObject
{
public int Id { get; set; }
[Required]
public String FirstName { get; set; }
[Required]
public String LastName { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (String.IsNullOrEmpty(FirstName))
{
var field = new[] { "FirstName" };
yield return new ValidationResult("Firstname can't be null", field);
}
}
}
}
namespace CustomValidation.Models
{
public class Address : IValidatableObject
{
public int Id { get; set; }
[Required]
public String Streetname { get; set; }
[Required]
public String Zipcode { get; set; }
[Required]
public String City { get; set; }
[Required]
public String Country { get; set; }
public Person Person { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (String.IsNullOrEmpty(Streetname))
{
var field = new[] { "Streetname" };
yield return new ValidationResult("Streetname can't be null", field);
}
}
}
}
public class MasterModel
{
public List<Address> Addressess { get; set; }
public Person Person { get; set; }
}
}
namespace CustomValidation.Models
{
public class DBEntities : DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Address> Addressess { get; set; }
}
}
----Controller----
namespace CustomValidation.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
MasterModel Model = new MasterModel();
Model.Person = new Person();
Model.Addressess = new List<Address>();
Model.Addressess.Add(new Address());
Model.Addressess.Add(new Address());
return View(Model);
}
[HttpPost]
public ActionResult Index(MasterModel Model)
{
DBEntities _db = new DBEntities();
if (TryValidateModel(Model.Person))
{
_db.People.Add(Model.Person);
_db.SaveChanges();
}
else
{
return View(Model);
}
for (int i = 0; i < Model.Addressess.Count; i++)
{
if (!String.IsNullOrEmpty(Model.Addressess[i].Country))
{
if (TryValidateModel(Model.Addressess[i]))
{
Model.Addressess[i].Person = Model.Person;
_db.Addressess.Add(Model.Addressess[i]);
_db.SaveChanges();
}
else
{
return View(Model);
}
}
}
return RedirectToAction("Index");
}
}
Here is my View:
#model CustomValidation.Models.MasterModel
#{
ViewBag.Title = "Index";
}
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Person</legend>
<div class="editor-label">
#Html.LabelFor(m => Model.Person.FirstName)
#Html.EditorFor(m => Model.Person.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(m => Model.Person.LastName)
#Html.EditorFor(m => Model.Person.LastName)
</div>
</fieldset>
for (int i = 0; i < Model.Addressess.Count; i++)
{
<fieldset>
<legend>Address</legend>
<div class="editor-label">
#Html.LabelFor(model => Model.Addressess[i].Streetname)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Addressess[i].Streetname)
#Html.ValidationMessageFor(model => Model.Addressess[i].Streetname)
</div>
<div class="editor-label">
#Html.LabelFor(model => Model.Addressess[i].Zipcode)
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.Addressess[i].Zipcode)
#Html.ValidationMessageFor(model => Model.Addressess[i].Zipcode)
</div>
<div class="editor-label">
#Html.LabelFor(model => Model.Addressess[i].City)
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.Addressess[i].City)
#Html.ValidationMessageFor(model => Model.Addressess[i].City)
</div>
<div class="editor-label">
#Html.LabelFor(model => Model.Addressess[i].Country)
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.Addressess[i].Country)
#Html.ValidationMessageFor(model => Model.Addressess[i].Country)
</div>
</fieldset>
}
<p>
<input type="submit" value="Create" />
</p>
}
The problem (that I've noticed while debugging something like this) is that before the request gets inside of my action MVC first runs validators for your collection. So if I've only filled out Person in my form, while validating Model.Person it just return false (i guess because of the Required fields for Address) and so it will bounce back to my View.
I need to have some workaround that lets me decided which instances of my collection I want to validate in my action.
I've not been able to find any solution after a lot of time searching on the net.
I hope that someone can help me out.
PS. I'm quite a newbie with Visual Studio and MVC 3 so please don't be to hard on me :)
In order to validate sub-models of the model returned to your action, you need to apply TryValidateModel to the specific sub-model, and use the overload which includes the prefix for the model. If you look at your generated HTML, you will see that the Person fields have Person as a prefix, the first Address fields have Addressess[0] as the prefix, and the second Address fields have Addressess[1] as the prefix.
In addition, you must clear all model errors before invoking TryValidateModel (or the existing errors will cause TryValidateModel to return false).
Do the following:
[HttpPost]
public ActionResult Index(MasterModel model)
{
var reloadView = true;
// clear any existing errors
foreach (var key in ModelState.Keys)
ModelState[key].Errors.Clear();
if (TryValidateModel(model.Person, "Person"))
{
_db.People.Add(model.Person);
_db.SaveChanges();
reloadView = false;
for (var i = 0; i < model.Addressess.Count(); i++)
{
foreach (var key in ModelState.Keys)
ModelState[key].Errors.Clear();
if (TryValidateModel(model.Addressess[i], "Addressess[" + i.ToString() + "]"))
{
**// UPDATED CODE**
// add Person to Address model
model.Addressess[i].Person = model.Person;
_db.Addressess.Add(model.Addressess[i]);
_db.SaveChanges();
}
}
}
if (reloadView)
{
// clear and re-add all errors
foreach (var key in ModelState.Keys)
ModelState[key].Errors.Clear();
TryValidateModel(model);
return View(model);
}
else
{
// go to some other view
}
}

Resources