ViewModel is passing null values to controller on submit - c#

My view :
#using (Html.BeginForm("", "", FormMethod.Post, new { id = "responseEntryForm" }))
{
<div id="SiteDeployment" class="tabcontent">
#Html.HiddenFor(m=>m.Sections,Model.Sections)
#for (int index = 0; index < Model.Sections.Count; index++)
{
<fieldset class="leftFieldset">
<div class="inputFieldDiv">
<label class="GroupHeadings"> #Model.Sections[index].Name</label><br />
#for (int subIndex = 0; subIndex < Model.Sections[index].SubSections.Count; subIndex++)
{
<div style="width:100%">
<div class="SubGroups">
#Model.Sections[index].SubSections[subIndex].Name
</div>
<div class="subEntries">
#for (int subsubIndex = 0; subsubIndex < Model.Sections[index].SubSections[subIndex].QuestionsList.Count; subsubIndex++)
{
<div class="subSections">
<label class="StrucQuestions"> #Model.Sections[index].SubSections[subIndex].QuestionsList[subsubIndex].Question</label>
#Html.DropDownListFor(m => m.Sections[index].SubSections[subIndex].QuestionsList[subsubIndex].Response, new SelectList(Model.ResponseList, "Value", "Text"), new { #class = "strucType", #id = "ddl_" + subIndex + Model.Sections[index].SubSections[subIndex].QuestionsList[subsubIndex].QuestionID })
</div>
}
</div>
</div>
}
</div>
</fieldset>
}
calling my controller and passing form data as below using ajax call:
function submitResponses() {
$.ajax({
url: '#Url.Action("SaveResponsesData", "Dashboard")',
datatype: 'json',
type: "POST",
data: $('#responseEntryForm').serialize(),
success: function (result) {
if (result == "T ") {
alert("Save is successful");
}
}
});
}
and my controller is like below:
[HttpPost]
public ActionResult SaveResponsesData(ResponseEntryViewModel objResponseEntryViewModel)
{
// ViewBag.SelectedType = TypeValue.ToUpper();
return View();
}
My ViewModel looks like below:
public class ResponseEntryViewModel
{
public int TypeID { get; set; }
public string TypeName { get; set; }
public string CompletedBy { get; set; }
public string CompletedOn { get; set; }
public int User_ID { get; set; }
public List<SectionDataModel> Sections = new List<SectionDataModel>();
public IEnumerable<SelectListItem> ResponseList { get; set; }
public class SectionDataModel
{
public int SectionID { get; set; }
public string Name { get; set; }
public string Status { get; set; }
public int TypeId { get; set; }
public List<SubSectionModel> SubSections = new List<SubSectionModel>();
}
public class SubSectionModel
{
public int SubSectionID { get; set; }
public string Name { get; set; }
public string Status { get; set; }
public int SectionId { get; set; }
public List<QuestionModel> QuestionsList = new List<QuestionModel>();
}
public class QuestionModel
{
public int SubSectionID { get; set; }
public int QuestionID { get; set; }
public string Question { get; set; }
public bool Response { get; set; }
}
}
In my view model ResponseEntryViewModel , i have a list of sections which has a list of sub sections which further has a list of questions and user is entering responses to those questions from my view.
When I click on submit. My viewModel is not having any values and Sections count is 0.
Any suggestions?

I'm not sure if this is the issue but it could be.
datatype
should be
dataType

Easiest would be just to remove dataType attribute completely. You are sending form-encoded data, not JSON there.
If you want to send JSON to server, you would have to use [FromBody] attribute:
[HttpPost]
public ActionResult SaveResponsesData([FromBody] ResponseEntryViewModel objResponseEntryViewModel)
{
// ...
return View();
}
However, you don't have data in JSON format. For JSON, normally you use JavaScript object and call JSON.stringify(data) function on it. JQuery's serialize() uses different format, for form-posting - Encode a set of form elements as a string for submission.
Example of this formatting would be: single=Single&multiple=Multiple&multiple=Multiple3&check=check2&radio=radio1
You might also have to set contentType: "application/x-www-form-urlencoded"

I think it would be a lot easier if you make a separete model for saving the response, something like, I hope you understand what I trying to show:
public class SaveResponseModel
{
public int SubSectionID { get; set; }
public int QuestionID { get; set; }
public bool Response { get; set; }
}
[HttpPost]
public ActionResult SaveResponsesData(List<SaveResponseModel> responses)
{
// ViewBag.SelectedType = TypeValue.ToUpper();
return View();
}
.cshtml:
for each Sections, SubSection, Question...{
<input name="responses.Index" type="hidden" value="#item.QuestionID" />
<input name="responses[#item.QuestionID].QuestionID" type="hidden" value="#item.QuestionID" />
<input name="responses[#item.QuestionID].SubSectionID" type="hidden" value="#item.SubSectionID" />
#Html.DropDownList((string)string.Format("responses[{0}].Response", #item.QuestionID), new SelectList(Model.ResponseList, "Value", "Text"), new { #class = "strucType", #id = "ddl_" + subIndex + Model.Sections[index].SubSections[subIndex].QuestionsList[subsubIndex].QuestionID })
}

Related

blazor dynamic forms add validation without model class

im learning blazor and wanted to build some small dynamic form generator
i known that there is already something like VxFormGenerator but wanted to learn by myself a bit - at least for simple forms purposes.
so i have it like this:
DynamicFormsComponent:
<EditForm Model = "#Params" OnValidSubmit="OnValidSubmit">
<DataAnnotationsValidator/>
#if(Params != null ) #foreach (var field in Params.FormFields)
{
<div class="mb-3">
<label for= "#field.Id">#field.Label :</label>
#switch (field.Type)
{
case FormFieldType.Text:
{
<InputText id="#field.Id" #bind-Value="#field.StrValue" placeholder="#field.PlaceHolder" class="form-control"></InputText>
break;
}
case FormFieldType.Number:
{
<InputNumber id="#field.Id" #bind-Value="#field.IntValue" placeholder="#field.PlaceHolder" class="form-control"> ></InputNumber>
break;
}
case FormFieldType.Date:
{
<InputDate id="#field.Id" #bind-Value="#field.DateValue" placeholder="#field.PlaceHolder" class="form-control"></InputDate>
break;
}
default:
{
break;
}
}
</div>
}
<ValidationSummary></ValidationSummary>
<button type="submit" class="btn btn-primary">#Params?.SendButtonText</button>
public partial class DynamicFormComponent:ComponentBase
{
[Parameter]
public DynamicFormParams Params { get; set; } = new DynamicFormParams();
[Parameter]
public EventCallback<DynamicFormParams> OnValidSubmitCallback { get; set; }
void OnValidSubmit()
{
Console.WriteLine("onValidSubmit");
if (OnValidSubmitCallback.HasDelegate ) OnValidSubmitCallback.InvokeAsync(Params);
//NavigationManager.navigateto.....
}
}
public class DynamicFormParams
{
public List<DynamicFormField> FormFields { get; set; } = new List<DynamicFormField>();
public string FormTitle { get; set; } = string.Empty;
public string SendButtonText { get; set; } = "Send";
}
public class DynamicFormField
{
public string? Label { get; set; }
public string Id { get; set; } = Guid.NewGuid().ToString();
public string PlaceHolder { get; set; } = string.Empty;
public FormFieldType? Type { get; set; }
public string? StrValue { get; set; }
public int? IntValue { get; set; }
public DateTime? DateValue { get; set; }
}
public enum FormFieldType
{
Text,
Number,
Date
}
so the usage would be
<DynamicFormComponent Params="#p" OnValidSubmitCallback=#onChildFormSubmit ></DynamicFormComponent>
DynamicFormParams p = new DynamicFormParams()
{
FormTitle = "test form Title",
SendButtonText = "Wyƛlij",
FormFields = new List<DynamicFormField>()
{
new DynamicFormField()
{
Label="testLabelStr",
Id="anyid-notGuId",
StrValue="a",
PlaceHolder="asdadsad",
Type=FormFieldType.Text
},
new DynamicFormField()
{
Label="testLabelInt",
Type=FormFieldType.Number,
PlaceHolder="enter nr"
},
new DynamicFormField()
{
Label="testLabelDate",
Type=FormFieldType.Date,
DateValue=DateTime.Parse("2021-04-01")
}
}
};
private void onChildFormSubmit(DynamicFormParams pp)
{
Console.WriteLine("from local variable");
Console.WriteLine(JsonSerializer.Serialize(p));
Console.WriteLine("from event arg");
Console.WriteLine(JsonSerializer.Serialize(pp));
}
and the question is:
how with this approach i can use form validation ?
i have no clasic'model' so probably would need something like add 'list of validators ' to my DynamicFormField class
and somehow force DataAnnotationsValidator to use this list ? is it possible withoud clasic 'model' and 'data annotations attributes' on it ?
thanks and regards
The only way to validate form without a model is to use the Blazorise validation system. https://blazorise.com/docs/components/validation.
PS. I'm a Blazorise creator.

How to print PartialView

i was looking for this and tried to fix for couple of days but with no sucess. What wrong im doing in this code? I want to print _Champions
and _SearchEngine as PartialView in Home/Index but it show error.
My HomeController
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpGet]
public ActionResult _SearchEngine()
{
SearchLeagueModel searchLeagueModel = new SearchLeagueModel();
searchLeagueModel.MainSelector = "champions";
return PartialView("_SearchEngine", searchLeagueModel);
}
public ActionResult _SearchEngine(SearchLeagueModel searchLeagueModel)
{
if (searchLeagueModel.MainSelector == "champions")
{
return RedirectToAction("_Champions", searchLeagueModel);
}
else return View();
}
[HttpPost]
public ActionResult _Champions(SearchLeagueModel searchLeagueModel)
{
string chooser = searchLeagueModel.MainSelector;
string selector;
if (searchLeagueModel.MainSelector != null)
{
selector = "filter[name]=" + searchLeagueModel.MainSelector;
}
else
{
selector = "";
}
WebRequest request = WebRequest.Create("https://api.pandascore.co/lol/" + chooser + "?" + selector + "&token=mytoken);
WebResponse response = request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string responseFromServer = reader.ReadToEnd();
List<ChampionsModel> champions = JsonConvert.DeserializeObject<List<ChampionsModel>>(responseFromServer);
return PartialView("_Champions", champions);
}
//other views
}
My IndexModelView
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace LeagueAPI.Models
{
public class IndexModelView
{
public IndexModelView()
{
ChampionsList = new ChampionsModel();
Searcher = new SearchLeagueModel();
}
public ChampionsModel ChampionsList { get; set; }
public SearchLeagueModel Searcher { get; set; }
}
public class ChampionsModel
{
public List<string> videogame_versions { get; set; }
public double spellblockperlevel { get; set; }
public double spellblock { get; set; }
public string name { get; set; }
public double mpregenperlevel { get; set; }
public double mpregen { get; set; }
public double mpperlevel { get; set; }
public double mp { get; set; }
public double movespeed { get; set; }
public string image_url { get; set; }
public int id { get; set; }
public double hpregenperlevel { get; set; }
public double hpregen { get; set; }
public double hpperlevel { get; set; }
public double hp { get; set; }
public double critperlevel { get; set; }
public double crit { get; set; }
public string big_image_url { get; set; }
public double attackspeedperlevel { get; set; }
public object attackspeedoffset { get; set; }
public double attackrange { get; set; }
public double attackdamageperlevel { get; set; }
public double attackdamage { get; set; }
public double armorperlevel { get; set; }
public double armor { get; set; }
}
}
My _Champions.cshtml PartialView(made as PartialView)
#using LeagueAPI.Models
#model System.Collections.Generic.List<ChampionsModel>
<fieldset>
<div class="d-flex p-3 w-auto h-auto">
#foreach (var element in #Model)
{
<div class="p-3 flex-lg-wrap">
<div class="card p-2" style="width: 15rem ;">
<img class="card-img-top" src="#Html.DisplayFor(model => element.big_image_url)">
<div class="card-body p-0 m-0">
<h5 class="card-title p-0 m-0 text-center">#Html.DisplayFor(model => element.name)</h5>
<p class="card-text p-0 m-0">DMG/LVL: #Html.DisplayFor(model => element.attackdamageperlevel)</p>
<p class="card-text p-0 m-0">ARMOR/LVL: #Html.DisplayFor(model => element.armorperlevel)</p>
<p class="card-text p-0 m-0">MOVEMENT SPEED: #Html.DisplayFor(model => element.movespeed)</p>
<p class="card-text p-0 m-0">ATTACK RANGE: #Html.DisplayFor(model => element.attackrange)</p>
<a href="/Home/Details"
class="btn btn-primary m-1 "
OnClick="GreetingBtn_Click">More details</a>
</div>
</div>
</div>
}
</div>
</fieldset>
Index View
#model LeagueAPI.Models.IndexModelView
#Html.Action("_SearchEngine", Model.Searcher)
#Html.Action("_Champions", Model.ChampionsList)
Everything else looks standard, in _Layout i have #RenderBody()
My second question is about _Champions Controller. Why when i put IndexModelView indexModelView = new IndexModelView() as parametr and bring necessary changes in code to this ActionResult, the MainSelector is null in that case.
Im still learning, if You can explain whats wrong here i will be thankful. cheers
Try this java Script:-
<script>
function printContent(el){
var restorepage = document.body.innerHTML;
var printcontent = document.getElementById(el).innerHTML;
document.body.innerHTML = printcontent;
window.print();
document.body.innerHTML = restorepage;
}
</script>
I would say instead of ActionResults rather use PartialViewResult on both actions _Champions and _SearchEngine
[HttpPost]
public PartialViewResult _Champions(SearchLeagueModel searchLeagueModel)
{
return PartialView("_Champions", champions);
}
And then from the index view Render those action like below:
#model LeagueAPI.Models.IndexModelView
<div>
#Html.RenderAction("_Champions");
#Html.RenderAction("_SearchEngine");
</div>

Getting some property of an ajax success data and binding it to the view

I have the following:
public class CarModelList
{
public CarModel CarsSea { get; set; }
public CarModel CarsAir { get; set; }
public CarModel CarsSoil { get; set; }
}
The CarModel is as follows:
public class CarModel
{
public long Id { get; set; }
public string Color { get; set; }
public List<SelectItem> ColorList { get; set; }
public string Seats { get; set; }
public string Model { get; set; }
public string Year { get; set; }
}
Upon clicking on some check box, a new CarModel, CarsAir, is added to CarModelList. This is done using an ajax call:
var obj = $('#form0').serialize();
var jsonObj = #Html.Raw(Json.Encode(Model))
console.log(jsonObj);
$.ajax({
url: "#Url.Action("AddAirModel", "Quote")",
//contentType: "application/json",
data: jsonObj,
dataType: "json",
type: "POST",
success: function (data, textStatus, jqXHR) {
//data.appendTo("#AirQuote");
console.log(data.language);
$("#AirQuote").show();
},
error: function (jqXHR, statusText, errorText) {
alert('Error: ' + errorText)
}
My action in the Controller is :
[HttpPost]
public ActionResult AddAirModel(CarModelList listCars)
{
listCars.CarsAir = new CarModel();
listCars.CarsAir.TypeOfService = "3";
ConfigureViewModel(listCars.CarsAir);
return Json(new { data = listCars }, JsonRequestBehavior.AllowGet);
}
This correctly add initializes the new CarsAir in the CarModelList and return the CarModelList listCars in the data.
However I now want to bind the CarsAir to the view. I have the following:
if (Model.QuoteModelAir != null)
{
<div id="AirQuote">
<div>
#Html.LabelFor(model => model.QuoteModelAir.Seats)
#Html.EditorFor(model => model.QuoteModelAir.Seats)
</div>
....so on for all the properties of CarsAir.
</div>
}
So how do I bind the data.CarsAir from the ajax results to the view?

Model Binding with Pagination

I have a PagingInfo class that I use to pass information to my controller for pagination functions:
public int TotalItems { get; set; }
public int ItemsPerPage { get; set; }
public int CurrentPage { get; set; }
public int TotalPages => (int)Math.Ceiling((decimal)TotalItems / ItemsPerPage);
The pagination buttons are rendered in my View via:
<div page-model="Model.PagingInfo" page-action="SearchResult" page-classes-enabled="true" page-class="btn" page-class-selected="btn-primary" class="btn-group pull-right m-1"></div>
as this incorporates a custom tag helper:
[HtmlTargetElement("div", Attributes = "page-model")]
public class PageLinkTagHelper : TagHelper
{
private IUrlHelperFactory urlHelperFactory;
public PageLinkTagHelper(IUrlHelperFactory helperFactory)
{
urlHelperFactory = helperFactory;
}
[ViewContext]
[HtmlAttributeNotBound]
public ViewContext ViewContext { get; set; }
public PagingInfo PageModel { get; set; }
public string PageAction { get; set; }
public bool PageClassesEnabled { get; set; } = false;
public string PageClass { get; set; }
public string PageClassNormal { get; set; }
public string PageClassSelected { get; set; }
public override void Process(TagHelperContext context,
TagHelperOutput output)
{
IUrlHelper urlHelper = urlHelperFactory.GetUrlHelper(ViewContext);
TagBuilder result = new TagBuilder("div");
for (int i = 1; i <= PageModel.TotalPages; i++)
{
TagBuilder tag = new TagBuilder("a");
tag.Attributes["href"] = urlHelper.Action(PageAction,
new { listPage = i });
if (PageClassesEnabled)
{
tag.AddCssClass(PageClass);
tag.AddCssClass(i == PageModel.CurrentPage
? PageClassSelected : PageClassNormal);
}
tag.InnerHtml.Append(i.ToString());
result.InnerHtml.AppendHtml(tag);
}
output.Content.AppendHtml(result.InnerHtml);
}
}
Also within my View, I bind specific model elements needed to filter the items displayed for pagination such as
<input hidden asp-for="#Model.SearchTerms.FormID" class="form-control" />
This is all wrapped in <form> tags. However, when I click the pagination buttons, no model binding occurs.
I can get model binding to happen if I instead change the <div> tags to <button> tags, like below:
<button page-model="Model.PagingInfo" page-action="SearchResult" page-classes-enabled="true" page-class="btn" page-class-selected="btn-primary" class="btn-group pull-right m-1"></button>
However, this then messes up the pagination button display making it unusable (same goes for <a> tags). Is there a way to bind my model within a <div> element?

Property get always null value in mvc4

I am working with c# and ASP.NET MVC4. I have a model class
public class Category {
private Category _parent;
public int Id { get; private set; }
public string Name { get; set; }
public int ParentId { get; private set; }
public Category Parent {
get {
if (this._parent == null) {
_parent = new Category(this.ParentId);
}
return _parent;
}
set {
_parent = value;
}
}
}
In the View I have a text input and a dropdown list for selecting the name and parent category:
<input type="text" placeholder="product name" class="form-control" name="name">
#Html.DropDownList("category", new SelectList(ViewBag.Category, "Id", "Name"), new { #class = "form-control" })
When I submit the form to the following Controller Action:
[HttpPost]
public ActionResult AddCategory(string category_NA, Category category_Parent)
{
................
}
I always get the category_Parent as null.
Can anyone help with this please? Thanks.

Categories