在动态创建中使用 typeahead-mvc-model Html.AutoCompleteFor

using typeahead-mvc-model in dynamically created Html.AutoCompleteFor

我正在使用来自 timdwilson 的 typeahead package。不幸的是,当我将 AutoCompleteFor 框放在 for 循环中时,我 运行 遇到了问题,因为 lambda 表达式不能很好地与 AutocompleteHelpers class (特别是, Expression 评估者。

基本上,我得到的不是 model => model.SelectedIngredeints[i] model => model.SelectedIngredients.get_Item(value(ASP._Page_Views_Recipes_Create_cshtml+<>c__DisplayClass3_0).i)

C# 是否可以将 SelectedIngredients.get_Item(value(ASP._Page_Views_Recipes_Create_cshtml+<>c__DisplayClass3_0).i 计算为简单的 SelectedIngredients[i]


如果我没说清楚,这里有一些屏幕截图...

这里没问题,因为 model => model.testInt 已经(?)评估或引用了。


但是,当我尝试使用我的迭代器时,会发生以下情况。

我是 timdwilson,我创建了您遇到问题的 Twitter.Typeahead.MVC.Model NuGet 包和 typeahead-mvc-model GitHub 存储库。在查看您的问题后,我发现 AutocompleteFor 为输入元素的 data-autocomplete-id-field 属性生成的 HTML 应该是 SelectedIngredients_0_ 但实际上是SelectedIngredients.get_Item(value(ASP._Page_Views_Recipes_Create_cshtml+<>c__DisplayClass3_0).i).

换句话说,您期待的是:

<input class="form-control typeahead" data-autocomplete-id-field="SelectedIngredients_12_" data-autocomplete-url="/Recipes/GetIngredients" id="SelectedIngredientsNames_12_" name="SelectedIngredientsNames[12]" type="text" value="" />

但是,相反,我们得到了这个:

<input class="form-control typeahead" data-autocomplete-id-field="SelectedIngredients.get_Item(value(ASP._Page_Views_Recipes_Create_cshtml+<>c__DisplayClass3_0).i)" data-autocomplete-url="/Recipes/GetIngredients" id="SelectedIngredientsNames_12_" name="SelectedIngredientsNames[12]" type="text" value="" />

由于 data-autocomplete-id-field 用于在页面上查找此元素并设置它的值,因此在选择预输入值时从未捕获所选 ID。

我通过正确生成 HTML 来解决这个问题,就像生成 valueExpression 一样。此修复将出现在 Twitter.Typeahead.MVC.Model version 1.0.6 NuGet package and it has already been checked in to the typeahead-mvc-model GitHub repository.

要在您的本地副本中修复此问题,请将 Controllers\HtmlHelpers 文件夹(或您将其移动到的任何位置)中的 AutocompleteHelpers class 替换为以下代码:

public static class HtmlHelpers {

    /// <summary>
    /// Extends MvcHtml to conditionaly display a value or empty string
    /// </summary>
    /// <param name="value">Value to be displayed if 'evaluation' is true</param>
    /// <param name="evaluation"></param>
    /// <returns></returns>
    public static MvcHtmlString If(this MvcHtmlString value, bool evaluation) {
        return evaluation ? value : MvcHtmlString.Empty;
    }

    /// <summary>
    /// Extends MvcHtml to conditionaly display one of two possible values
    /// </summary>
    /// <param name="value">Value to be displayed if 'evaluation' is true</param>
    /// <param name="evaluation"></param>
    /// <param name="valueIfFalse">Value to be displayed if 'evaluation' is false</param>
    /// <returns></returns>
    public static MvcHtmlString If(this MvcHtmlString value, bool evaluation, MvcHtmlString valueIfFalse) {
        return evaluation ? value : valueIfFalse;
    }
}

public static class AutocompleteHelpers
{
    public static MvcHtmlString AutocompleteFor<TModel, TProperty1, TProperty2>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty1>> valueExpression,
        Expression<Func<TModel, TProperty2>> idExpression, string actionName, string controllerName, bool requestFocus)
    {
        return CreateTextBoxForFromAutocompleteFor<TModel, TProperty1, TProperty2>(html, valueExpression, actionName, controllerName, requestFocus,
            idExpression.Body.ToString());
    }

    public static MvcHtmlString AutocompleteFor<TModel, TProperty1, TProperty2>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty1>> valueExpression,
        Expression<Func<TModel, TProperty2>> idExpression, int index, string actionName, string controllerName, bool requestFocus)
    {
        // Get the fully qualified class name of the autocomplete id field
        string idFieldString = idExpression.Body.ToString();

        // handle if the id field is an array
        int loc_get_Item = idFieldString.IndexOf(".get_Item(");
        if (loc_get_Item > 0)
        {
            idFieldString = idFieldString.Substring(0, loc_get_Item);
            idFieldString += string.Format("_{0}_", index);
        }

        var textBoxFor = CreateTextBoxForFromAutocompleteFor<TModel, TProperty1, TProperty2>(html, valueExpression, actionName, controllerName, requestFocus, idFieldString);
        return textBoxFor;
    }

    private static MvcHtmlString CreateTextBoxForFromAutocompleteFor<TModel, TProperty1, TProperty2>(HtmlHelper<TModel> html,
        Expression<Func<TModel, TProperty1>> valueExpression, string actionName, string controllerName, bool requestFocus, string idFieldString)
    {
        string autocompleteUrl = UrlHelper.GenerateUrl(null, actionName, controllerName,
                                                       null,
                                                       html.RouteCollection,
                                                       html.ViewContext.RequestContext,
                                                       includeImplicitMvcValues: true);
        string @class = "form-control typeahead" + (requestFocus ? " focus" : string.Empty);
        // We need to strip the 'model.' from the beginning
        int loc = idFieldString.IndexOf('.');
        // Also, replace the . with _ as this is done by MVC so the field name is js friendly
        string autocompleteIdField = idFieldString.Substring(loc + 1, idFieldString.Length - loc - 1).Replace('.', '_');
        var textBoxFor = html.TextBoxFor(valueExpression,
            new {data_autocomplete_url = autocompleteUrl, @class, data_autocomplete_id_field = autocompleteIdField});
        return textBoxFor;
    }
}

如果此修复对您有效,请接受此作为您问题的答案。如果您有任何其他问题或困难,请告诉我。谢谢罗里!