Asp.net mvc - implementing autofill tag selection for a blog?

I am working on a blog system for my own use and would like to implement automatic tag selection (similar to stackoverflow), how would I implement something like this? Any example or tutorial links would be appreciated.

Thanks.

+4
source share
4 answers

I decided to give jQuery UI Autocomplete a try, and it seems simple enough :) Here is the javascript code:

$(document).ready(function () { function split(val) { return val.split(/,\s*/); } function extractLast(term) { return split(term).pop(); } $("#TagsString") // don't navigate away from the field on tab when selecting an item .bind("keydown", function (event) { if (event.keyCode === $.ui.keyCode.TAB && $(this).data("autocomplete").menu.active) { event.preventDefault(); } }) .autocomplete({ source: function (request, response) { $.get("/Blog/GetTags", { term: extractLast(request.term) }, function (data) { response($.map(data.tags, function (item) { return { label: item.Name, value: item.Id } })) }, "json"); }, minLength: 2, dataType: 'json', focus: function () { // prevent value inserted on focus return false; }, select: function (event, ui) { var terms = split(this.value); // remove the current input terms.pop(); // add the selected item terms.push(ui.item.label); // add placeholder to get the comma-and-space at the end terms.push(""); this.value = terms.join(", "); return false; } }); }); 

Here's the HTML:

 <p> @Html.TextBoxFor(Model => Model.TagsString, new { @tabindex = "2", @size = "22", @value = "", @class = "text_input" }) <label for="TagsString"> <strong class="leftSpace">Tags</strong></label></p> <style> .ui-autocomplete-loading { background: white url('/Content/Images/ui-anim_basic_16x16.gif') right center no-repeat; } </style> 

And here is the action:

 [HttpGet] public virtual JsonResult GetTags(string term) { var getTags = _tag.All().Where(t => t.Name.ToLower().Contains(term.ToLower())).OrderBy(t => t.Name).ToList(); TagViewModel model = new TagViewModel() { Tags = Mapper.Map<List<Tag>, List<TagModel>>(getTags) }; return Json(new { tags = model.Tags }, JsonRequestBehavior.AllowGet); } 

It works well :)

+4
source

See my question here jQuery, autocomplete using json, id and display values

We actually โ€œborrowedโ€ (read the copy and pasted) SO autofill javascript, and then slightly changed it - for example, renamed it so that it would not interfere with jquery ui autocomplet e.

Both are actually very similar, but we wanted to specifically have a tag system like SO.

you can use the code that i used http://pastebin.com/t29RCCZg

and here is an example of the action we used for tags

 public ActionResult ProfileTags(string prefix, int? limit) { if (!limit.HasValue) limit = ConfigurationHelper.Paging.TagList; if (String.IsNullOrEmpty(prefix)) prefix = String.Empty; ProfileTagModel model = new ProfileTagModel() { Tags = profileTagRepository.GetList(new ProfileTagsByPrefixQuery(prefix)).OrderBy(x => x.Name).Take<ProfileTag>(limit.Value) }; return View(model); } 

And the view looks like this:

 <%@ Page Language="C#" ContentType="text/html" Inherits="System.Web.Mvc.ViewPage<ProfileTagModel>" %> <% if(Model.Tags != null) { %> <% foreach (ProfileTag tag in Model.Tags) { %> <%= tag.Name + ((tag.ProfileCount > 0) ? " (" + tag.ProfileCount.ToString() + ")" : String.Empty) %> <% } %> <% } %> 

And then our use on the page looks something like this.

 $().ready(function () { $("#ProfileTags").troppinautocomplete('<%= Url.Action("ProfileTags", "Filter") %>', { max: 10, highlightItem: true, multiple: true, multipleSeparator: " ", matchContains: false, scroll: true, scrollHeight: 300, dataType: "html" }); }) 

You donโ€™t have to do this. You can force the action method to return an array of objects as json, and then by changing the way your autocomplete is declared, you can actually format the tags for display using the icon or other functions.

Here is an example that json took for formatted view

 $('#troppinSearch').troppinautocomplete(url, { dataType: 'json', parse: function (data) { var rows = new Array(); if (data != null) { for (var i = 0; i < data.length; i++) { rows[i] = { data: data[i], value: data[i].Id, result: data[i].Title }; } } return rows; }, formatItem: function (row, i, n) { return '<table><tr><td valign="top"><img height="28" width="28" src="' + row.ImageUrl + '" /></td><td valign="top" style="padding:0px 0px 0px 6px;"><div>' + row.Title + '</div><div><small>' + row.ResultType + '</small></div></td></tr></table>'; }, formatResult: function (row, i, n) { return row.Id; }, width: 336, max: 20, highlightItem: true, multiple: false, matchContains: true, scroll: true, scrollHeight: 300 }).result(function (event, data, formatted) { var type = data.ResultType.toLowerCase(); var id = data.Id; if (type == "product") { window.location.href = '/Shop/Product/' + id; } else { window.location.href = '/Profile/Index/' + id; } }); 

And the action looks like this:

 public ActionResult Search(string contentType, string prefix, int? limit) { if (!limit.HasValue) limit = ConfigurationHelper.Paging.ProfileList; SearchResponse response = GetSearchResults(contentType, prefix); var dropDownResults = (from r in response.Results select new { Id = r.Id, Title = r.Name, ImageUrl = r.DefaultImage, ResultType = r.ResultType.ToString() }).Distinct().Take(limit.Value); return Json(dropDownResults.ToList(), JsonRequestBehavior.AllowGet); } 

When you do this, you do not need a view. Autostart takes json data and does everything magically. The .Result function at the end allows you to customize the event that occurs when selected. in this case, it actually sends the user to another page, but we used it to set the value in a hidden field.

EDIT

I forgot the built-in CSS classes for this code. Here is an example of CSS.

 .ac_results{ padding:0; border:1px solid #4c4c4c; background-color:#ffffff; overflow:hidden; z-index:99999; text-align:left; font-size: 14px; line-height:14px; color: #333333; } .ac_highlight{ font-weight:bold; text-decoration:underline; background-color: #ff6600; color: #ffffff; } .ac_results ul{ width:100%; list-style-position:outside; list-style:none; padding:0; margin:0; } .ac_results li{ margin:0; padding:3px 6px 3px 6px; cursor:default; display:block; line-height:14px; overflow:hidden; } .ac_loading{ background:#fff url(/Content/images/loading.gif) right center no-repeat; } .ac_over{ background-color:#ff6600; color:#ffffff; } 
+7
source

I use jQuery UI autocomplete, but preload the data;

View:

 @Html.TextBoxFor(Model => Model.Tags, new { @class = "txtbox-long" }) @Html.Resource(@<link href="@Url.Content("~/Content/CSS/flick/jquery-ui-1.8.11.css")" rel="stylesheet" type="text/css" />, "css") @Html.Resource(@<script src="@Url.Content("~/Content/JS/jquery-ui-1.8.11.min.js")" type="text/javascript" language="javascript"></script>, "js") @Html.Resource( @<script type="text/javascript" language="javascript"> $(document).ready(function () { var tags; $.getJSON("/Thread/GetTags", function (data) { tags = data; }); function split(val) { return val.split(/ \s*/); } function extractLast(term) { return split(term).pop(); } $("#Tags") // don't navigate away from the field on tab when selecting an item .bind("keydown", function (event) { if (event.keyCode === $.ui.keyCode.TAB && $(this).data("autocomplete").menu.active) event.preventDefault(); }) .autocomplete({ delay: 0, minLength: 0, source: function (request, response) { response($.ui.autocomplete.filter(tags, extractLast(request.term))); }, focus: function () { // prevent value inserted on focus return false; }, select: function (event, ui) { var terms = split(this.value); // remove the current input terms.pop(); // add the selected item terms.push(ui.item.value); // add placeholder to get the space at the end terms.push(""); this.value = terms.join(" "); return false; } }); }); </script> , "js") 

Controller:

 [Classes.Attributes.Ajax] public JsonResult GetTags() { return Json( TagService.GetTags().Select(x => x.Name), "text/plain", JsonRequestBehavior.AllowGet ); } 

It works well and saves several calls to the database as it uses client-side search. I use it in a small project, so there will not be many tags.

+3
source

You can call the action method, which will take the text that they are currently entering, and return the view with a filled list of possible tags.

Your action method might look like this:

 public ActionResult GetTags(string tag) { List<string> tags = // get AutoComplete data from somewhere return View(tags); } 

And your Autocomplete View could be simple:

 <%@ Page Language="C#" Inherits="ViewPage<IList<string>>" %> <ul> <% foreach(string tag in Model) { %> <li><%=tag %></li> <% } %> </ul> 

And if you use jQuery, you can try:

 $.ajax({ url: "Autocomplete/GetTags/" + tag, cache: false, success: function(html) { $("#autocomplete").html(html); } }); 
+1
source

Source: https://habr.com/ru/post/1333712/


All Articles