jQuery-ui autocomplete causes validation to fail if result is null - jquery-ui

Long day and I'm still beating my head against the desk over this one. I think I've read every jQuery ui autocomplete post here on stack overflow as well as most of the jQuery ui documentation.
The Problem:
I have a form in an asp.net mvc 4 application. The form is for submitting a timesheet/work ticket. The user selects a project and based upon that project an autocomplete field for work order number is enabled. If the user chooses and existing work order number for the project, I populate two additional inputs with information about the work order. I need to allow the user to type in a completely new work order with out selecting an autocomplete suggested work order and still have the form validate. The problem is that validation fails if I do not select a suggestion from the autocomplete.
The jQuery-ui documentation does show that the methods close, disable, and destroy available to be used but I'm not finding a good example of how to use them and which would actually be best to use in my situation. Also it might be worth noting that I am using jQuery-ui 1.9
The error I get:
System.Data.Entity.Validation.DbEntityValidationException: Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
The error points to the line of code on my controller where I call _db.SaveChanges();
if ( ModelState.IsValid )
{
_db.WorkTickets.Add(workticket);
_db.SaveChanges();
}
The model state is valid and I have no nulls trying to be saved. My model does allow nulls on a few fields but in this case all fields are complete.
The form works great if I choose an existing work order from the autocomplete widget or if I leave it blank. It only fails if I type in a new work order. I have set a break point and verified that the model does have the value I typed in for work ticket.WONumber before calling save changes.
Here is my jQuery.
$(document).ready(function () {
$("#ProjectID").change(function () {
var id = $(this).val();
var results = "result";
var source1 = "Project/QuickCCSearch?project=" + id;
$("#ChargeCode").autocomplete({ source: source1 });
$("#ChargeCode").attr("disabled", false)
var source2 = "Project/QuickPOSearch?project=" + id;
$("#PONumber").autocomplete({ source: source2 });
$("#PONumber").attr("disabled", false)
var source3 = "Project/QuickWOSearch?project=" + id;
$("#WONumber").attr("disabled", false)
$("#WONumber").autocomplete({
source: function (request, response) {
$.ajax({
url: source3,
data: request,
success: function (data) {
response(data);
if (data.length === 0) {
$("#WONumber").attr("check", false);
}
}
});
},
change: function () {
if ($("#WONumber").attr("check") != false) {
$.getJSON("Project/JobLocation", { wo: $("#WONumber").val() },
function (data) {
$("#JobLocation").val(data);
});
$.getJSON("Project/JobDescription", { wo: $("#WONumber").val() },
function (data) {
$("#JobDescription").val(data);
});
}
}
});
$.getJSON("WorkTicket/GetClient/", { id: id },
function (data) {
$("#Client").html(data);
});
$.getJSON("WorkTicket/GetClientRep/", { id: id },
function (data) {
$("#ClientRep").html(data);
});
$.getJSON("WorkTicket/GetManager/", { id: id },
function (data) {
$("#Manager").html(data);
});
});
})
Edit:
Here is my Html
#model WorkTicket
#{
ViewBag.Title = "Create";
}
<article>
<div class="linearBg1">
Create Daily Work Ticket
</div>
<br />
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<div class="linearBg1">
General Information
</div>
<div class="section-span-body">
<table>
<tr class="empTableRowBody2">
<th class="empTableRowBody2">
#Html.LabelFor(Model => Model.DateWorked)
</th>
<th class="empTableRowBody2" colspan="2">
#Html.LabelFor(Model => Model.ProjectName)
</th>
</tr>
<tr>
<td>
#Html.EditorFor(Model => Model.DateWorked)
</td>
<td colspan="2">
#Html.DropDownList("ProjectID")
</td>
</tr>
<tr class="empTableRowBody2">
<th class="empTableRowBody2">
Client
</th>
<th class="empTableRowBody2">
Client Rep
</th>
<th class="empTableRowBody2">
Manager
</th>
</tr>
<tr>
<td>
<div id="Client"></div>
</td>
<td>
<div id="ClientRep"></div>
</td>
<td>
<div id="Manager"></div>
</td>
</tr>
<tr class="empTableRowBody2">
<th class="empTableRowBody2">
Charge Code
</th>
<th class="empTableRowBody2">
PO Number
</th>
<th class="empTableRowBody2">
Work Order
</th>
</tr>
<tr>
<td>
#Html.TextBoxFor(Model => Model.ChargeCode, new { disabled = true })
</td>
<td>
#Html.TextBoxFor(Model => Model.PONumber, new { disabled = true })
</td>
<td>
#Html.TextBoxFor(Model => Model.WONumber, new { disabled = true, check = true })
</td>
</tr>
<tr class="empTableRowBody2">
<th class="empTableRowBody2" colspan="3">
Job Location
</th>
</tr>
<tr>
<td colspan="3">
#Html.TextBoxFor(Model => Model.JobLocation, new { #class = "inputWidth500" })
</td>
</tr>
<tr class="empTableRowBody2">
<th class="empTableRowBody2" colspan="3">
Job Description
</th>
</tr>
<tr>
<td colspan="3">
#Html.TextBoxFor(Model => Model.JobDescription, new { #class = "inputWidth500" })
</td>
</tr>
</table>
</div>
<div class="section-span-footer"></div>
<br />
<div>
<input type="submit" value="Next" />
</div>
}
</article>
#section Menu{
#Html.Partial("_MainMenu")
#Html.Partial("_MenuFooter")
}
#section scripts{
#Scripts.Render("~/bundles/jqueryval")
#Scripts.Render("~/Scripts/WorkTicket.js")
}
I'm sure I'm doing many things wrong as I am new to jQuery and still learning. Is there a way to disable the autocomplete if the user does not choose an option from the autocomplete widget or if the result of the widget is null? Thank you in advance!
T.

Ok, I finally solved it. It has nothing to do with autocomplete. Just goes to show how much I need to learn about jQuery. I had a bad line of code in my controller where I was saving information about the new work order back to the project. I was missing one required item and I was just over looking it. Sorry for being an idiot and ignorant about jQuery. Thanks anyone that looked. Can't believe that took me so long to see.......

Related

Add table controls for asp.net mvc web application using signalR

I want to add controls to sort a table which is rendered in a partial view. The partial view is called using a signalR method. Every time the server updates the database with new information it calls the javascript method to return a new partial view to <div id="customersTable">.
I need a way to pass a query to the controller, and make the last query sent persistent so that when signalR calls the controller action again, the clients actions are remembered.
In addition to sorting I would also like to implement child rows that are expandable via a toggle button in an additional column. I'm not sure how feasible that is using partial views and signalR in this way.
I have partially solved this by adding JQuery controls to the main page. However when AJAX updates the DOM, the controls are reset to their default state, which is something I ultimately want to avoid happening.
Here is the partial view:
#model IEnumerable<XXXX.Models.CustomerModel>
<table class="table table-hover">
<tbody>
<tr>
<th class="col-sm-2">
Name
</th>
<th class="col-sm-2">
SO Number
</th>
<th class="col-sm-2">
Report Time
</th>
<th class="col-sm-2">
Report Date
</th>
<th align="center" class="col-sm-1">
System Status
</th>
</tr>
#foreach (var item in Model)
{
<tr onclick="location.href = '#(Url.Action("SystemDetails", "Monitoring", new { id = item.ID }))'" #(item.Errors == 0 ? String.Empty : "class=danger")>
<td class="col-sm-2">
#Html.DisplayFor(modelItem => item.Name)
</td>
<td class="col-sm-2">
#Html.DisplayFor(modelItem => item.SONumber)
</td>
<td class="col-sm-2">
#Html.DisplayFor(modelItem => item.ReportTime)
</td>
<td class="col-sm-2">
#Html.DisplayFor(modelItem => item.ReportDate)
</td>
<td align="center" class="col-sm-1">
#if (item.Errors == 0)
{
<i class="glyphicon glyphicon-ok"></i>
}
else if (item.Errors > 0)
{
<i class="glyphicon glyphicon-warning-sign"></i>
}
</td>
</tr>
}
</tbody>
</table>
Here is the javascript method client side:
function getAllCustomers()
{
var tbl = $('#customersTable');
$.ajax({
url: '/Monitoring/GetCustomers',
contentType: 'application/html ; charset:utf-8',
type: 'GET',
dataType: 'html'
}).success(function (result) {
tbl.empty().append(result);
}).error(function () {
});
}
And the controller method where the db context is sorted:
public ActionResult GetCustomers()
{
return PartialView("~/Views/Monitoring/_CustomersList.cshtml", db.Customers.OrderBy(c => c.SONumber).ToList());
}

two-way binding of a single object in observableArray

My page is as follows:
<button id="add">Add Data</button>
<button id="show">show</button>
<table>
<tr style="vertical-align:top">
<td>
<table border="1">
<thead>
<tr>
<th>Id</th>
<th>Name</th>
</tr>
</thead>
<tbody data-bind="foreach: students">
<tr>
<td data-bind="text: id"></td>
<td>
<input type="text" data-bind="value: name" />
</td>
<td> Select
</td>
</tr>
</tbody>
</table>
</td>
<td>
<table id="data">
<tbody data-bind="with: selectedData">
<tr>
<td>Id</td>
<td>
<input type="text" data-bind="value: id" />
</td>
</tr>
<tr>
<td>Name</td>
<td>
<input type="text" data-bind="value: name" />
</td>
</tr>
<tr>
<td></td>
<td>
<input type="button" value="Close" />
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</table>
The javascript is as follows:
function ViewModel() {
var self = this;
self.students = ko.observableArray([]);
self.showData = function (dt) {
if (window.console) console.log(dt);
self.selectedData(dt);
$('#data').show();
}
this.selectedData = ko.observable();
}
$(function () {
window.appViewModel = new ViewModel();
ko.applyBindings(window.appViewModel);
$('#add').click(function () {
var model = window.appViewModel;
$.each(students, function (idx, student) {
if (window.console) console.log(student);
model.students.push(student);
});
$('table').show();
});
$('table').hide();
$('input').click(function () {
$('#data').hide();
});
$('#show').click(function () {
var s = JSON.stringify(window.appViewModel.students());
alert(s);
});
});
Preview:
In pic, I click on the select corresponding to student with id = 3. The other table shows up with the selected student details. Suppose I enter something in textbox 1, textbox 2 doesn't update, and vice versa.
What to do to make that happen?
Fiddle: http://jsfiddle.net/deostroll/YdrQf/1/
Your inputs aren't updating because the id and name values are not being stored or bound against observables, which are the special object that knockout provides specifically for this purpose. You can easily solve this with your code by adding a new Student type:
function Student(data) {
this.id = ko.observable(data.id);
this.name = ko.observable(data.name);
};
and use it to populate your students array with:
$.each(students, function (idx, student) {
if (window.console) console.log(student);
model.students.push(new Student(student));
});
With those properties now being observables, their changes will propagate to the UI. Here is the fiddle, with these two minor changes.
That being said, I think you have largely missed the point of Knockout. I strongly suggest you go through the Knockout tutorials, if you haven't done so already.
You're use of jQuery to create click functions for your viewmodel really goes against the model that Knockout encourages. Please take a look at this fiddle, which converts your code into 100% Knockout, using viewmodel functions, and drops all the jQuery.

Invalid length for a Base-64 char array or string. when I trying to pass byte[]

I am trying send Byte[] by converting to string from View to controller in #Html.ActionLink. Evey time when I click on ActionLink it is throwing exception. I am attaching code here.
Exception
URL After Action Click
http://localhost:55253/Member/Create?customerContactNumber=0439349
&committeeId=AAAAAAAADLc%3D
View Code
#using VolunteerPoints.BootstrapSupport
#model Tuple<VolunteerPoints.Models.Contact, IEnumerable<VolunteerPoints.Data.Committee>>
#{
ViewBag.Title = "SearchResults";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Activity Search Results</h2>
<table id="Activitieslist" class="table table-striped table-bordered table-hover .table-condensed">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Item2.GetEnumerator().Current.Committee_Name)
</th>
<th>
#Html.DisplayNameFor(model => model.Item2.GetEnumerator().Current.Committee_Type)
</th>
<th></th>
</tr>
</thead>
#foreach (var model in Model.Item2)
{
<tr>
<td>
#Html.DisplayFor(modelItem => model.Committee_Name)
</td>
<td>
#Html.DisplayFor(modelItem => model.Committee_Type)
</td>
<td>
<div>
<div>
#Html.ActionLink("Select", "Create","Member", new
{customerContactNumber = Model.Item1.Number, committeeId =
Convert.ToBase64String(model.Committee_Id) }, new { #class = "btn btn-primary" })
</div>
</div>
</td>
</tr>
}
</table>
#section Scripts {
#Styles.Render("~/Content/DataTables/css")
#Scripts.Render("~/bundles/DataTables")
<script type="text/JavaScript">
$(document).ready(function () {
$('#Activitieslist').dataTable({
"bSort": true,
"bPaginate": false,
"bAutoWidth": false,
});
});
</script>
}
Well this part of the URL:
AAAAAAAADLc%3D
should be decoded to
AAAAAAAADLc=
... at which point the length is a multiple of 4, with perfectly reasonable padding at the end.
So I suspect the problem is how/whether the decoding is performed.
(As a side note: byte[] is a pretty unusual representation for an ID. Do you really need it to be done that way?)
Try changing the section of code:
committeeId = Convert.ToBase64String(model.Committee_Id)
To
committeeId = HttpServerUtility.UrlTokenEncode(model.Committee_Id)
This will provide a more URL friendly encrypted string which will avoid characters in the URL that may cause errors.
Hope this helps you James123;

All model and Formcollection values are null, blank or don't exist in Firefox or Chrome

During debugging, my MVC model and Formcollection are blank with no values in FireFox (15) or Chrome (latest version).
During debugging using IE (9), I can see these values just fine.
Do you know what the solution is for this? This is very serious for public facing web sites not being able to do any programming angainst these browsers.
Here is my View...
#model PDFConverterModel.ViewModels.ViewModelTemplate_Guarantors
#{
ViewBag.Title = "BHG :: PDF Generator";
}
<h2>#ViewBag.Message</h2>
<div>
<table style="width: 1000px">
<tr>
<td colspan="5">
<img alt="BHG Logo" src="~/Images/logo.gif" />
</td>
</tr>
#using (Html.BeginForm("ProcessForm", "Home", FormMethod.Post))
{
<tr>
<td>
#(Html.Kendo().IntegerTextBox()
.Name("LoanID")
.Placeholder("Enter Loan ID")
)
</tr>
<tr>
<td>#Html.LabelFor(model => model.LoanType)
#Html.DisplayFor(model => model.LoanType)
</td>
<td>
<label for="ddlDept">Department:</label>
#(Html.Kendo().DropDownList()
.Name("ddlDept")
.DataTextField("DepartmentName")
.DataValueField("DepartmentID")
.Events(e => e.Change("Refresh"))
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetDepartments", "Home");
});
})
)
</td>
</tr>
if (Model.ShowGeneratePDFBtn == true)
{
if (Model.ErrorT == string.Empty)
{
<tr>
<td colspan="5">
<u><b>#Html.Label("Templates:")</b></u>
</td>
</tr>
<tr>
#for (int i = 0; i < Model.Templates.Count; i++)
{
<td>
#Html.CheckBoxFor(model => Model.Templates[i].IsChecked)
#Html.DisplayFor(model => Model.Templates[i].TemplateId)
</td>
}
</tr>
}
else
{
<tr>
<td>
<b>#Html.DisplayFor(model => Model.ErrorT)</b>
</td>
</tr>
}
if (Model.ErrorG == string.Empty)
{
<tr>
<td colspan="5">
<u><b>#Html.Label("Guarantors:")</b></u>
</td>
</tr>
<tr>
#for (int i = 0; i < Model.Guarantors.Count; i++)
{
<td>
#Html.CheckBoxFor(model => Model.Guarantors[i].isChecked)
#Html.DisplayFor(model => Model.Guarantors[i].GuarantorFirstName) #Html.DisplayFor(model => Model.Guarantors[i].GuarantorLastName)
</td>
}
</tr>
}
else
{
<tr>
<td>
<b>#Html.DisplayFor(model => Model.ErrorG)</b>
</td>
</tr>
}
}
<tr>
<td colspan="3">
<input type="submit" name="submitbutton" id="btnRefresh" value='Refresh' />
</td>
#if (Model.ShowGeneratePDFBtn == true)
{
<td>
<input type="submit" name="submitbutton" id="btnGeneratePDF" value='Generate PDF' />
</td>
}
</tr>
<tr>
<td colspan="5">
#Model.Error
</td>
</tr>
}
</table>
</div>
<script type="text/javascript">
$('btnRefresh').on('click', '#btnRefresh', function () {
Refresh();
});
function Refresh() {
var LoanID = $("#LoanID").val();
if (LoanID != "") {
document.forms[0].submit();
}
else {
alert("Please enter a LoanId");
}
}
</script>
I know this is a very old question, but answering this might help people like who are struggling with this issue.
I had a similar issue. The problem lies here:
<table style="width: 1000px">
<tr>
<td colspan="5">
<img alt="BHG Logo" src="~/Images/logo.gif" />
</td>
</tr>
#using (Html.BeginForm("ProcessForm", "Home", FormMethod.Post))
{
<tr>
<td>
#(Html.Kendo().IntegerTextBox()
.Name("LoanID")
.Placeholder("Enter Loan ID")
)
</td>
</tr>
}
</table>
After begin form there are <tr> tags directly! Browsers like chrome and mozilla get confused in such cases. The <table> tag should be inside the form. If we look at your code, which was exactly what I had done, <table> tag was before #using Html.BeginForm.
Internet Explorer somehow understands this, but the other browsers don't.
When I did an inspect element I found that there was a form tag within each <tr> tag and it always returned FormCollection as null. Simply defining <table> within form solved my problem.
So here's how it should be:
<table style="width: 1000px">
<tr>
<td colspan="5">
<img alt="BHG Logo" src="~/Images/logo.gif" />
</td>
</tr>
<tr><td>
#using (Html.BeginForm("ProcessForm", "Home", FormMethod.Post))
{
<table>
<tr>
<td>
#(Html.Kendo().IntegerTextBox()
.Name("LoanID")
.Placeholder("Enter Loan ID")
)
</td>
</tr>
</table>
}
</td></tr>
</table>
I just found out what the issue is by experimneting.
The Telerik MVC widgets don't emit any FormCollection data!!!!
Only EditorFor and TextBoxFor emit these values, plus the input buttons.
What good are these widgets if I can't use the FormCollection values from them???? Especially the DropDownList where I can retrireve data and need the selected value to pass onto other methods.
(This would be better suited as comment, but I can't comment yet)
For future reference, here's a spec (W3C might have something different) for what gets submitted when a form is submitted:
http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#category-submit
You can look at whatever HTML was generated to make sure it gets submitted. You could also use something like Fiddler to look at the Http request

Input validation in MVC 3

I am developing the CRM and facing some troubles in model validation.The process looks simple when only one object in the model(i am using EF) is validated on the form. But when i am trying to process validation on multiply objects, only one top record got validated. Here is the code:
#model List<CROS1.Models.GetParams_Result> //
<h3 align="center">
Please fill report params
</h3>
<div class="sidebar_item">
#using (#Ajax.BeginForm("ConfirmGeneration", "Home", ajaxOptions: new AjaxOptions
{
HttpMethod = "GET",
UpdateTargetId = "params",
InsertionMode = InsertionMode.Replace,
LoadingElementId = "resultLoadingDiv",
}, htmlAttributes: new { id = "Form2" }))
{
<table id="hor-minimalist-b">
<tread>
<tr>
<th scope ="col">Report</th>
<th scope ="col">Filter</th>
<th scope ="col">Value</th>
</tr>
</tread>
#foreach (CROS1.Models.GetParams_Result res in Model)
{
<tbody>
<tr>
<td>#Html.DisplayTextFor(r => res.R_name)
</td>
<td>#Html.DisplayTextFor(r => res.Filter_name)
</td>
<td>#Html.EditorFor(r => res.Value)
#Html.ValidationMessageFor(r=>res.Value)
</td>
<td>#Html.DisplayFor(r => res.Unity)
</td>
#Html.HiddenFor(r=>res.F_id)
#Html.HiddenFor(r=>res.R_id)
#Html.HiddenFor(r=>res.Filter_id,new{id="some"})
#Html.HiddenFor(r => res.F_name)
#Html.HiddenFor(r => res.Filter_name)*#
#Html.HiddenFor(r=>res.DefaultValue)
#Html.HiddenFor(r=>res.Visibles)
</tr>
</tbody>
}
</table>
#* <input type="submit" id="submGetParams" />*#
}
</div>
What i should do in this case? How the model must look like to be able to perform such validation?
You need to iterate through each item in your list of items returned, appending the iteration number to each items element, this should help: mvc clientside validation for nested (collection) properties

Resources