I have a farily straight forward form that renders personal data as a partial view in the center of the form. I can not get client side validation to work on this form.
I started chasing down the generate html and came up with the same model field rendered on a standard form and a partial view.
I noticed that the input elements are correctly populated on the first call, #html.partial, the following only happens when the partialview is reloaded via an ajax request.
First the header of my partial view, this is within a Ajax.BeginForm on the main page.
#model MvcMPAPool.ViewModels.EventRegistration
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function ()
{
$(".phoneMask").mask("(999) 999-9999");
});
</script>
#{
var nPhn = 0;
var dTotal = 0.0D;
var ajaxOpts = new AjaxOptions{ HttpMethod="Post", UpdateTargetId="idRegistrationSummary", OnSuccess="PostOnSuccess" };
Html.EnableClientValidation( true );
Html.EnableUnobtrusiveJavaScript( true );
}
Here is the razor markup from the partial view:
#Html.ValidationMessageFor(model=>Model.Player.Person.Addresses[0].PostalCode)
<table>
<tr>
<td style="width:200px;">City*</td>
<td>State</td>
<td>Zip/Postal Code</td>
</tr>
<tr>
<td>#Html.TextBoxFor(p=>Model.Player.Person.Addresses[0].CityName, new { style="width:200px;", maxlength=50 })</td>
<td>
#Html.DropDownListFor(p=> Model.Player.Person.Addresses[0].StateCode
, MPAUtils.GetStateList(Model.Player.Person.Addresses[0].StateCode))</td>
<td>
<div class="editor-field">
#Html.TextBoxFor(p=>Model.Player.Person.Addresses[0].PostalCode, new { style="width:80px;", maxlength=10 })
</div>
</td>
</tr>
</table>
Here is the rendered field from the partial view:
<td>
<div class="editor-field">
<input id="Player_Person_Addresses_0__PostalCode" maxlength="10" name="Player.Person.Addresses[0].PostalCode" style="width:80px;" type="text" value="" />
</div>
</td>
Here is the same model field rendered in a standard view:
<div class="editor-field">
<input data-val="true" data-val-length="The field Postal/Zip Code must be a string with a maximum length of 10." data-val-length-max="10" data-val-required="Postal or Zip code must be provided!" id="Person_Addresses_0__PostalCode" maxlength="10" name="Person.Addresses[0].PostalCode" title="Postal/Zip Code is required" type="text" value="" />
<span class="field-validation-valid" data-valmsg-for="Person.Addresses[0].PostalCode" data-valmsg-replace="true"></span>
</div>
Notice that the partial view rendering has no data-val-xxx attributes on the input element.
Is this correct? I do not see how the client side validation could work without these attributes, or am I missing something basic here?
In order to create the unobtrusive validation attributes, a FormContext must exist. Add the following at the top of your partial view:
if (this.ViewContext.FormContext == null)
{
this.ViewContext.FormContext = new FormContext();
}
If you want the data validation tags to be there, you need to be in a FormContext. Hence, if you're dynamically generating parts of your form, you need to include the following line in your partial view:
#{ if(ViewContext.FormContext == null) {ViewContext.FormContext = new FormContext(); }}
You then need to make sure you dynamically rebind your unobtrusive validation each time you add/remove items:
$("#form").removeData("validator");
$("#form").removeData("unobtrusiveValidation");
$.validator.unobtrusive.parse("#form");
Related
Hey Guys Am trying to update the jsp page by using ajax response here my issue is
i have one dropdown ,It contains some values ,each value is associated with the some certain data,if i select one value from dropdown then i'll get the corresponding data on the jsp page ,If i try to select Another value from dropdown ,then jsp page contains the old as well as new data ,But actually i want new data ,once new data comes old data on jsp page shouls vanishes out from the page
here my ajax call code is
function getSubjects(sectionId) {
$.ajax({
type : 'get',
url : approoturl+'/admin/section/subjects?sectionId='+sectionId,
success : function(response) {
var table = $('<table class="table table-bordered"/>').appendTo($('#somediv'))
.append($('<th/>').text("Subject Name"))
.append($('<th/>').text("Language"))
.append($('<th/>').text("Subject ID"))
$(response).each(function(i, response) {
$('<tr/>').appendTo(table)
.append($('<td/>').text(response.name))
.append($('<td/>').text(response.language))
.append($('<td/>').text(response.id));
});
}
});
}
</script>
and my jsp page is
<div id="form-group-section-id"
class="form-group col-md-4 col-md-offset-4">
<label class="control-label">Choose Class</label>
<form:select cssClass="form-control" path="section.id"
onchange="getSubjects(value);">
<form:option value="${-1}">Select Class</form:option>
<c:forEach items="${sections}" var="section">
<form:option value="${section.id}">${section.name}</form:option>
</c:forEach>
</form:select>
<div class="text-danger">
<form:errors path="section.id" />
</div>
</div>
<div id="somediv"></div>
Please give me some tips to remove old data and populate new data to particular div "somediv"
any help would be greatfull
You can clear the div before appending.
$('#somediv').empty();
Or
$('#somediv').html("");
I have the following index view:
#model BoringStore.ViewModels.ProductIndexViewModel
#{
ViewBag.Title = "Index";
}
<h2>Produkte</h2>
<div id='addProduct'>
#{ Html.RenderPartial("Create", new BoringStore.Models.Product()); }
</div>
<div id='productList'>
#{ Html.RenderPartial("ProductListControl", Model.Products); }
</div>
The "productList" is just a list of all products.
The addProduct renders my Create View:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<div id="dialog-confirm" title="Produkt hinzufügen" style="display:none">
#using (Ajax.BeginForm("Index_AddItem", new AjaxOptions { UpdateTargetId = "productList" }))
{
#Html.Raw(DateTime.Now.ToString());
<div>
#Html.LabelFor(model => model.Name)
#Html.EditorFor(model => model.Name)
</div>
<br />
<div>
#Html.LabelFor(model => model.Price)
#Html.EditorFor(model => model.Price)
</div>
<br /><br />
<div>
<input type="submit" value="Produkt hinzufügen" />
</div>
}
When submitting the form, the Index_AddItem-method in my controller is called. Unfortunately the form always calls the method twice. :(
Can someone help me out?
Don't include scripts inside your partial views! They should go the your "main" views or your _layout.cshtml.
Your problem is that you have included the jquery.unobtrusive-ajax.min.js twice in your page. Once in your Create partial and once somewhere else. Because if you include that script multiple times it will subscribe on the submit event multiple times so you will get multiple submit with a single click.
So make sure that you have include that script only once in a page. So move the jquery.unobtrusive-ajax.min.js reference into your index view.
insure that you dont have jquery.unobtrusive-ajax.min.js file duplicated in the layout
as mentioned above, and you can check this using browser Inspectors
Another problem which may cause this error that i have encountered is resting a form using jquery in the ajax request as following
$("form").trigger("reset"); //just remove this line
Is this possible to use Ajax.Beginform with update target inside of ajax form. like this:
using(Ajax.BeginForm("EditPhone", new { id = item.Id.Value }, new AjaxOptions {
UpdateTargetId = "TRTarget"})) {
<tr class="gradeA odd" id="TRTarget">
<input type"submit" value="submit" />
</tr>
}
Update
OK if it's possible so what is wrong with this?
This is my partial view that another partial view rendered inside it:
using(Ajax.BeginForm("EditPhone", new { id = item.Id.Value }, new AjaxOptions {
UpdateTargetId = "TRTarget"})) {
<tr class="gradeA odd" id="TRTarget">
#{Html.RenderPartial("_PhoneRow", item);}
</tr>
}
and _PhoneRow:
#model MyModel
<td>#Html.DisplayFor(model=>model.Number)</td>
<td>#Html.DisplayFor(modelItem => Model.PhoneKind)</td>
<td><input type="submit" value="Edit" class="button" /></td>
And EditPhone Action:
public ActionResult EditPhone(long Id){
//Get model
return PartialView("_EditPhoneRow", model);
}
And _EditPhoneRow:
<td>#Html.EditorFor(model => model.MainModel.Number)</td>
<td>#Html.EditorFor(model => model.MainModel.PhoneKind)</td>
<td><input type="submit" value="Save" class="button" /></td>
Actually each of my rows have an Ajax form so when click on edit I want to replace the row with another as you see, but when I add the Edit, all of my page destroyed and just _EditPhoneRow shown like I select all page for updateTrget where is the problem? and what is your suggestion to change all the specific row like this?
According to the HTML specification forms cannot be nested. This produces invalid HTML and depending on the user agent either the outer or the inner <form> simply won't work. That's a limitation of the HTML specification, don't be confused with ASP.NET MVC, it has nothing to do with it. One possibility is to replace your Ajax.BeginForm with an Ajax.ActionLink:
<tr class="gradeA odd" id="TRTarget">
#Ajax.ActionLink(
"Submit",
"EditPhone",
new { id = item.Id.Value },
new AjaxOptions { UpdateTargetId = "TRTarget" }
)
</tr>
UPDATE:
After you have updated your question and explained the symptoms I think you might have forgotten to reference the jquery.unobtrusive-ajax.min.js script to your page:
<script type="text/javascript" src="#Url.Content("~/scripts/jquery.unobtrusive-ajax.min.js")"></script>
If you don't include this script the Ajax.* helpers such as Ajax.BeginForm and Ajax.ActionLink will be simple HTML forms and anchors. No AJAX at all. It is this script that reads the HTML5 data-* attributes emitted by those helpers and unobtrusively AJAXifies them.
I'm using this tutorial at the moment.
(I believe my issue is related to strongly typed collections... by what I've been seeing on the internet, but I could be wrong)
Please bear with me. :)
I've been having this issue which I asked in another question, the answer seemed fine, but after tinkering with the code a bit more I realized that the issue is that the fields that make use of my custom partial view, don't get a prefix added to them like the fields that use a TextBoxFor html helper, for example. EG. When I click on add a new item, it adds it, but with the same ID as an item that's been added before, then my Javascript fails because there's two items with the same id.
Some code to try and clarify the issue
Partial View
#model Portal.ViewModels.Micros
#using Portal.Helpers
<div class="editorRow" style="padding-left:5px">
#using (Html.BeginCollectionItem("micros"))
{
#Html.EditorFor(model => model.Lab_T_ID)
#Html.EditorFor(model => model.Lab_SD_ID)
#Html.TextBoxFor(model => model.Result)
<input type="button" class="deleteRow" title="Delete" value="Delete" />
}
</div>
The TextBoxFor (Result) gets rendered as
<input id="micros_5e14bae5-df1b-4c42-9e96-573a8e52f8b2__Result" name="micros[5e14bae5-df1b-4c42-9e96-573a8e52f8b2].Result" type="text" value="">
Editor For get rendered as
<select id="Lab_SD_ID" multiple="multiple" style="width: 300px; display: none; " >
<option value="5" selected="selected">Taken at Packing 1</option>
<option value="6">Taken at Packing 2</option>
<option value="7">Taken at Packing 3</option>
</select>
<button type="button" class="ui-multiselect ui-widget ui-state-default ui-corner-all" aria-haspopup="true" tabindex="0" style="width: 300px; ">
<span class="ui-icon ui-icon-triangle-2-n-s"></span><span>Taken at Packing (Winc 4/5-25d)</span></button>
I can include more code if its needed, there is a helper class as well (BeginCollectionItem), that I used which is located in the demo project in the tutorial as well.
I basically need to find out how "micros[5e14bae5-df1b-4c42-9e96-573a8e52f8b2]." gets appended to the input boxes as far as I can see, but have been stumped by it so far :/
The reason this works with TextBoxFor and not your custom EditorFor is because the TextBoxFor helper respects the template navigational context whereas in your editor template you have simply hardcoded a <select> element that doesn't even have a name. I would recommend you to use HTML helpers when generating input fields:
So replace your hardcoded select in the custom template with:
#model int?
#{
var values = ViewData.ModelMetadata.AdditionalValues;
}
<span>
#Html.DropDownList(
"",
Enumerable.Empty<SelectListItem>(),
new {
multiple = "multiple",
style = "width:" + values["comboboxWidth"] + "px",
data_url = Url.Action((string)values["action"], (string)values["controller"]),
data_noneselectedtext = values["noneSelectedText"],
data_value = values["id"],
data_text = values["description"]
}
)
</span>
I am loading a partial view in the popup using following code:
<div id="Mydiv" title="Modify" class="ModifyRule" style="overflow: hidden" />
<script type="text/javascript">
$(document).ready(function () {
//define config object
var dialogOpts = {
title: "Modify Rule",
modal: true,
autoOpen: false,
height: 300,
width: 700,
open: function () {
//display correct dialog content
$("#Mydiv").load("Modify", { SelectedRow: $('#MyParam').val() });
}
};
$("#Mydiv").dialog(dialogOpts); //end dialog
$('#Modify').click(
function () {
$("#Mydiv").dialog("open");
return false;
}
);
});
</script>
Here is the code from partial view:
#Code
Using (Html.BeginForm())
#<div id="Master">
<table>
<tr>
<td>
#Html.LabelFor(Function(model) model.InputAuthorityGridDetail.TcmAccount)
</td>
<td>#Html.EditorFor(Function(model) model.InputAuthorityGridDetail.TcmAccount)
</td>
<td>
#Html.LabelFor(Function(model) model.InputAuthorityGridDetail.Amount)
</td>
<td>#Html.EditorFor(Function(model) model.InputAuthorityGridDetail.Amount)
</td>
</tr>
<tr align="right">
<td>
<input name="button" type="submit" value="Save" class="btn" />
</td>
</tr>
</table>
</div>
End Using
End Code
the controller method modify returns a partial view named _Modify, the view is rendered correctly in the popup but I notice that the CSS styles are not applied to the controls in the partial view can someone help me?
When a partial is loaded into a layout page, the layout page contain the reference to the css that is used by the partial view.
However, from what I gather here (my javascript is not that great), you are loading the partial directly into a popup display and not using the layout page? If this is correct then your partial will not know about the css. And to correct this you would need to add a reference to the css at the top of the partial.
My partial views dont start with #Code and dont end with End Code. Try removing them and see if it works then.