My Model:
public class EntryModel
{
[Required]
public string Date { get; set; }
public string Car { get; set; }
public string Engine { get; set; }
public string User { get; set; }
public int CarCod { get; set; }
public int EngineCod { get; set; }
}
My View:
<%=Html.Label("Car")%>
<%=Html.Text("Car", car,new { #class = js_car")%>
<%=Html.ValidationMessageFor(x=>x.Car) %>
<%=Html.TextBox("CarCod", carCod, new { #class = "js_car", #style = "display:none;",#id="_car_cod" })%>
My Problem:
When posting the data, "CarCod" always fires an error at the ModelState, thus rendering both ModelState.IsValid and Html.ValidationSummary useless.
I already have workarounds for this (i.e not using them), but it would be very nice to know why.
To go off of what Garret said, make CarCod and EngineCod nullable.
It looks like you're hiding the CarCod textbox so it will be submitted with an empty string. The Model expects it to be an int so it's having problems converting that to an integer. What happens if you set the value to "0"?
Related
I have radiobuttons nested within two for loops, they are for a quiz and only one radiobutton should be selected for each question, here is the second for loop where the radiobutton is:
for (int k = 0; k < Model[i].QuizAnswers.Count(); k++)
{
<li>
#Html.HiddenFor(model => Model[i].QuizAnswers[k].Correct)
#Html.RadioButtonFor(model => Model[i].QuizAnswers[k].Chosen, true, new { id = "radioanswer", #Name = "N-" + #Model[i].Order, data_questionid = #Model[i].Order })
#Html.DisplayFor(model => Model[i].QuizAnswers[k].Answer)
</li>
}
In order to stop the user selecting multiple radiobuttons I have grouped the name attribute for each set of radiobuttons as above. Each Radiobutton is posting true to an individual boolean field. Without the grouped name attribute the radiobuttons post correctly, however with the grouped name attribute they do not post. I'm guessing this is because by grouping the buttons using the name attribute MVC assumes they all should be returning to a single field. How can I fix this so that the Radiobuttons return true to their individual fields whilst at the same time being grouped so that only one can be selected?
Edit - As requested my models are as follows, the view model the radio buttons are posted too:
public class QuizViewModel
{
public int QuizQuestionID { get; set; }
public int QuizID { get; set; }
public int EnrollmentID { get; set; }
public int OldCoursePageID { get; set; }
public string Question { get; set; }
public int Order { get; set; }
public int Type { get; set; }
public IList<QuizAnswers> QuizAnswers { get; set; }
}
The QuizAnswers model within the viewmodel above:
public class QuizAnswers
{
[Key]
public int QuizAnsID { get; set; }
public int QuizQuestionID { get; set; }
public string Answer { get; set; }
public int Order { get; set; }
public bool Correct { get; set; }
public bool Chosen { get; set; }
public virtual QuizQuestions QuizQuestions { get; set; }
}
Probably I'm doing this the wrong way, but this is a sample of the code I'm dealing with:
ViewModel
public class TasDataView
{
public int nTas { get; set; }
public string codTas { get; set; }
public decimal nValue { get; set; }
public bool nState { get; set; }
public System.DateTime nDate { get; set; }
public IEnumerable<Segments> ListSegments { get; set; }
public IEnumerable<Tas> ListTas { get; set; }
}
Segments class
public class Segments
{
public int segmentValue { get; set; }
public string segmentCode { get; set; }
public bool nState { get; set; }
public System.DateTime nDate { get; set; }
}
So, when I call the View with my controller, I send an TasDataView object as parameter:
public ActionResult AddTas()
{
TasDataView TDV = new TasDataView();
SegmentsManager SM = new SegmentsManager();
TDV.ListSegments = SM.DataSegments();
return View(TDV);
}
And here is the problem I'm facing. I need all the values of ViewModel for this View to work. So, for example, I have:
#model Project.Models.ViewModel.TasDataView
#Html.EditorFor(model => model.nValue, new { htmlAttributes = new { #class = "form-control" } })
And that will create the box for inserting whatever I want into nValue. But what if I want to access the ListSegments properties (from Segments class) that I sent to the View, so I can make a DropDown List ?
I can't do something like:
#Html.DropDownListFor(x => x.ListSegments.segmentValue, new SelectList(Model.ListSegments));
because all the ListSegments (like segmentValue) properties "are not in" TasDataView, but in Segments class.
How can I reorganize my DataView to be manageable for what I want? Instead of a List<> I should have plain variables?
I guess you're doing it wrong. The first argument of DropDownListFor is an expression that represents the property of the model that receives the value of the item selected in the drop down list. It must be some dedicate=d property somewhere on your model. e.g. selectedSegment.
EDIT:
So, if your goal is to present a list of values via model to the user in a drop down list and let the user pick a value, you'll need to:
have a property on the model to store the selected item (segment), e.g. selectedSegment,
properly render your segments as strings to present them.
The simplest solution is given below.
public class TasDataView
{
public int nTas { get; set; }
public string codTas { get; set; }
public decimal nValue { get; set; }
public bool nState { get; set; }
public System.DateTime nDate { get; set; }
public IEnumerable<Segments> ListSegments { get; set; }
public IEnumerable<Tas> ListTas { get; set; }
public Int32 selectedSegment;
}
#Html.DropDownListFor(x => x.selectedSegment, new SelectList(Model.ListSegments.Select(s => s.segmentCode)));
So there are no properties of the list you need to access.
Long winded out of necessity:
I have a strongly typed MVC 4 form. The form is built dynamically depending on the current URL parameters. When the user submits the form, the form input data is posted to a controller, the controller does it's thing, then the results from the controller method need to be displayed below the form.
Specifically in my case the results are line item ticket data. The user can hit submit as many times as they want and each time the additional results from the controller are displayed on the same page below the form; Each post is an added line item. (The line items are requested/stored by a call to an external webapi, so each time a submit happens I rebuild the line items from my controller method).
What I am trying to do is not have the page refresh every time to build the form all over again while simply updating the line items below the form through an ajax call. The form is expensive to build because it also is built from an external web api call. My model is very large and has a lot of data even though the form itself isn't.
What I have attempted so far is to put the line items into a partial view, which I will update after each form submit. I'm submitting the form with jQuery and Ajax. What seems to be happening is the form is submitted, the ajax method is called, but my controller is returning the partial view and master page layout directly. It's not returning back to the jQuery call. This could be Sitefinity or it could be something I'm doing completely wrong.
What I have so far is this: http://beta.kentuckycenter.org/all-shows/jeff-beck. Click on "Buy Tickets" on this page to see form.
Submit the form (Press "GO") then the form submits and only returns the partial view.
But it should look like this (this is design only):
http://www.kentuckycenter.org.staging01.spiiider.com/select-tickets.php
Sitefinity MVC widgets change the complexity for sure. My setup is Master page (Sitefinity templates are built from master pages), then default view, and partial view. I'm trying to update the partial view inside the default view.
I've tried many different ways including ajax.beginform form but I still can't seem to get a partial view to return inside a default view. I can't pass my original SelectTicketsModel data in hidden fields because some of the items are lists of other models.
Controller Actions simplified:
public ActionResult Index(string performanceID, string pageID)
{
var Model = new SelectTicketsModel();
Model = Model.GetPerformanceDetails(performanceIDnew, productionID);
return View("Default", Model);
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Index(GetTicketsModel Model)
{
//call webapi to reserve tickets
ticketsReserved = Model.ReserveTickets(Model.PriceType, performanceID, numberOfTickets, zoneID, Model.Accessible);
if (ticketsReserved == numberOfTickets)
{
LineItemModel lineModel = new LineItemModel();
//Fill LineItemModel from webpapi
}
return PartialView("TicketList", LineItemModel);
}
public class SelectTicketsViewModel
{
public bool Results { get; set; }
public int PerformanceID { get; set; }
public Nullable<DateTime> PreSaleDateStart { get; set; }
public Nullable<DateTime> PreSaleDateEnd { get; set; }
public bool HideSYOS { get; set; }
public bool IsGeneralAdmission { get; set; }
public bool WillCallOnly { get; set; }
public bool IsOnSale { get; set; }
public bool IsSoldOut { get; set; }
public int MaxSeats { get; set; }
public int ZoneMapID { get; set; }
public string TimeSlot { get; set; }
public string Title { get; set; }
public DateTime PerformanceDate { get; set; }
public string Location { get; set; }
// Create Lists from Models below
public List<PriceZoneModel> PriceZones { get; set; }
public List<PriceTypeModel> PriceTypes { get; set; }
public List<LineItemModel> LineItems { get; set; }
}
public class PriceZoneModel
{
public int PriceZoneID { get; set; }
public string PriceZoneDescription { get; set; }
public int PriceTypeID { get; set; }
public string PriceTypeDescription { get; set; }
public decimal Price { get; set; }
public decimal BasePrice { get; set; }
public bool Available { get; set; }
public int AvailableCount { get; set; }
public int Rank { get; set; }
}
public class PriceTypeModel
{
public int PriceTypeID { get; set; }
public string PriceTypeDescription { get; set; }
public string PriceTypeShortDescription { get; set; }
public string Category { get; set; }
public bool IsDefaultPriceType { get; set; }
public bool IsPromo { get; set; }
}
public class LineItemModel
{
int id { get; set; }
bool AccessibleSeats { get; set; }
public List<SubLineItemModel> SubLineItems { get; set; }
}
public class SubLineItemModel
{
public string Section { get; set; }
public int NumberOfSeats { get; set; }
public string SeatNumber { get; set; }
public int SeatID { get; set; }
public decimal Price { get; set; }
public string PriceTypeDescription { get; set; }
}
public class GetTicketsModel
{
//Form Values needed to Reserve Tickets
public string NumberOfTickets { get; set; }
public string PriceType { get; set; }
public string ZoneID { get; set; }
public bool Accessible { get; set; }
public string PerformanceID { get; set; }
}
If the returned ajax is opening up on a new page, it sounds like you are not using the unobtrusive library.
Make sure you have the following file included somewhere on your cshtml page or even in your layout file (if you are using ajax throughout your site).
jquery.unobtrusive-ajax.js
Where can one download Microsoft jQuery Unobtrusive Validation without using NuGet
From the sounds of it, your method of returning the data in a partial and updating the front end element should work fine.
Only thing I would look out for is that you should be passing the variable as the Model, not the class
if (ticketsReserved == numberOfTickets)
{
LineItemModel lineModel = new LineItemModel();
//Fill LineItemModel from webpapi
}
return PartialView("TicketList", lineModel ); //<-- here
EDIT
Yeah, I took a look at your beta link and the page does not contain the unobtrusive-ajax.js. That should fix your problem.
If you are getting the whole page as a response from the controller from an Ajax call it's a sitefinty thing. Try returning your list from your action result as Json(items, allow get ) instead of the partial view? Also kendo observable or kendo grid push the need data to the observable would be great solutions also.
Last day, i saw that in my razor view
#Html.DropDownListFor(x => x.FoodId,null, htmlAttributes: new { #class = "form-control" })
// and (just another alternative)
#Html.DropDownList("FoodId", null, htmlAttributes: new { #class = "form-control" })
And i'm wondering what's going on with the data in the list, where and when data-filling occurs? and what is the difference between the two lines? and how the dropdown got filled with data (because there is data in the execution of the code)
sorry for my bad english
Update #1
Model:
Food.cs and User.cs
public partial class Food
{
public Food()
{
this.User = new HashSet<User>();
}
public System.Guid Id { get; set; }
public string Name { get; set; }
public virtual ICollection<User> User { get; set; }
}
//
public partial class User
{
public System.Guid Id { get; set; }
public string Name { get; set; }
public Nullable<System.Guid> FoodId { get; set; }
public virtual Food Food { get; set; }
}
Controller (only action)
public ActionResult Create()
{
ViewBag.FoodId = new SelectList(db.FoodSet, "Id", "Name");
return View();
}
Omg thanks i'm now stupid :)
Answer: Got filled with ViewBag.FoodId
When passing a null value to the second argument, it it will automatically, even without javascript and with a cleared cache look in the ViewBag for a key with the same name as the dropdown, otherwise launch exception.
In my case, null was passed and it checked the ViewBag and found a key
I have the following view model to query my table:
QuestionViewModel.cs
public enum TypeQuestion {
Long = 1,
Short = 2,
Small = 3,
}
public class QuestionViewModel
{
public string Name { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public string MaxAge { get; set; }
public string Category { get; set; }
public string Account { get; set; }
public TypeQuestion CurrentTypeQuestion { get; set; }
}
if the query I'm doing is of type:
Long: displays all fields.
Short: displays Name, LastName, Address, MaxAge.
Small: displays Name, LastName.
Is there any way to put some kind of DataAnnotation to determine which fields to display in the view or some other way?, To avoid putting a "what if?" for each field.
Thank you.
This may be overkill, and i'd in fact lean towards #Mystere Man's answer, but this is another option.
Instead of regular primitive types in your ViewModel, set them up to cater for the logic. Looks like Name and LastName are always displayed, whilst Address and MaxAge are conditional.
So, setup your ViewModel like this:
public class QuestionViewModel
{
public string Name { get; set; }
public string LastName { get; set; }
public IEnumerable<ConditionalField> ConditionalFields { get; set; }
public string Category { get; set; }
public string Account { get; set; }
}
public class ConditionalField
{
public string Field { get; set; }
public bool Display { get; set; }
}
In your controller, setup the nested viewmodel and the boolean values for Address and MaxAge ccording to the value of CurrentTypeQuestion.
Then, have your View like this:
/Views/Questions.cshtml
#model QuestionViewModel
#Html.DisplayForModel()
Then create a custom display template (or editor template, if this is a form) for QuestionViewModel:
/Views/DisplayTemplates/QuestionViewModel.cshtml
#model QuestionViewModel
#Html.DisplayFor(model => model.Name)
#Html.DisplayFor(model => model.LastName )
#Html.DisplayFor(model => model.Category)
#Html.DisplayFor(model => model.Account)
#Html.DisplayFor(model => model.ConditionalFields)
Then create another custom display template for ConditionalField:
Views/DisplayTemplates/ConditionalField.cshtml
#model ConditionalField
#if (Model.Display) {
#Html.DisplayForModel()
}
As i said, may be overkill, but in the end, you only have a single if statement in the custom template, no loops, and your main view and first-level template stays clean.
To keep it simple, and avoid complex if logic in your view, just create three different views, with only the data you need in each view. Then select the view in your controller based on the question type.
Based from this link and this link
Controller:
public ActionResult Consulta()
{
return View(new QuestionViewModel());
}
ViewModel:
public enum TypeQuestion {
Long = 1,
Short = 2,
Small = 3,
}
public class QuestionViewModel
{
public string Name { get; set; }
public string LastName { get; set; }
public string Address { get; set; }
public int MaxAge { get; set; }
public string Category { get; set; }
public string Account { get; set; }
public TypeQuestion CurrentTypeQuestion { get; set; }
public bool EnabledField(ModelMetadata field)
{
//check pending implementation
return true;
}
}
View:
#model MySite.QuestionViewModel
#using System.Linq;
#using System.Collections;
#{
ViewBag.Title = "Question";
Layout = "~/Views/Shared/Layout.cshtml";
}
<h2>Question</h2>
#using (Html.BeginForm(new { id = "FormQuestion" }))
{
foreach (var prop in ViewData.ModelMetadata.Properties
.Where(pm => pm.ShowForDisplay && !ViewData.TemplateInfo.Visited(pm) && ViewData.Model.EnabledField(pm)))
{
if (prop.HideSurroundingHtml)
{
Html.Editor(prop.PropertyName);
}
else
{
<div class="editor-label">
#(prop.IsRequired ? "*" : "")
#Html.Label(prop.PropertyName)
</div>
<div class="editor-field">
#Html.Editor(prop.PropertyName, prop.Model)
#Html.ValidationMessage(prop.PropertyName, "*")
</div>
}
}
}