How to Implement Autocomplete Textbox in MVC - c#

I am facing a problem in autocompleting the textbox vith hardcoded data, my json "Search" method does not fire i have been search a lot of code implement it into my project but did not get any success yet. i dont know where is the problem. kindly help me thankx in advance
Model:
public class Locations
{
public int Id { get; set; }
public string Name { get; set; }
}
Controller:
public JsonResult Search(string query)
{
List<Locations> locations = new List<Locations>()
{
new Locations() {Id = 1, Name = "London"},
new Locations() {Id = 2, Name = "Walles"},
new Locations() {Id = 3, Name = "Birmingham"},
new Locations() {Id = 4, Name = "Edinburgh"},
new Locations() {Id = 5, Name = "Glasgow"},
new Locations() {Id = 6, Name = "Liverpool"},
new Locations() {Id = 7, Name = "Bristol"},
new Locations() {Id = 8, Name = "Manchester"},
new Locations() {Id = 9, Name = "NewCastle"},
new Locations() {Id = 10, Name = "Leeds"},
new Locations() {Id = 11, Name = "Sheffield"},
new Locations() {Id = 12, Name = "Nottingham"},
new Locations() {Id = 13, Name = "Cardif"},
new Locations() {Id = 14, Name = "Cambridge"},
new Locations() {Id = 15, Name = "Bradford"},
new Locations() {Id = 16, Name = "Kingston Upon Hall"},
new Locations() {Id = 17, Name = "Norwich"},
new Locations() {Id = 18, Name = "Conventory"}
};
List<string> Loc;
Loc = locations.Where(x => x.Name.StartsWith(query.ToLower())).Select(x => x.Name).ToList();
return Json(Loc, JsonRequestBehavior.AllowGet);
}
View:
#model IEnumerable<SearchBox.Models.Locations>
#using SearchBox.Models
#{
ViewBag.Title = "Index";
}
<link href="~/Content/Autocomplete/jquery-ui.css" rel="stylesheet" />
<script src="~/Content/Autocomplete/jquery-ui.js"></script>
<link href="~/Content/Autocomplete/jquery-ui.theme.css" rel="stylesheet" />
<script type="text/javascript">
$("#tags").autocomplete({
source: '#Url.Action("Search")'
});
</script>
<input type="text" id="tags" />

You need to make ajax request instead of passing just url in data source.
<link href="~/Content/jquery-ui.css" rel="stylesheet" />
<script src="~/Content/jquery-1.12.4.js"></script>
<script src="~/Content/jquery-ui.js"></script>
<input type="text" id="tags" />
<script type="text/javascript">
$("#tags").autocomplete({
source: function (request, response) {
$.ajax({
url: '#Url.Action("Search")',
dataType: "jsonp",
data: {
term: request.term
},
success: function (data) {
response($.map(data, function (item) {
return {
label: item.Name,
value: item.Id
};
}));
}
});
},
minLength: 2,
select: function (event, ui) {
}
});
</script>
See how to use autocomplete with ajax request.

I have implemented this in my project. Please check if you can make use of it
<div class="tag_cover" style="margin-top:60px; margin-left:57px">
<input type="text" style="width:300px; display:inline-block; border:transparent" class="tag_input brzero has-icon" id="SkillSet" list="json-datalist" placeholder="Employee name or Skills">
<datalist id="json-datalist"></datalist>
</div>
JQuery:
$(".tag_input").keyup(function (e) {
var type = $("input[name='search']:checked").val();
if (type == "Name") {
var sString = $("#SkillSet").val();
if (sString == null || sString == "") {
e.preventDefault();
}
else {
$.ajax({
url: "#Url.Action("GetEmployeeNameByKeyword","Home")",
type: "POST",
data: { 'SearchedString': sString },
dataType: "json",
success: function (data) {
if (data == null || data == "") {
//alert("no skills found");
}
else {
var dataList = document.getElementById('json-datalist');
$(dataList).empty();
$.each(data, function (key, value) {
$(dataList).append($('<option>').text(value.UserNames.trim()).attr("value", value.UserId));
});
}
},
error: function () {
alert("failure");
}
});
}
}
}
Controller:
public JsonResult GetEmployeeNameByKeyword(string SearchedString)
{
List<UserProfile> EmployeeNames = new List<UserProfile>();
EmployeeNames = _db.UserProfiles.Where(i => i.UserNames.Contains(SearchedString)).ToList();
return Json(EmployeeNames, JsonRequestBehavior.AllowGet);
}

I have been looking everywhere for references on a feature like this, myself.
I don't have enough rep to comment, but Naveen's answer worked for me after I started going one line at a time with console.log("PASS");. If the function is never called on an event like keyup, then it likely means one of the variable names is wrong or there is bad syntax. The reason you could not get any calls to the javascript was because of a missing }); which is an ending statement for JQuery functions. The end of the code for the scripting part should appear like so:
}
}); //END $.ajax
}
}
}); //END keyup function

Using Razor, with T4MVC at an MVC5 project, we'll implement jQuery Autocomplete.
You should have inside your solution, one or more projects, and inside your project, among many other usual MVC5 things, the folders Models, Views and Controllers. And inside of them...
NuGet
Get the dependencies in place (your should know how to get them using Visual Studio):
jQuery: https://www.nuget.org/packages/jQuery/3.6.0
jQuery-UI: https://www.nuget.org/packages/jQuery.UI/
Then put them in the BundleConfig.cs files, at the App_Start folder:
using System.Web.Optimization;
namespace MyProject.Web
{
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
bundles
.Add(new ScriptBundle("~/bundles/jquery")
.Include(
"~/Scripts/jquery-{version}.js",
"~/Scripts/jquery-ui.js",
));
bundles
.Add(new StyleBundle("~/Content/css")
.Include(
"~/Content/jquery-ui.css"
));
}
}
}
This will add the dependencies you´ll need to the view (see View section down below for more instructions).
Model
namespace MyProject.Web.Models.MyModelFolder
{
public class MyModel
{
public string MyValue { get; set; }
public string MyAnotherValue { get; set; }
public string AndAnotherValue { get; set; }
}
}
View
(Using Bootstrap)
#model MyProject.Web.Models.MyModelFolder.MyModel
<div class="ui-widget">
#Html.LabelFor(model => model.MyValue)
#Html.EditorFor(model => model.MyValue, new { htmlAttributes = new { #class = "form-control", id = "myTextbox" } })
#Html.ValidationMessageFor(model => model.MyValue, "", new { #class = "text-danger" })
</div>
We'll be querying the MyValue field.
And add the dependencies from the BundleConfig.cs where you'll need them in your page:
<header>
#Styles.Render("~/Content/css")
</header>
<body>
<p>Your Content</p>
#Scripts.Render("~/bundles/jquery")
</body>
Adding the Autocomplete
There are two ways you can accomplish this, as:
Internal file to the page or,
as an external .js file.
NOTE: Autocomplete must be always below the required jQuery dependencies.
Internal file
In the .cshtml file. Inside your <body> tag, at the bottom of it:
<script>
$("#myTextbox").autocomplete({
source: '#Url.Action(MVC.MyController.MyMethod())'
});
</script>
Or instead in the...(Choose one, not both!)
External file
In the Scripts folder. Remember to add this block at the bottom of your view to call the function from the outside.
#section Scripts {
<script src="~/Scripts/autocomplete.js"></script>
}
And in the Scripts folder in a JS file add:
$(document).ready(function () {
$("#myTextbox").autocomplete({
source: '/MyController/MyMethod',
});
})
You can see there the method you'll be calling from from the controller.
Controller
#region jQuery Method Calls
using MyProject.Web.Models.MyModelFolder;
public virtual JsonResult MyMethod(string term)
{
// _myViewModel is a partial model
List<MyModel> MyAutocompleteList = new List<MyModel>();
/* In this example I´m using AutoMapper, and getting back the List
from the Database (layer, using Entity Framework), using Repository
Pattern (layer) and Unit of Work Pattern. */
// But you can get the List however way you want.
MyAutocompleteList = _theMapper.GetMyModelList(_operationsLayerService.GetMyModelList());
// This LINQ query makes the magic happen
var result = from U in MyAutocompleteList
where U.MyValue.Contains(term)
// It retrieves a composed string, not just a single value.
select new { value = $"{U.MyValue} | {U.MyAnotherValue} {U.AndAnotherValue}" };
// Security vulnerabilities? https://stackoverflow.com/a/21453075/7389293
return Json(result, JsonRequestBehavior.AllowGet);
}
#endregion
That's it.

Related

Passing parameter to displaytemplate between different views

I have several views with different viewmodels.
Every view has "ProjectId" dropdownlist, and I want to show selected project's start date beside the "ProjectId" dropdownlist before submit.
And the "ProjectId" dropdownlist is a ViewBag.
Is there any other way besides adding start date to each viewmodel?
view:
<div class="form-inline">
Project:
<div>
#Html.DropDownList("ProjectId", new SelectList(ViewBag.ProjectsDropDownList, "Value", "Text"))
</div>
</div>
It is a bit hard to answer you without you supplying your code but I have had a look at
https://www.tutorialsteacher.com/mvc/viewbag-in-asp.net-mvc regarding viewbags which you are welcome to have a look at.
It shows that you could simply use a label with something like this in the front end:
<label>Project Start Date:</label> #ViewBag.projectStartDate
That would be if you are using ASP.NET or HTML for the client side coding
In the back end something like this :
namespace MVC_BasicTutorials.Controllers
{
public class ProjectController : Controller
{
string projectName;
int projectId;
string projectDate;
public ProjectController ()
{
projectName = "new project";
projectId = 0;
projectDate = "01-01-1990";
}
public ActionResult returnDate()
{
ViewBag.projectStartDate = this.projectDate;
return View();
}
}
}
The last approach I used:
ProjectsController:
public PartialViewResult ProjectDate(int projectId)
{
// get project start date
ViewBag.StartDate = startDate;
return PartialView("_ProjectDate");
}
_ProjectDate.cshtml:
// use ViewBag.StartDate to render html what I want
get_start_date.js
$(document).ready(function () {
var projectId = $('#ProjectId').val();
if (projectId != undefined) {
$.ajax({
url: '/Projects/GetProjectDate',
data: { ProjectId: projectId },
success: function (result) {
$("#project_date").html(result);
}
});
}});
_Layout.cshtml import get_start_date.js, and insert this code in the page I need:
<div id="project_date"></div>

Simple ASP.NET PartialView issue

I'm very new to ASP.Net and am trying to figure out partial views. I'm trying to get some very simple data to load in a partial view and am just not having any luck. I've got the following, and everything in it works except the load button:
Index.cshtml
#model IEnumerable<MMC_ASP.Models.MMCProjectViewModel>
#{
ViewBag.Title = "MMCView";
}
<h2>Active Projects</h2>
<div class="project-list">
#foreach (var item in Model)
{
<div class="mig-project #item.ColorClass">
<div>
<div class="client-name">#item.Client</div>
<div class="source-target">#item.SourceTarget</div>
<div class="server-name">#item.ServerName</div>
<div class="error-count">#item.ErrorCount</div>
</div>
</div>
}
</div>
<div id="partial"></div>
<input type="button" id="btn" value="Click for Data" />
<script type="text/javascript">
$(document).ready(function () {
$('#btn').click(function () {
$('#partial').load('/MMC/LoadPartialView');
});
});
</script>
MMCController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MMC_ASP.Controllers
{
public class MMCController : Controller
{
public ActionResult Index()
{
Models.MMCProjectViewModel Project1 = new Models.MMCProjectViewModel() { Client = "Test Client1", SourceTarget = "Source to Target", ServerName = "Server1", ErrorCount = 3, ColorClass = "yellow" };
Models.MMCProjectViewModel Project2 = new Models.MMCProjectViewModel() { Client = "Test Client2", SourceTarget = "Source to Target", ServerName = "Server2", ErrorCount = 1, ColorClass = "red" };
Models.MMCProjectViewModel Project3 = new Models.MMCProjectViewModel() { Client = "Test Client3", SourceTarget = "Source to Target", ServerName = "Server3", ErrorCount = 0, ColorClass = "green" };
Models.MMCProjectViewModel Project4 = new Models.MMCProjectViewModel() { Client = "Test Client4", SourceTarget = "Source to Target", ServerName = "Server4", ErrorCount = 2, ColorClass = "green" };
Models.MMCProjectViewModel Project5 = new Models.MMCProjectViewModel() { Client = "Test Client5", SourceTarget = "Source to Target", ServerName = "Server5", ErrorCount = 1, ColorClass = "red" };
List<Models.MMCProjectViewModel> ProjectList = new List<Models.MMCProjectViewModel>();
ProjectList.Add(Project1);
ProjectList.Add(Project2);
ProjectList.Add(Project3);
ProjectList.Add(Project4);
ProjectList.Add(Project5);
return View(ProjectList.OrderBy(o => o.Client).ToList());
}
public ActionResult LoadPartialView()
{
return PartialView();
}
}
}
LoadPartialView.cshtml
<div>TEST DATA HERE</div>
Nothing happens when I click the "Click for Data" button. What am I missing? And for the record, I do realize I should be breaking the script into a separate file, and that the work on the Index action will be done differently. This is a proof of concept for me to make sure I understand all the pieces, and I believe this is the last one to make this work.
Your code looks fine. I have a very strong feeling that your code is failing to update the partial view because you are getting a 404 Not Found error when trying to make an ajax call.
It is a good practice to take advantage of the HTML helper methods like Url.Action to generate the correct url to an action method. You can execute the Url.Action method in the razor view and keep the output of that(the url) in html 5 data attributes on the button.
<input type="button" id="btn" data-url="#Url.Action("LoadPartialView","MMC")"
value="Click for Data" />
Now when click event happens, read the data attribute value and use that to make the ajax call.
$(function () {
$('#btn').click(function (e) {
e.preventDefault();
$('#partial').load($(this).data("url"));
});
});
Thanks to the great help from #sleeyuen, #Shyju, and #maccettura I got it working. I needed to add this to my view below the #{ViewBag.Title...} area:
#section scripts {
<script type="text/javascript">
$(document).ready(function () {
$('#btn').click(function (e) {
$('#partial').load($(this).data("url"));
});
});
</script>
}
And the Ajax.BeginForm method wouldn't work because my project doesn't include jquery.unobtrusive-ajax.js. Hope this helps someone else down the line.

ASP. MVC JsonResult

Hello I am trying to pass the parameter id to the a JsonResult. Currently the code below works if I hard code my id and when I do not pass a parameter through.
The code below is for the Events Calendar View
<script>
$(document).ready(function () {
$('#calendar').fullCalendar({
header: {
left: "prev,next,today",
center:'title',
right:''
// right: 'month'
},
defaultView: 'month',
editable:false,
allDaySlot: false,
selectable: true,
slotMinutes: 15,
firstDay:1,
events: 'GetEvents/'
});
});
</script>
<div id='calendar' style="width:90%">
</div>
JsonResult where the id is currently hard coded I would like to pass this value through when I click the button to load the page e.g. /EventsCalendar/2
public JsonResult GetEvents(string start , string end)
{
int id = 1;
var events = CustomEvents(start , end, id );
return Json(rows, JsonRequestBehavior.AllowGet);
}
Item 2 is the name of the button and Item 1 is the name
#Html.ActionLink(item.Item2, "ShowEvents", new { controller = "Leaves", id = item.Item1 }, new { #Class = "btn btn-primary" })
public ActionResult EventsCalendar()
{
return View();
}

Problems Cascading dropdownlist, generated dropdown isn't posting selected value to server

Here is my view in image
The code is working fine, but...
When i submit the form, it only sends the value of first dropdownlist (I checked on browser network received arguments), also when i view the page source it doesn't show the generated options that I generated using ajax function.
Here is my Code
Action that generate my first dropdownList
public ActionResult TwoDropDownList()
{
HotelContext H = new HotelContext();
ViewBag.DropDownListOne = new SelectList(H.Continent.ToList(), "Id", "Name");
return View();
}
Action that return json of second dropdownlist data
[HttpPost]
public JsonResult UpdateCountryDropDownList(int ContinentId)
{
HotelContext H = new HotelContext();
List<SelectListItem> CountryNames = new List<SelectListItem>();
List<Country> Co = H.Country.Where(x => x.ContinentId == ContinentId).ToList();
Co.ForEach(x =>
{
CountryNames.Add(new SelectListItem { Text = x.Name, Value = x.Id.ToString() });
});
return Json(CountryNames , JsonRequestBehavior.AllowGet);
}
My Ajax call
#model Hotel.Models.Continent
<script>
$(document).ready(function () {
$("#Name").change(function () {
var ContinentoId = $(this).val();
$.ajax({
type: "POST",
dataType: "json",
data: { ContinentId: ContinentoId },
url: '#Url.Action("UpdateCountryDropDownList","Home")',
success: function (result) {
var Country = "<select id='ddlCountry'>";
Country = Country + '<option value="">--Select--</option>';
for (var i = 0; i < result.length; i++) {
Country = Country + '<option value=' + result[i].Value + '>' + result[i].Text + '</option>';
}
Country = Country + '</select>';
$('#Countries').html(Country);
},
error: function (xhr, ajaxOptions, thrownError) {
console.log(arguments)
}
});
});
})
</script>
My View
#using(Html.BeginForm()){
SelectList se = ViewBag.DropDownListOne;
#Html.DropDownListFor(x=>x.Name,se,"--Select--")
<div id ="Countries">
#Html.DropDownList("ddlCountry",new List<SelectListItem>(),"--Select--")
</div>
<input type="submit" value="submit" style="margin-top:100px;" />
}
HTTPPost Action
[HttpPost]
public string TwoDropDownList(string Name, string ddlCountry)
{
if (string.IsNullOrEmpty(Name) || string.IsNullOrEmpty(ddlCountry))
{
return ("you must select Both");
}
else
return ("everything is working fine");
}
You already have a <select> element with name="ddlCountry" (generated by #Html.DropDownList("ddlCountry", new List<SelectListItem>(), "--Select--") but in the ajax call, you overwrite it and create a new <select> element without a name attribute (so its value is not posted back.
In the success callback, you should be creating <option> elements and appending them to the existing <select>
success: function (result) {
var country = $('#ddlCountry); // get the existing element
country.empty().append($('<option></option>').val('').text('--Select--'));
$.each(result, function(index, item) {
country.append($('<option></option>').val(item.Value).text(item.Text));
});
}
Side note: Your methods should be returning a collection of anonymous objects, not SelectListItem There is no point sending extra data (the other properties of SelectListItem) across the wire when you don't use them.
I think you are missing the end tag </div> for the <div id ="Countries">.
Try this:
<div id ="Countries">
#Html.DropDownList("ddlCountry",new List<SelectListItem>(),"--Select--")
</div>

asp.net mvc partial view is caching my model values

I am working on an asp.net mvc web application. and i have a WebGrid, where i added a Page-size drop-down list to enable users to select how many records they like to have per page.
the Action method is:-
[OutputCache(CacheProfile = "NoCache")]
public ActionResult Disposed(string filter = null, int page = 1, int? pageSize = null, string sort = "Technology.Tag", string sortdir = "ASC")
{
GridList<DisposedResources> gridrecords = repository.GetDisposedResourcesForGrid(filter, page, pageSize, sort, sortdir, "rack");
ViewBag.PagedSizeOptions = new PageOptions().FilterOptions;
if (Request.IsAjaxRequest())
{
return PartialView("_disposed", gridrecords);
}
return View("Disposed", gridrecords);
}
and here is the repository method :-
public GridList<DisposedResources> GetDisposedResourcesForGrid(string filter, int page, int? pageSize, string sort, string sortdir, string resourcetype)
{
if (!pageSize.HasValue)
{
pageSize = Int32.Parse(System.Web.Configuration.WebConfigurationManager.AppSettings["TechPageSize"]);
}
var records = new GridList<DisposedResources>();
records.currentfilter = filter;
records.TotalRecords = GetDisposedResourcesForGridCount(filter, resourcetype);
records.hasNetworkInfo = false;
records.hasSystemInfo = false;
records.CurrentPage = page;
records.PageSize = pageSize.Value;
records.currentsort = sort;
records.currentsortdir = sortdir;
records.Content = tms.DisposedResources.Include(a=>a.Technology).Where(x => (filter == null ||
(x.Technology.Tag.ToLower().StartsWith(filter.ToLower()))
) && x.ResourceType.ToLower() == resourcetype.ToLower())
.OrderBy(sort + " " + sortdir)
.Skip((page - 1) * pageSize.Value)
.Take(pageSize.Value).ToList();
return records;
}
the Disposed view is :-
#model S.ViewModels.GridList<S.Models.DisposedResources>
Show #Html.DropDownList("FilterSize", new SelectList(ViewBag.PagedSizeOptions, "Value", "Text", ViewBag.pagesize ), new { #id= "FilterSize1",#class="SmallDropDown3"}) <span class="hidden-phone">per page.</span>
<div id="disposed">
#Html.Partial( "_disposed",Model)
</div>
#section Scripts {
<script type="text/javascript">
$("body").on('change', '#FilterSize1', function () {
//$(SizeProgressSort).show();
$.ajaxSetup({ cache: false });
$.ajax({
type: "Get",
url: '#Url.Action("Disposed")',
data: { pageSize: $('#FilterSize1').val(), page: "1", sort: $('#currentsort').val(), sortdir: $('#currentsortdir').val() },
success: successFunc,
error: errorFunc
});
function successFunc(data, status) {
$('#disposed').html(data);
}
function errorFunc() {
alert('error');
}
});
</script>
}
and the _disposed partial view is:-
#model S.ViewModels.GridList<S.Models.DisposedResources>
var gridcolumns = new List<WebGridColumn>();
gridcolumns.Add(new WebGridColumn()
{
ColumnName = "Technology.Tag",
Header = Html.DisplayNameFor(model => model.Content.FirstOrDefault().Technology.Tag).ToString(),
CanSort = true
});
//code goes here...
var grid = new WebGrid(
canPage: true,
rowsPerPage: Model.PageSize,
canSort: true,
ajaxUpdateContainerId: "grid");
grid.Bind(Model.Content, rowCount: Model.TotalRecords, autoSortAndPage: false);
grid.Pager(WebGridPagerModes.All);
#grid.GetHtml(htmlAttributes: new { id = "grid" }, // id for ajaxUpdateContainerId parameter
fillEmptyRows: false,
tableStyle: "table table-bordered table-hover",
mode: WebGridPagerModes.All,
columns: gridcolumns
);
}
</div></div></div>
<input type="hidden" value="#Model.currentsort" id="currentsort" /> #Model.currentsort
<input type="hidden" value="#Model.currentsortdir" id="currentsortdir" /> #Model.currentsortdir
the problem i am facing is that the two parameters; currentsort + currentsortdir which are being passed as part of the javascript will not be changed,and the user will loose the current sort order if he chose to chnage the page size drop down-list. so can anyone advice what is the problem, now even if i chose to display the two values:-
Model.currentsort
&
Model.currentsortdir
they will always have the defualt value, although these values are being changed inside the repository method... but seems the partial view is somehow caching the old values for these two parameter ?
The ModelState is probably overriding the values you changed in your model. Call ModelState.Clear() in your action method and you should see the changed values.
I know that you have done the cache setting through ajaxSetup but try putting cache:false inside your script and see if that makes a difference.
$.ajax({
cache: false
type: "Get",
url: '#Url.Action("Disposed")',
--------

Categories