asp.net mvc - реализовать выбор тегов "автозаполнение" для блога? - PullRequest
4 голосов
/ 29 декабря 2010

Я работаю над системой блогов для своего собственного использования и хотел бы реализовать выбор тегов с автозаполнением (по аналогии со стековым потоком), как бы я реализовал что-то подобное?Любой пример или ссылки на учебник будет принята с благодарностью.

Спасибо.

Ответы [ 4 ]

7 голосов
/ 29 декабря 2010

См. Мой вопрос здесь Jquery, автозаполнение с использованием json, значения идентификатора vs против отображения

Мы фактически "позаимствовали" (прочитали, скопировали и вставили) автозаполнение javascript SO, а затем слегка доработали его - такойкак его переименование, чтобы оно не мешало автозаполнению jquery ui e.

Они на самом деле очень похожи, но мы хотели специально иметь систему тегов, такую ​​как SO.

вы можете восстановить код, который я использовал http://pastebin.com/t29RCCZg

, и вот пример действия, которое мы использовали для тегов

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);
    }

И вид выглядит так

<%@ 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) %>
    <% } %>
<% } %>

И тогда наше использование на странице выглядит примерно так

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


})

Хотя вам не обязательно делать это таким образом.Вы можете заставить метод действия возвращать массив объектов в виде json, а затем, изменив способ объявления автозаполнения, можно фактически отформатировать теги для отображения со значком или другими функциями.

Вот пример, которыйвзял json для форматированного вида

$('#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;
        }
    });

И действие выглядит так

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);
    }

Когда вы делаете это таким образом, вам не нужно представление.Автозаполнение принимает данные json и делает все магическим образом.Функция .Result в конце позволяет вам настроить событие, которое происходит при выборе.в этом случае он фактически отправляет пользователя на другую страницу, но мы использовали его для установки значения в скрытом поле.

РЕДАКТИРОВАТЬ

Я забыл встроенныйCSS классы для этого кода.Вот пример 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;

}
4 голосов
/ 31 декабря 2010

Я решил попробовать jQuery UI Autocomplete, и это кажется достаточно простым :) Вот код javascript:

$(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;
                }
            });
});

Вот 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>

А вот и действие:

[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);
        }

Работает очень хорошо:)

3 голосов
/ 24 апреля 2011

Я использую автозаполнение пользовательского интерфейса jQuery, но загружаю данные заранее;

Просмотр:

@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")

Контроллер:

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

Работает очень хорошо и сохраняет несколько вызововв базу данных, поскольку он использует поиск на стороне клиента.Я использую его в небольшом проекте, поэтому тегов не будет много.

1 голос
/ 29 декабря 2010

Вы можете вызвать метод действия, который будет принимать текст, который они вводят в данный момент, и возвращать представление с заполненным списком возможных тегов.

Ваш метод действия может выглядеть следующим образом:

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

    return View(tags);
}

И ваш вид автозаполнения может быть просто:

<%@ Page Language="C#" Inherits="ViewPage<IList<string>>" %>

<ul>
    <% foreach(string tag in Model) { %>
    <li><%=tag %></li>
    <% } %>
</ul>

А если вы используете jQuery, вы можете попробовать:

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