justiceorjustus justiceorjustus - 2 months ago 13
jQuery Question

Jquery autocomplete not working MVC with Entity Framework

I have two models. One of the models (my ViewModel) is tied to the textbox in the form and the other model is tied to an entity (Employees) that I'm using to autocomplete the textbox (VieModel.Name). I followed a tutorial here and cannot seem to get it working. I delved around Google, as well. It may be my newness to Entity Framework or the fact I'm using a ViewModel not tied to an entity and a Model tied to an entity.

Ultimately I am trying to autocomplete the Name in the ViewModel from the FirstName + LastName from the Employees Entity Model, but am trying FirstName for now.

Model from entity:

public partial class Employee
{
public bool ActiveFlag { get; set; }
public int EmpNid { get; set; }
public string RecKey { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
... etc


My ViewModel not tied to entity but posted with this form:

public class SalesViewModel
{
[Display(Name = "Employee Name")]
[Required(ErrorMessage = "The employee name is required")]
public string Name { get; set; }
... etc


View:

<div class="form-group">
@Html.LabelFor(m => m.Name, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(m => m.Name,
new
{
@class = "employees-autocomplete",
data_url = Url.Action("EmployeesAutocomplete", "Employee")
})
@Html.ValidationMessageFor(m => m.Name, "", new { @class = "text-danger" })
</div>
</div>


My Jquery at the bottom of the page:

$(function () {
$('.employees-autocomplete').autocomplete({
minLength: 0,
source: function (request, response) {
var url = $(this.element).data('url');

$.getJSON(url, { term: request.term }, function (data) {
response(data);
})
}
});
})


My JsonResult Controller:

public JsonResult EmployeesAutocomplete(string term)
{
Employee[] matching = string.IsNullOrWhiteSpace(term) ?
db.Employees.ToArray() :
db.Employees.Where(p => p.FirstName.ToUpper().StartsWith(term.ToUpper())).ToArray();

return Json(matching.Select(m => new
{
id = m.EmpNid,
value = m.FirstName,
label = m.ToString()
}), JsonRequestBehavior.AllowGet);
}


Am I supposed to be doing anything in the post or get request? Not sure where I went wrong.

Answer

Your code looks fine. The only issue i see is, you are calling the ToString() on the Employee entity object/record for the label value. Since this is the value to be shown to the user, you probably want to use your FirstName or any string properties here ( Unless you overwrote the a ToString() method in your Employee class to return a string version)

Replace this

return Json(matching.Select(m => new
{
    id = m.EmpNid,
    value = m.FirstName,
    label = m.ToString()
}), JsonRequestBehavior.AllowGet);

With this

return Json(matching.Select(m => new
{
    id = m.EmpNid,
    value = m.FirstName,
    label = m.FirstName +' '+m.LastName 
}), JsonRequestBehavior.AllowGet);

As per the comment

Uncaught ReferenceError: $ is not defined(anonymous function)

This usually happens when you are trying to use jQuery before it is defined in your page. Double check the following steps

  1. Include jQuery before everything else
  2. Include jQuery UI after jQuery library
  3. Execute your page level scripts only after loading the dependeny libraries (jQuery/jQueryUI). You can do this by calling your page level scripts inside a script section.

    @section scripts
    {
      $(function(){
    
       // Your code for initializing the auto complete goes here
    
      })
    }
    

    Assuming your layout has a section called scripts which is defined after loading jQuery and jQuery UI libraries.

So in your layout file, it should be like this

@RenderBody()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.0/themes/smoothness/jquery-ui.css">
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.0/jquery-ui.min.js"></script>
@RenderSection("scripts", required: false)