mvc radiobuttonfor in editortemplate keyboard navigation does not set model - asp.net-mvc

Context:
Model generating some RadioButtonFor groupings as input to answer questions.
What is happening:
Case 1. When mouse click on a radio option the display looks correct. When the [HttpPost] ActionResult(model) for the page is triggered the Model.Answer comes through with the correct value. Which is good and desired.
Case 2. When navigating with the keyboard to the radio group and selecting one with arrow keys the display looks correct. But when the [HttpPost] ActionResult (model) is triggered the Model.Answer value is unchanged from what it was loaded as on page load.
Here is the code that makes the radio group:
#model NexusPWI.ViewModels.Wizard.QuestionModel
#* Dynamically generate and model bind controls for QuestionModel *#
#{
<div class="row d-contents">
<div class="form-group">
<div class="question">
<div class="col-lg-2 d-contents">
<div class="btn-group btn-toggle group-sm d-contents" data-toggle="buttons">
<label class="btn QuestionRadio btn-default #(Model.Answer == YesNoNAOptions.Yes ? "active" : "")" for="#Model.Answer">
#YesNoNAOptions.Yes.ToString().ToUpper()
#Html.RadioButtonFor(Model => Model.Answer, YesNoNAOptions.Yes, new { #onfocus = "radiofocus(event)", #onblur = "radioblur(event)" })
</label>
<label class="btn QuestionRadio btn-default #(Model.Answer == YesNoNAOptions.No ? "active" : "")" for="#Model.Answer">
#YesNoNAOptions.No.ToString().ToUpper()
#Html.RadioButtonFor(Model => Model.Answer, YesNoNAOptions.No, new { #onfocus = "radiofocus(event)", #onblur = "radioblur(event)" })
</label>
#if (!Model.NaInvalid)
{
<label class="btn QuestionRadio btn-default #(Model.Answer == YesNoNAOptions.NA ? "active" : "")" for="#Model.Answer">
N/A
#Html.RadioButtonFor(Model => Model.Answer, YesNoNAOptions.NA, new { #onfocus = "radiofocus(event)", #onblur = "radioblur(event)" })
</label>
}
</div>
</div>
<div class="col-lg-9 d-contents">
<div class="row">
<p>
<strong>#Model.Question</strong>
</p>
</div>
#Html.HiddenFor(x => Model.Question_IdentityMarker, new { #class = "Question_IdentityMarker" })
</div>
</div>
</div>
</div>
}
Here is an example of the html that is generated:
<div class="form-group">
<div class="question">
<div class="col-lg-2 d-contents">
<div class="btn-group btn-toggle group-sm d-contents" data-toggle="buttons">
<label class="btn QuestionRadio btn-default " for="No">
YES
<input data-val="true" data-val-required="The Answer field is required." id="Questions_0__Answer" name="Questions[0].Answer" onblur="radioblur(event)" onfocus="radiofocus(event)" value="Yes" type="radio">
</label>
<label class="btn QuestionRadio btn-default active" for="No">
NO
<input checked="checked" id="Questions_0__Answer" name="Questions[0].Answer" onblur="radioblur(event)" onfocus="radiofocus(event)" value="No" type="radio">
</label>
<label class="btn QuestionRadio btn-default " for="No">
N/A
<input id="Questions_0__Answer" name="Questions[0].Answer" onblur="radioblur(event)" onfocus="radiofocus(event)" value="NA" type="radio">
</label>
</div>
</div>
<div class="col-lg-9 d-contents">
<div class="row">
<p>
<strong>Do you charge sales tax?</strong>
</p>
</div>
<input class="Question_IdentityMarker" id="Questions_0__Question_IdentityMarker" name="Questions[0].Question_IdentityMarker" value="CUSTOMERSALESTAX" type="hidden">
</div>
</div>
</div>
EDIT Adding onFocus & onBlur at request:
onFocus & onBlur are css highlighting for the keyboard navigation to make it more clear for the user where they are in the page.
function radiofocus(event) {
// Get event object if using Internet Explorer
var e = event || window.event;
// Check the object for W3C DOM event object, if not use IE event object to update the class of the parent element
if (e.target) {
var addClass = focusClass(e.target.parentNode.parentNode.parentNode.parentNode.parentNode.className, "r");
e.target.parentNode.parentNode.parentNode.parentNode.parentNode.className = addClass;
} else {
var addClass = focusClass(e.srcElement.parentNode.parentNode.parentNode.parentNode.parentNode.className, "r");
e.srcElement.parentNode.parentNode.parentNode.parentNode.parentNode.className = addClass;
}
};
function radioblur(event) {
// Get event object if using Internet Explorer
var e = event || window.event;
var removeClass = focusClass("", "r").trim();
// Check the object for W3C DOM event object, if not use IE event object to update the class of the parent element
if (e.target) {
e.target.parentNode.parentNode.parentNode.parentNode.parentNode.className = e.target.parentNode.parentNode.parentNode.parentNode.parentNode.className.replace(removeClass, "");
} else {
e.srcElement.parentNode.parentNode.parentNode.parentNode.parentNode.className = e.srcElement.parentNode.parentNode.parentNode.parentNode.parentNode.className.replace(removeClass, "");
}
};
Why do the keyboard navigated changes not get back to the controller?
Anything to add to make this clearer?
Side note: For some reason before a value is chosen in the radio group the keyboard tab navigation is stopping for each radio answer for a question.

Related

how to add the placeholder value to ngmodel

I am following an example in primeng in which I can add a new row to a table. Everything "seems" to work as long as I fill out all the fields in the input option. However, I want to add the place holder value to the NGmodel if the user does not change the value of the input. I tried everything (ng-init, ngvalue, etc etc) but I can never get the ngmodel to carry the value in the place holder... and the table gets fill with the 3 filled fields but not the one where the user did not type anything.
extract of the HTML....
<div class="ui-g-12">
<div class="ui-g-4">
<label for="product_line_id">Product ID</label>
</div>
<div class="ui-g-8">
<input pInputText id="product_line_id" [ngModel]="myproduct.product_line_id" placeholder="{{ lastproductline + 1}}" />
</div>
</div>
<div class="ui-g-12">
<div class="ui-g-4">
<label for="product_line_1">Product</label>
</div>
<div class="ui-g-8">
<input pInputText id="product_line_1" [(ngModel)]="myproduct.product_line_1" autofocus />
</div>
</div>
<div class="ui-g-12">
<div class="ui-g-4">
<label for="product_line_2">Category</label>
</div>
<div class="ui-g-8">
<input pInputText id="product_line_2" [(ngModel)]="myproduct.product_line_2" />
</div>
</div>
<div class="ui-g-12">
<div class="ui-g-4">
<label for="product_line_3">Sub Category</label>
</div>
<div class="ui-g-8">
<input pInputText id="product_line_3" [(ngModel)]="myproduct.product_line_3" />
</div>
</div>
the ts file looks something like...
productlines = [];
myproduct: { [s: string]: ProductLines; } = {};
showDialogToAdd() {
this.newProductLine = true;
this.myproduct = {};
this.displayDialog = true;
}
save() {
let productlines = [...this.productlines];
productlines.push(this.myproduct);
this.finalproductchanges.push(this.myproduct)
this.productlinesClone = productlines;
this.myproduct = null;
this.displayDialog = false;
}
Any ideas will be greatly appreciated
I managed to change the code by adding the field directly in the controller.

Edit action in controller not updating

When I edit an item and return to the index view the item doesn't show what I updated it to.
I think I know what the problem is but not sure how to fix it. In my service class I have a CreateEditItem method and when I step thru the code it hits the if condition <=0. So it acts like there is an id of 0 when I click the submit button to submit my update. I'm not sure what to do to fix this. Do I need to have a separate method for Edit? And if so what should that look like?
public bool CreateEditItem(Item item)
{
if (item.ItemId <= 0)
{
var maxId = _mockList.Max(p => p.ItemId);
item.ItemId = maxId + 1;
_mockList.Add(item);
return true;
}
var itemToEdit = _mockList.FirstOrDefault(p => p.ItemId ==
item.ItemId);
itemToEdit = item;
return true;
}
Action in Controller
[HttpPost]
public IActionResult EditItem(Item itemToEdit)
{
_itemService.CreateEditItem(itemToEdit);
return RedirectToAction(nameof(Index), new { id =
itemToEdit.ItemId });
}
View:
<div class="row">
<form asp-action="EditItem">
<div asp-validation-summary="ModelOnly" class="text-
danger"></div>
<div class="container form-group">
<div class="row">
<div class="col-md-2">As Of : <label
for="AsOf" /></div>
<div class="col-md-4"><input id="AsOf"
value="#Model.ItemToEdit.AsOf" name="AsOf" type="date" /></div>
</div>
<br />
<div class="row">
<div class="col-md-2">Title Summary : <label
for="TitleSummary" /></div>
<div class="col-md-2"><input id="TitleSummary"
value="#Model.ItemToEdit.Title" name="Title" type="text" /></div>
</div>
<br />
<br />
<div class="row">
<div class="col-md-2"><input type="submit"
value="Submit" class="btn btn-primary" /></div>
</div>
</div>
</form>
</div>
I expect when I click the submit button to submit my update it will show the updated Title and/or AsOf date.
change your method from HTTPut to HttpPost
it will work.

Concatenation of strings in Razor MVC 5 for "class" attribute

I'm building an ASP.NET MVC 5 application for a local inventory. This app shows items on a page with buttons to deliver the items.
I want the "Scarica" buttons to be greyed-out when items are not available, so I thought I could just delete the btn-info attribute and that should've done the trick, so I changed the relevant lines of code in the view from this
<div class="col-sm-2">
#using (Html.BeginForm("ScaricaItem", "Scarico"))
{
string Disabilitato = "";
if (i.Qty == 0)
{
Disabilitato += "disabled";
}
<div class="pull-right">
#Html.HiddenFor(x => #i.Item.Modello)
#Html.Hidden("returnUrl", Request.Url.PathAndQuery)
<input type="submit" class="btn btn-info" value="Scarica" #Disabilitato />
</div>
}
</div>
to this:
<div class="col-sm-2">
#using (Html.BeginForm("ScaricaItem", "Scarico"))
{
string Disabilitato = "";
string Classe = "";
if (i.Qty == 0)
{
Disabilitato += "disabled";
Classe = "btn";
}
else
{
Classe = "btn btn-info";
}
<div class="pull-right">
#Html.HiddenFor(x => #i.Item.Modello)
#Html.Hidden("returnUrl", Request.Url.PathAndQuery)
<input type="submit" class=#Classe value="Scarica" #Disabilitato />
</div>
}
</div>
but now I have all the buttons greyed-out because the btn-info attribute value is treated as if it was an attribute itself
<input type="submit" class="btn" btn-info="" value="Scarica">
I also tried
<input type="submit" class=#(Classe) value="Scarica" #Disabilitato />
and
<input type="submit" class=#(String.Format("{0}", Classe)) value="Scarica" #Disabilitato />
but nothing changes.
Thanks,
Davide.

Show or Hide History in MVC

I am working on a registration form. I want to show and hide my users past registrations using a button.The button should only show or hide registrations that are gone not the upcoming ones This is what I have so far. Pleasssseeee Help.
<div class="Table01">
<button id="older">Show Registration History</button>
#foreach (var sm in Model)
{
var tmp = #sm.SeminarNm.Replace("&", "and");
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-12 well table-item" align="left" data-toggle="tooltip" data-eventtype="#tmp" data-placement="top" title="#tmp">
<span class="sortName mid-weight"> #sm.SeminarNm</span>
<span class="sortDate alert-info">(ON #string.Format("{0:yyyy-MM-dd}", #sm.SessionStartDT) IN #sm.SessionCityNm)</span>
<div class="row " style="margin-top:10px">
#if (#sm.IsEditable == "Y")
{
using (Html.BeginForm("EditRegister", "App", FormMethod.Post, new { onclick = "showPageLoadingSpinner()" }))
{ #Html.AntiForgeryToken()
<div class="col-xs-12 col-md-6 col-lg-6">
<input class="btn btn-success " name="submitButton" type="submit" value="Edit" />
<input type="hidden" value="#sm.RegistrantSeq" name="hiddenseq" />
<input type="hidden" value="0" name="cntView" />
<input type="hidden" value="EditRegister" name="cntStage" />
</div>
}
}
#using (Html.BeginForm("ViewRegister", "App", FormMethod.Post))
{ #Html.AntiForgeryToken()
<div class="col-xs-12 col-md-6 col-lg-6 col">
<input class="btn btn-info" name="submitButton" type="submit" value="View" />
<input type="hidden" value="#sm.RegistrantSeq" name="hiddenseq" />
<input type="hidden" value="ViewRegister" name="cntStage" />
</div>
}
//
</div>
}
</div>
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
<script>
var $btns = $('.btn').click(function () {
if (this.id == 'older') {
$('#child > div').toggle(450);
}
$btns.removeClass('active');
$(this).addClass('active');
})
</script>
My Program Pic
I dont know if I need some sorting javascript function to display only those sessions that are in the past. Nothing seems to be working.
Assuming old registrations are any item with SessionStartDT value earlier than current date, you can set an html data attribute on each item's container div indicating whether it is an old item or new item and when user clicks the hide/show button, toggle the visibility of these items.
#foreach (var sm in Model)
{
<div data-old="#(p.SessionStartDT.Date < DateTime.Today.Date)">
<!-- your existing code for rendering each item goes here -->
</div>
}
And in the javascript part, when the button is clicked, make select the elements who's data-old attribute value is True (which we set via our C# expression which results in a boolean value) and toggle the visibility.
$(document).ready(function() {
$("#older").click(function(e) {
e.preventDefault();
$("[data-old='True']").toggle();
});
});

I need to call a controller by passing the param from the view on clicking the ActionLink

I am trying to search a student and display the student record based on the value entered on textbox. I am not sure how to pass the value without using Jquery. Is there a way.
Controller:
[Authorize]
public ActionResult GetStudentsByName(string name)
{
SchoolDbEntities db = new SchoolDbEntities();
var student = db.Students.Where(s => s.StudentName.Contains(name));
return View(student);
}
View
<div class="panel-body">
<div class="form-group">
#Html.LabelFor(m=> m.SearchEntity.StudentName,"Search Student")
#Html.TextBoxFor(m => m.SearchEntity.StudentName, new { #class = "form-control" })
</div>
</div>
<div class="panel-footer">
<button type="button" onclick="location.href='#Url.Action("GetStudentsByName", "Student")'" class="btn btn-primary">Search <i class="glyphicon glyphicon-search"></i></button>
<button id="Reset"
class="btn btn-primary btn-sm">
<i class="glyphicon glyphicon-share-alt"></i> Reset
</button>
</div>
I need to pass the param , In the #Url.Action("GetStudentsByName", "Student", new {#name= 'value from the textbox')
Also it is a Get Method and not httpPost.
You can keep the input form element inside a form control and submit the form via GET method.
Make sure the input element name matches with your action method parameter name
#using (Html.BeginForm("GetStudentsByName","Student",FormMethod.Get))
{
<input type="text" name="name"/>
<button type="submit" class="btn btn-primary">Search </button>
}
If you dont wanna make the button a submit button then by giving your text box a specific class you can do it .
<div class="panel-body">
<div class="form-group">
#Html.LabelFor(m=> m.SearchEntity.StudentName,"Search Student")
#Html.TextBoxFor(m => m.SearchEntity.StudentName, new { #class = "form-control,txt-input" })
</div>
</div>
<div class="panel-footer">
<button type="button" onclick="location.href='#Url.Action("GetStudentsByName", "Student",new { data= "STUDENT_NAME" })'.replace("STUDENT_NAME", $('.txt-input').val())" class="btn btn-primary">Search <i class="glyphicon glyphicon-search"></i></button>
<button id="Reset"
class="btn btn-primary btn-sm">
<i class="glyphicon glyphicon-share-alt"></i> Reset
</button>
</div>
I tried something like this long back , i think it should work.
Try this
View
#using (Html.BeginForm("GetStudentsByName", "Home"))
{
<div class="form-group">
#Html.LabelFor(m => m.StudentName, "Search Student")
#Html.TextBoxFor(m => m.StudentName, new { #class = "form-control" })
</div>
<input type="submit" value="Search" class="btn btn-primary" />
}
</div>
Controller
public ActionResult GetStudentsByName()
{
string name = Request.Form["StudentName"]
SchoolDbEntities db = new SchoolDbEntities();
var student = db.Students.Where(s => s.StudentName.Contains(name));
return View(student);
}
using Request.Form["StudentName"] you can access the value from view to controller. Also, one more suggestion, use using statement it helps to manage unhandled memory. For example
public ActionResult GetStudentsByName()
{
string name = Request.Form["StudentName"]
using(SchoolDbEntities db = new SchoolDbEntities())
{
var student = db.Students.Where(s => s.StudentName.Contains(name));
return View(student);
}
}

Resources