ValidationMessage does not render in my view (asp.mvc3) - c#

This problem is very strange, maybe I have missed some small detail, since I'm new to mvc 3...
In a partial view, I have a different model than in the main view (I don't think that it matters in this case). I have added a couple of Validation-helper calls in the view. No matter what I do, they dont show up on the page.
I have enabled framework source debugging, and I can see that the HTML is generated, and are written to "output". Still, they dont appear in the final rendered page. I cannot understand why.
In my partial view:
#model ModelsDTO.Domain.GridRowDTO
#Html.ValidationSummary()
#Html.TextBox("Kalla")
#Html.ValidationMessage("Kalla")
I have the textbox there just to see if it renders. It does.
My controller code (hard coded message, just to try to make it work):
[HttpPost]
public ActionResult SaveGridRow(GridRowDTO rad)
{
List<string> valideringsFel = _dagboksanteckning.SaveDagbokObjekt(rad);
ModelState.AddModelError("Kalla", "Källan felaktig");
return PartialView("_DagbokGrid", rad);
}
The model:
public class GridRowDTO
{
public string Kronika { get; set; }
public string Ok { get; set; }
public string Datum { get; set; }
public string Tid { get; set; }
public string Kalla { get; set; }
public string Handelse { get; set; }
public string Bedomning { get; set; }
public string Till { get; set; }
public string Rubrik { get; set; }
public string Verksamhetsslag { get; set; }
public string OperationPadrag { get; set; }
public string Verksamhetskod { get; set; }
public string LatitudTecken { get; set; }
public string Latitud { get; set; }
public string LongitudTecken { get; set; }
public string Longitud { get; set; }
public string Media { get; set; }
public string AnnatDokument { get; set; }
public string Region { get; set; }
public string id { get; set; }
}
Edit, very interesting finding!
When tracing the call with IE9 F12-mode, the response text acutally contains the expected HTML! Why does'nt it render!
<div class="validation-summary-errors"><ul><li>Källan felaktig</li>
</ul></div>
<input class="input-validation-error" id="Kalla" name="Kalla" type="text" value="1" />
<span class="field-validation-error">Källan felaktig</span>
I would be really thankfull if I could get some assistance to understand this problem.

If you are calling this controller action using AJAX you should make sure that you are substituting the contents of the partial with the new value. For example assuming your partial is wrapped inside a div:
<div id="container">
#Html.Patrial(....)
</div>
Now inside the success callback make sure you have refreshed the contents of the div:
$.ajax({
url: '#Url.Action("SaveGridRow")',
type: 'POST',
data: ...,
success: function(result) {
// Here you must refresh the div or whatever part of the DOM
// you need to update
$('#container').html(result);
}
});
or if you are using Ajax.* helpers to call the action make sure you have specified UpdateTargetId in the AjaxOptions and that this value corresponds to the id of some DOM element you want to refresh.

Related

Object's collection being nulled on post in Razor Pages after having been set successfully through Ajax call

I am trying to add items dynamically to an object's list property using Razor Pages. I can successfully add one item to the list but when I try to add another item it loses the binding and says that the list property is null.
The rest of the form has regular string and int properties that are set and persist as expected. However, when I try to manipulate a list property by dynamically adding new rows using an ajax call the list gets nulled after the first (successful) attempt.
The ajax call:
$("#btnAdd").on('click', function () {
$.ajax({
async: true,
headers: { 'RequestVerificationToken': $('input:hidden[name="__RequestVerificationToken"]').val() },
type: "POST",
url: '?handler=AddOrderItem',
success: function (partialView) {
$('#orderItemsContainer').html(partialView);
}
});
});
The PageModel method:
public IActionResult OnPostAddOrderItem()
{
CurrentSample.SampleDistributions.Add(new SampleDistributionResource());
return Partial("SampleDistributionsPartial", CurrentSample);
}
The partial view:
#model QBSampleGenerator.Models.Resources.CreateSample
#for (int i = 0; i < #Model.SampleDistributions.Count(); i++)
{
<div class="form-group">
<label asp-for="#Model.SampleDistributions[i].DistributionAmount" class="control-label"></label>
<input asp-for="#Model.SampleDistributions[i].DistributionAmount" class="form-control" />
<span asp-validation-for="#Model.SampleDistributions[i].DistributionAmount" class="text-danger"></span>
</div>
}
The class definition of the CurrentSample object:
public class CreateSample
{
public int SurveyId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public int SampleSize { get; set; }
public int[] FilterIds { get; set; }
public IList<SampleDistributionResource> SampleDistributions { get; set; }
}
Let me know if I've forgotten to provide some necessary information. Many thanks in advance for any guidance!
You should check the CurrentSample after Add(). Here I set CurrentSample is static.
private static CreateSample CurrentSample = new CreateSample();
[HttpPost("/AddOrderItem")]
public IActionResult OnPostAddOrderItem()
{
CurrentSample.SampleDistributions.Add(new SampleDistributionResource());
return PartialView("SampleDistributionsPartial", CurrentSample);
}
Codes of Model
public class SampleDistributionResource
{
public SampleDistributionResource() { DistributionAmount = 0; }
public int DistributionAmount { get; set; }
}
public class CreateSample
{
public int SurveyId { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public int SampleSize { get; set; }
public int[] FilterIds { get; set; }
public IList<SampleDistributionResource> SampleDistributions { get; set; }
public CreateSample() { SampleDistributions = new List<SampleDistributionResource>(); }
}
Screenshots of test

Filtering the data at the controller before it is rendered in a view

Hello, I am very new to MVC5, Razor, and EF and I have been looking for two days and still can't figure out a solution to my problem.
What I want to do is have a view where users enter a year, the quarter, and division. On submit, I want a controller for another view to see these parameters and filter the data before the view is rendered. Currently I have 5 different division and I want to filter only one division when the view is rendered.
I have looked at a lot of forums, websites, etc. trying to figure this out and I haven't had any luck. I would be glad to at least get pointed in the right direction. I am trying to learn this by jumping into the fire and figuring it out myself but I need help now.
I have the whole idea down behind how MVC works, I have no problems working with the DB, and I have been successful on learning how scaffolding works and also ViewModels. I am now trying to learn how to manipulate the data within the controller and views. Any help would be appreciated.
View 1 - Just to enter parameters
<p> Enter Year: #Html.TextBox("Year")</p>
<p> Enter Quarter: #Html.TextBox("Qtr")</p>
<p> Enter Division: #Html.TextBox("Div")</p>
<p><input id="Submit" type="button" value="button" /></p>
Controller for View 2
namespace BSIntranet.Controllers
{
public class DivisionIncomeController : Controller
{
private ProjectionsEntities db = new ProjectionsEntities();
// GET: DivisionIncome
public ActionResult Index()
{
return View(db.JobRecaps.ToList());
}
}
}
I don't know what or how to get started here. Thanks for your help!!
EDIT
using System;
using System.Collections.Generic;
public partial class JobRecap
{
public int ID { get; set; }
public string Job_ID { get; set; }
public int Year { get; set; }
public int Qtr { get; set; }
public string Div { get; set; }
public string PreparedBy { get; set; }
public string ReviewedBy { get; set; }
public Nullable<System.DateTime> Date { get; set; }
public Nullable<System.DateTime> ProjStart { get; set; }
public Nullable<System.DateTime> ProjComp { get; set; }
public string SvgsSplit { get; set; }
public Nullable<int> OwnerSplit { get; set; }
public Nullable<int> BSSplit { get; set; }
public string JointVent { get; set; }
public Nullable<int> BSPct { get; set; }
public string ContractType { get; set; }
public string ContractWritten { get; set; }
public Nullable<decimal> CurContrAmt { get; set; }
public string FeeBasis { get; set; }
public Nullable<decimal> EstTotFeePct { get; set; }
public Nullable<decimal> EstTotFeeAmt { get; set; }
public string PreconFeeBasis { get; set; }
}
To keep things simple you can simply add int? Year, int? Qtr, string Div parameters to your Index action and search using them:
public ActionResult Index(int? Year, int? Qtr, string Div)
{
var data= db.JobRecaps.AsQueryable();
if(Year.HasValue)
data= data.Where(x=>x.Year == Year);
if(Qtr.HasValue)
data= data.Where(x=>x.Qtr == Qtr );
if(!string.IsNullOrEmpty(Div))
data= data.Where(x=>x.Div == Div );
return View(data.ToList());
}
Note:
Also you can separate concerns and create a JobRecapSearchModel containing those search parameters and use it as parameter of action and also create a JobRecapBusinessLogic class containing a List<JobRecap> Search(JobRecapSearchModel searchMode) method with the business that I used above. This way you will have a more flexible and beautiful controller.
To learn more about how to use such method and the benefits you can take a look at this question:
Filter/Search using Multiple Fields - ASP.NET MVC

Bind generated fields to model in razor view

UPDATE: fixed this issue by adding the name attribute to the select tag that was added in order for it to be added to the formelement upon submit.
I have a partial view that get's passes a model that has a foreign key. The partial view's sole purpose is to create a new object in the database for this model. I created a drop down for one of the fields based on something outside of the model and now when I post the form, that field isn't included in the api post to create the record.
(for those familiar, yes, this is pretty much the contact example out of the box, I'm trying to extend it a bit and could use some help)
<form id="addContact" data-bind="submit: createContactFromForm">
#Html.ValidationSummary(true)
<fieldset>
<legend>Contact</legend>
#Html.EditorForModel()
<div class="editor-label"><label>Store:</label></div>
<div class="editor-field" id="storediv">
<select id="StoreId" **name="StoreId"** data-bind="options: stores, optionsText: 'Name', optionsValue: 'Id', optionsCaption: 'Choose...'"></select>
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
</form>
How can I get the Store field to be part of the model on form submit? I'm overriding the submit to call the createContactFromForm function in the knockoutjs viewmodel.
Updated with portion of the viewmodel that is being called:
self.createContactFromForm = function (formElement) {
// If valid, post the serialized form data to the web api
$(formElement).validate();
if ($(formElement).valid()) {
$.post("api/contacts", $(formElement).serialize(), "json")
.done(function (newContact) {
self.contacts.push(newContact);
$('#addContact')[0].reset();
});
}
}
Server side model:
public Contact()
{
this.Created = DateTime.Now;
this.Emails = new List<Emails>();
}
[ScaffoldColumn(false)]
public int Id { get; set; }
[Required, MaxLength(256)]
public string FirstName { get; set; }
[Required, MaxLength(256)]
public string LastName { get; set; }
[ScaffoldColumn(false)]
public string Name { get { return string.Concat(this.FirstName, " ", this.LastName); } set { } }
[MaxLength(256)]
public string EmailAddress {
get
{
return this.Emails.Count == 0 ? string.Empty : this.Emails[0].EmailAddress;
}
set
{
if (this.Emails.Count == 0)
{
this.Emails.Add(new Emails());
}
this.Emails[0].EmailAddress = value;
}
}
[MaxLength(50)]
public string PhoneNumber { get; set; }
[MaxLength(256)]
public string Address { get; set; }
[MaxLength(256)]
public string City { get; set; }
[MaxLength(50)]
public string State { get; set; }
[MaxLength(256)]
public string ZipCode { get; set; }
[Required]
[ScaffoldColumn(false)]
public int StoreId { get; set; }
public Store Store { get; set; }
[ScaffoldColumn(false)]
public DateTime Created { get; set; }
public virtual IList<Emails> Emails { get; protected set; }

Trying to submit form values where only part of the form binds to a model (with ASP.Net MVC3)

I apologize in advance for a wall of text below. I hope to provide all the info at once that may be needed to understand what I'm doing.
I've got a page where I'm collecting some basic user info (name, email, etc). In another portion of the page I have a multiple choice quiz form (using radio inputs for each question). My goal is to collect the contact info, process the quiz answers, and store a score with the contact info in a QuizResults table.
This may be a case of over thinking, or over engineering.. so feel free to tell me I'm going about this all wrong.
Here's my Quiz related models:
public class QuizType {
public QuizType() {
this.QuizQuestions = new HashSet<QuizQuestion>();
this.QuizResults = new HashSet<QuizResult>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<QuizQuestion> QuizQuestions { get; set; }
public virtual ICollection<QuizResult> QuizResults { get; set; }
}
public class QuizQuestion {
public QuizQuestion() {
this.QuizAnswers = new HashSet<QuizAnswer>();
}
public int Id { get; set; }
public string Question { get; set; }
public int Order { get; set; }
public int QuizTypeId { get; set; }
public virtual ICollection<QuizAnswer> QuizAnswers { get; set; }
public virtual QuizType QuizType { get; set; }
}
public class QuizResult {
public int Id { get; set; }
public string TesterName { get; set; }
public string TesterEmail { get; set; }
public string TesterCompany { get; set; }
public string TesterPhone { get; set; }
public string ApproverName { get; set; }
public string ApproverEmail { get; set; }
public bool HasCompanyIssuedIdBadge { get; set; }
public int Score { get; set; }
public virtual QuizType QuizType { get; set; }
}
public class QuizAnswer {
public QuizAnswer() {
}
public int Id { get; set; }
public bool isCorrectAnswer { get; set; }
public string Answer { get; set; }
public int QuizQuestionId { get; set; }
public virtual QuizQuestion QuizQuestion { get; set; }
}
So basically I can create a Quiz Type, then for each type I can create multiple questions, each question can have multiple answers. I'm not trying to post back any data for QuizType, QuizQuestion, or QuizAnswer. Those are just there to help build my page[s].
This is where I start scratching my head. I need to be able to iterate through QuizQuestions and QuizAnswers to create the multiple choice form. But I also need to bind part of that form to QuizResults for posting back.... here's what I've got now in order to display the form (but not work correctly).
First, I've created a ViewModel:
public class QuizViewModel {
public IQueryable<QuizQuestion> QuizQuestions { get; set; }
public QuizResult QuizResults { get; set; }
}
Then in my controller:
public ViewResult Index() {
var questions =
from q in unitOfWork.QuizQuestionRepository.Get()
where q.QuizType.Name.Equals("QuizTypeOne")
select q;
var qvm = new QuizViewModel {
QuizQuestions = questions
};
return View(qvm);
}
I won't post my entire razor view, but I think these are the pertinent parts:
#model QuizViewModel
#* *** MISC STYLE, JS, ETC LEFT OUT FOR BREVITY *** *#
#using (Html.BeginForm()) {
#Html.LabelFor(model => model.QuizResults.TesterName)<br />
#Html.EditorFor(model => model.QuizResults.TesterName)
#* *** OTHER FORM FIELDS LEFT OUT FOR BREVITY *** *#
foreach (var item in Model.QuizQuestions) {
<div class="wizard-step">
<h3>#item.Question</h3>
#{
// I've been tinkering with this trying to find a way to get it
// so that the input would have the right id to be picked up and
// dropped into my post object correctly
var inputId = "SelectedAnsers[" + item.Id + "]";
}
#foreach (var answer in item.QuizAnswers) {
<input type="radio" id="#inputId" name="#inputId" value="#answer.Id" /> #answer.Answer #:(#answer.isCorrectAnswer)
<br />
}
</div>
}
}
Back in my controller I have a method setup to handle the post, but it's not doing anything at the moment. I'm just running in debug and looking at the values posted when I submit the form.
[HttpPost]
public ViewResult DukeDrive(QuizViewModel quizViewModel) {
// I have a breakpoint set so that I can inspect quizViewModel
return View();
}
In my head I want to be able to process the quiz form values, calculate the score, then create a new QuizResult object based on the contact info filled out and the newly calc'd score. I'll be darned if I can find the right way to do it though.
Any pointers?
You could add another parameter of type FormCollection which contains all posted values.
[HttpPost]
public ViewResult DukeDrive(QuizViewModel quizViewModel, FormCollection formData) {
// I have a breakpoint set so that I can inspect quizViewModel
return View();
}

ASP.Net MVC returning value of a DropDown

I am learning, and managed to make a nice info display page, displaying lists of transactions. However, I have no added DropDown box, which has a list of Bank Accounts. It's defaulted to All.
When the user selects an account, and presses the submit button, the page should then reloca with only transactions for that account.
I have created the drop down, and the form for it, like this:
<form id="form1" runat="server">
<h2>
Transactions:</h2>
<p>
<%
using (Html.BeginForm())
{
%>
Bank Account:
<% =Html.DropDownList("ddAccounts", Model.BankAccountItems)%> <input id="Submit1" type="submit" value="Select" />
<%
}
%>
</p>
</form>
My model contains this:
public class AccountTransactionDisplay
{
public AccountTransactionDisplay()
{
DisplayLines = new List<AccountTransactionDisplayLine>();
}
public SelectList BankAccountItems { get; set; }
public List<AccountTransactionDisplayLine> DisplayLines {get; set; }
public string ClosingBalance { get; set; }
}
public class BankAccountDropdownItem
{
public string Text {get; set;}
public string Value {get; set;}
}
public class AccountTransactionDisplayLine
{
public string RowColouring { get; set; }
public string TransactionDate { get; set;}
public string PayeeName { get; set; }
public string Amount { get; set; }
public bool AmountIsDebit { get; set; }
public string CategoryName { get; set; }
public string CostCenterName { get; set; }
public string BudgetName { get; set; }
public string RunningTotal { get; set; }
public bool RunningTotalIsDebit { get; set; }
public bool AlternateRowColour { get; set; }
public bool HasSplitItems { get; set; }
}
So, AccountTransactionDisplay is the model I pass to the view. In that model, I have this:
public SelectList BankAccountItems { get; set; }
That holds a list of items that are displayed in my Drop Down. That is being displayed correctly.
However, when the user clicks the submit button, I am unsure how to get the selected value back.
I thought that I would have a method in my controller that accepts the POST... So, I have added this:
[HttpPost]
public ActionResult Transactions(AccountTransactionDisplay model)
{
AccountTransactionDisplay trans = GetTransactions();
return View(trans);
}
And if I set a breakpoint, it is hitting this, but it seems model is empty. I need to add the id of the selected account ot the GetTransactions method, to do the filtering.
When your page renders, view the source. Whatever the name attribute of the select element is, that is the name of a property you will need to add to your model, then the model binder will bind that value to your model. When a form is submitted, only name/value pair of the form fields are submitted (for the most part), so the select element's name will be in the form data as well as its selected value, all of the options are not posted back, so MVC has no way of rebinding your SelectList property.
HTH

Categories