ASP.Net MVC 3 Unobtrusive validation not working on Partial View - asp.net-mvc-3

I've setup a partial view which houses its own form tag, like so:
<tr>
#using (Html.BeginForm("Create"))
{
<td>
#Html.TextBoxFor(model => model.Date)
#Html.ValidationMessageFor(model => model.Date)
</td>
<td>
#Html.TextBoxFor(model => model.Amount)
#Html.ValidationMessageFor(model => model.Amount)
</td>
<td>
#Html.TextBoxFor(model => model.Tags)
#Html.ValidationMessageFor(model => model.Tags)
</td>
<td>
#Html.EnumDropDownListFor(model => model.Type)
</td>
<td>
<input type="submit" value="Add" />
#Html.ValidationSummary(true)
</td>
}
</tr>
I render it on a page using #Html.Action("Create") (It's part of a table, hence the <tr> tags.
For some odd reason my clientside validation isn't working, and I first see the errors upon posting.
Is there something special about partial views and clientside validation ?
I have included the following scripts:
<script src="/Scripts/jquery.1.5.1.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js" type="text/javascript"></script>
EDIT
I just tried tossing this script onto the page:
jQuery('form').submit(function ()
{
alert(jQuery(this).valid());
});
It alerts 'true', so the clientside validation script is definately there, and for some reason it's not checking the fields in question :-/
EDIT 2
I've uploaded the entire source code for the page (the HTML + JS) to pastebin: http://pastebin.com/GvqLW495

Edit:
I just realized, looking at your code, that you're using jQuery 1.5.1 with the (I'm assuming) .NET provided jQuery.validate. Unfortunately, those two do not work together yet. You'll have to head to here to grab a version that works with the latest jQuery (you'll need to use 1.4.4). If that doesn't work, I would still recommend checking out the solution below.
I had a similar problem (although I'm not sure it's the exact same problem). I wrote about the solution in this blog post. Unfortunately, I can't be sure you're having the same exact problem, but it's worth a shot.
Basically, it boiled down to the fact that I had to call this line after loading my PartialViews (although I was loading them via AJAX which is what I think caused the problem):
$.validator.unobtrusive.parse($("#validation"));
See the blog post for more detail. Hopefully it helps you out.

I finally found out what's causing it to fail, it's the fact that my partial view is inside a html table...
<table>
<tr>
<th>
Date
</th>
<th>
Amount
</th>
<th>
Tags
</th>
<th>
Type
</th>
<th>
</th>
</tr>
#Html.Action("Create")
</table>
This doesn't work, however if I move the #Html.Action outside the table tag, it works just fine.

I think that the root of your problem wat the use of illegal html syntax:
<tr> tag can only contain <td> tags.
In most cases structure like your's won't be rendered correcty in browsers, especiallywhen loaded asynchronously.

Related

Angular 2 doesn't update my view after I add or edit item

I've finally made my app in angular 2. Everything is solved, except one thing. When I add item into my table or edited it, I can't see the change until I refresh page or click for example next page button (I have implemented pagination). I included:
<script src="node_modules/systemjs/dist/system-polyfills.js"></script>
<script src="node_modules/angular2/bundles/angular2-polyfills.js"></script>
in this order. My method for adding item is very simple:
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();}
Whhen I add item, and put breakpoint on get method, It is called correctly and I get right information from my DB, but I don't know why view isn't refreshed then. Do you have any idea why is it happened? Thanks for suggestions!
EDIT: department is just department: Department, where Department is interface with properties (departmentNo, departmentName, departmentLocation). The view for adding item looks like:
<form [ngFormModel]="myForm"
(ngSubmit)="addDepartment(newItem); showAddView=false" [hidden]="!showAddView" align="center">
<div>
<label for="editAbrv">Department name:</label><br>
<input type="text" [(ngModel)]="newItem.departmentName" [ngFormControl]="myForm.controls['departmentName']" >
<div *ngIf="myForm.controls['departmentName'].hasError('required')" class="ui error message"><b style="color:red;">Name is required</b></div>
</div>
<br/>
<div>
<label for="editAbrv">Department Location:</label><br>
<input type="text" [(ngModel)]="newItem.departmentLocation" [ngFormControl]="myForm.controls['departmentLocation']" >
<div *ngIf="myForm.controls['departmentLocation'].hasError('required')" class="ui error message"><b style="color:red;">Location is required</b></div>
</div>
<br/>
<div>
<button type="submit" [disabled]="!myForm.valid" class="ui button">Add item</button>
<button><a href="javascript:void(0);" (click)="showHide($event)" >
Cancel
</a></button>
</div>
</form>
and my department table is:
<table align="center">
<thead>
<tr>
<td>#</td>
<td><strong>Department</strong></td>
<td><strong>Department Location</strong></td>
<td><strong>Edit</strong></td>
<td><strong>Delete</strong></td>
</tr>
</thead>
<tbody>
<tr *ngFor="#department of departments | searchString:filter.value ; #i = index">
<td>{{i + 1}}.</td>
<td> {{department.departmentName}}</td>
<td>{{department.departmentLocation}}</td>
<td>
<button class="btnEdit" (click)="showEdit(department)">Edit</button>
</td>
<td>
<button class="btnDelete" (click)="deleteDepartment(department)" >Delete</button>
</td>
</tr>
</tbody>
</table>
With this code, you don't wait for the response of the addDepartment request and execute the getAll request directly.
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();
}
You should move the call to getAll within the callback registered in subscribe. At this moment, the addDepartment is actually done and you can reload the list...
The code could be refactored like this (it's a guess since I haven't the content of addDepartment and getAll methods):
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(addedDepartment => {
this.department = this.getAll();
});
}
This issue occurs because of the way you're using departmant and how change detection works. When you use *ngFor="#department of departments", angular change detection looks for a object reference on departments array. When you update/change one of the items in this array object reference to the array itself doesn't change, so angular doesn't run change detection.
You have few options:
1) change reference of the array by replacing it with new array with updated values
2) tell angular explicitly to run change detection (which I think is easier in your case):
constructor(private _cdRef: ChangeDetectorRef) {...}
addDepartment(item){
this._departmentService.addDepartment(item)
.subscribe(departments => this.department = departments.json());
this.getAll();
this._cdRef.markForCheck();
}

When using AjaxHelper to retrieve a partial view, the embedded data is always the same

We use ASP.NET MVC 5's AjaxHelper and Ajax.BeginForm to request a partial view. That request also needs some JSON data in order to update a map control.
The view rendering part of the process works great (a table body is replaced with the strongly-typed partial view), but the JSON data (embedded into the data-json attribute of the div element as described in this answer and retrieved in my OnSuccess function) always has the same value.
To eliminate the controller code or ViewBag as culprit, I replaced the JSON data (originally retrieved from the ViewBag) with a direct call to DateTime.Now. Sure enough, the same DateTime is printed each time in updateMap() (e.g., 2/11/2016+5:24:42+PM)
I've tried disabling caching, and changing the HTML method to Post, in my AjaxOptions.
In the Parent View (changing the ListBox selection submits the form):
#model string
#{
ViewBag.Title = "Project List";
AjaxOptions ajaxOpts = new AjaxOptions
{
UpdateTargetId = "tableBody",
OnSuccess = "updateMap",
HttpMethod = "Post",
AllowCache = false
};
}
#using (Ajax.BeginForm("GetProjectsData", ajaxOpts))
{
<fieldset>
<legend>Project State</legend>
<div class="editor-field">
#Html.ListBox("selectedStates", ViewBag.StatesList as MultiSelectList,
new { #class = "chzn-select", data_placeholder = "Choose States...", style = "width:350px;", onchange = "$(this.form).submit();" })
</div>
</fieldset>
}
<table class="table">
<thead>
<tr>
<th>
Project Name
</th>
<th>
Project Firm
</th>
<th>
Project Location
</th>
<th>
Building Type
</th>
<th>
Project Budget
</th>
<th></th>
</tr>
</thead>
<tbody id="tableBody">
#Html.Action("GetProjectsData", new { selectedStates = Model })
</tbody>
</table>
<script>
function updateMap() {
var jsonData = $("#geoJsonData").attr("data-json");
var decoded = decodeURIComponent(jsonData);
console.log(decoded); // always prints same value
}
</script>
The partial view:
#model IEnumerable<OurModel>
<div id="geoJsonData" data-json="#Url.Encode(DateTime.Now.ToString())"></div>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.NAME)
</td>
<td>
#Html.DisplayFor(modelItem => item.COMPANY_NAME)
</td>
<td>
#Html.DisplayFor(modelItem => item.STATE)
</td>
<td>
#Html.DisplayFor(modelItem => item.BUILDING_TYPE)
</td>
<td>
#Html.DisplayFor(modelItem => item.BUDGET_AMT)
</td>
</tr>
}
I'm hesitant to jettison the MVC helper classes' pattern of returning a partial view and instead manually render a view into a JSON object. Why is the updated tablebody visible on screen, but when jQuery requests the div element it always has the same data?
Interesting...replacing the div with a good old hidden input element worked. Now fresh data is retrieved each time.
This
<div id="geoJsonData" data-json="#Url.Encode(DateTime.Now.ToString())"></div>
Became this
<input id="geoJsonData" type="hidden" value="#Url.Encode(DateTime.Now.ToString())" />
I wonder why the data-json in the div remained "stale" while the value of the input field did the trick?

How to use rowTemplate and detailTemplate together in KendoUI?

I having trouble using a rowtemplate with a detail grid.
Basically when I use them in combination, the rendering is messed up.
See this fiddle, http://jsfiddle.net/yzKqV/, to reproduce this error (uncomment the commented out line and run again to see the error).
How do I fix this?
I think the reason your rowTemplate is not working when you use detailTemplate is because it needs to have the tr and first td defined like a hierarchy grid. (http://jsfiddle.net/yzKqV/3/)
<script id="rowTemplate" type="text/x-kendo-tmpl">
<tr class="k-master-row">
<td class="k-hierarchy-cell"></td>
<td> #= FirstName # </td>
<td> #= LastName # </td>
</tr>
</script>

jQuery selectable list with nested table not sized properly in jQuery tab

I'm implementing a jQuery tab in my MVC3 application, but one of the tabs is not sized properly. That is, some of the content is inside the tab, but the following strange formatting on my part is only partially inside the tab:
<div id="tabs">
<ul>
<li>Edit Schedule</li>
...
</ul>
<div id="tabs-1">
...
<div id = "scheduleData">
#Html.Partial("_partialView", ViewData["data"])
</div>
</div>
...
</div>
My partial view renders many tables, one with just a head, and the rest nested inside a jQuery selectable list:
<table>
<thead>
<tr>
<td>ID</td>
...
</tr>
</thead>
</table>
<ol id="selectable>
#foreach (var obj in Model)
{
<li class="ui-widget-content">
<table>
<tr>
<td>#obj.ID</td>
...
</tr>
</table>
</li>
}
</ol>
I'm not sure whether the tab sizing problem is happening because of the partial view, or my very strange formatting, or both.
It is worth noting that only the first table is inside the tab, and any other tables are consistently not in the tab, no matter how large or small the partial view is.
This is obviously a sloppy solution, and I was wondering if there is a better way to render a table row inside a selectable list so the jQuery tab is sized correctly, such as having all the rows in the first table? (which won't work because you can't nest a selectable list inside a table, to my knowledge) I appreciate your input.
The possibility exists to make a table a selectable item, instead of each row, but due to formatting issues I adopted the following solution instead:
$(document).ready(function () {
$("#scheduleTable tr").click(function () {
var href = $(this).find("a").attr("href");
if (href) {
$("#editDialog").dialog({ modal: true });
}
});
});
The markup then has an edit link in each row, which the Javascript watches, then creates a jQuery dialog box.
<table>
<thead>
<th> </th>
...
</thead>
<tbody>
#foreach (var obj in Model)
{
<tr>
<td>Edit</td>
...
</tr>
}
</tbody>
</table>
<div id="editDialog" title="Edit Entry" style="display:none">
...
</div>

help me ! MVC and AJAX toolkit Editor in ASP.NET

I have view to use Ajax toolkit editor control.
View CreateProduct
<fieldset>
<legend>Product information</legend>
<table align="center">
<tr>
<td><label for="slogan">Slogan:</label></td>
<td><%= Html.TextBox("slogan")%></td>
</tr>
<tr>
<td><label for="content">Content :</label></td>
<td>
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<cc1:Editor ID="content" runat="server" Height="300px" />
</td>
</tr>
</table>
</fieldset>
ProductController:
public ActionResult CreateProduct(string slogan, string content)
{
ProductDataContext data = new ProductDataContext();
PRODUCT p = new PRODUCT();
p.SLOGAN = slogan;
p.CONTENT = content;
data.AddProduct(p);
data.SubmitChanges();
return View();
}
When I added a product, just slogan was added, content was null.
I dont understand and how to repair it.
Help me, please!
Thanks so much!
It does not work this way. You are mixing ASP.NET WebForms with MVC. ID="content" only sets the server-side ID of the Editor control. Controller parameters however are mapped by form field names and in your case the name of the corresponding textarea is generated automatically. I'm not aware of any way you could normally change the name of a control rendered by ASP.NET. You can, however try the following:
<script type="text/javascript">
document.getElementById('<%= content.ClientID =>').name = 'content';
</script>
Put this at the bottom of your view. It might just work.
Keep in mind that even if it works, the above is a dirty hack. The right approach in an MVC project would be to initialize the Editor control using just client scripting. This is not always easy but doable. For reference, try looking at the source of this page:
http://www.asp.net/ajax/ajaxcontroltoolkit/samples/htmleditor/OtherSamples/ClientSide.htm

Resources