Динамически создаваемые представления: заполнять метаданные свойств во вложенное представление для проверки на стороне клиента?

#c# #.net #asp.net-mvc #validation

#c# #.net #asp.net-mvc #проверка

Вопрос:

Я реализовал базовую модель представления для форм конфигурации различных модулей в моей системе.

В этой базовой логике я повторяю отраженные свойства (пользовательской) производной viewmodel и динамически создаю список объектов ConfigItem

Упрощенный мой объект выглядит следующим образом:

 public class ConfigItem
{ 
     public string Key { get; set; }
     public object Value { get; set; }
     public  Type PropertyType { get; set; } 
     public ConfigType ConfigType { get; set; }
     public string PostId { get; set; } 
};
  

Свойство «значение» может быть объектом простого или сложного типа (строка, bool image и т. Д.).

Во вложенном представлении я отображаю все элементы конфигурации в цикле (чтобы украсить каждый дополнительной информацией, такой как всплывающие подсказки и т.д.). Для привязки опубликованной формы я устанавливаю атрибут name полей ввода, чтобы значения привязывались к свойствам viewmodel оригинала. Проверка атрибутов DataAnnotation работает на стороне сервера.

Теперь к проблеме:

Как мы все знаем, ASP поставляется с удобной функцией отображения ненавязчивых атрибутов проверки jquery. К сожалению, я теряю все свои метаданные при рендеринге конфигурационных элементов вместо исходных свойств, поэтому ASP не знает о моих атрибутах, таких как, например, «Required» или «StringLength». У кого-нибудь есть идея, как каким-то образом «перенести» метаданные свойства?

Лучше всего было бы, чтобы значением моего ConfigItem могло быть дерево выражений типа Expression> , чтобы я мог переносить «указатель» на исходное свойство. Но я не мог понять, как это технически решить. Если бы кто-нибудь мог пролить немного света на это (или, возможно, иметь какие-то другие подсказки) Я очень ценю это. Спасибо!

Обновление: я визуализирую свои конфигурационные элементы с помощью небольшого пользовательского Html-помощника, где я оцениваю состояние модели:

 public static MvcHtmlString ConfigItem<TModel>(this HtmlHelper<TModel> htmlHelper, ConfigItem configItem, bool isEditMode = false)
    {
        if (isEditMode)
        {
            if (!htmlHelper.ViewData.ModelState.IsValidField(configItem.PostId))
            {
                var itemState = htmlHelper.ViewData.ModelState[configItem.PostId];

                if (itemState.Errors.Count > 0)
                {
                    configItem.ValidationMessage = string.Join("</br>", Array.ConvertAll(itemState.Errors.ToArray(), i => i.ErrorMessage));
                }
            }
            return htmlHelper.Partial(EditorConfigItemPartialPath, configItem);
        }
        else
        {
            return htmlHelper.Partial(DisplayConfigItemPartialPath, configItem);
        }
    }
  

ConfigItem EditorTemplate делает что-то вроде этого:

 @model ConfigItem    
<div class="value">
@switch (Model.DataType)
{
    case ConfigDataType.String:
        {
            var value = Model.Value == null ? "" : Model.Value;
            @Html.EditorFor(m => value, "string", Model.PostId)
            break;
        }
    case ConfigDataType.Bool:
        {
            @Html.EditorFor(m => Model.Value, "", Model.PostId)
            break;
        }
    case ConfigDataType.Image:
        {
            @Html.ConfigImage(Model.Key, m => Model.Value, Url.Action(ApplicationController.ActionUploadImage), Model.PostId)
            break;
        }
}
@if (!string.IsNullOrEmpty(Model.ValidationMessage))
{
    <span class="@errorClass">
        @Html.Raw(Model.ValidationMessage)
    </span>
}
</div>
  

Комментарии:

1. как вы визуализируете конфигурационные элементы? Через jQuery AJAX или только вашим кодом?

2. Я обновил свой вопрос для дальнейшего уточнения.

3. итак, вы потеряли свои скрипты при частичном просмотре, верно?

4. Точно, я потерял все метаданные свойств при установке их значений в элемент конфигурации «объекты». Я также попробовал пользовательский ModelValidatorProvider, но там я не могу сделать вывод из «объекта» обратно к исходному свойству view models.

Ответ №1:

Если ваш сценарий не соответствует вашему частичному представлению, вы можете использовать приведенный ниже код:

Общая функция для загрузки скрипта в частичное представление :

 function loadScript(url, callback){

    var script = document.createElement("script")
    script.type = "text/javascript";

    if (script.readyState){  //IE
        script.onreadystatechange = function(){
            if (script.readyState == "loaded" ||
                    script.readyState == "complete"){
                script.onreadystatechange = null;
                callback();
            }
        };
    } else {  //Others
        script.onload = function(){
            callback();
        };
    }

    script.src = url;
    document.getElementsByTagName("head")[0].appendChild(script);
}
  

и вызовите эту функцию в свой оператор switch, как показано ниже :

 @switch (Model.DataType)
{
    case ConfigDataType.String:
        {
            var value = Model.Value == null ? "" : Model.Value;
            @Html.EditorFor(m => value, "string", Model.PostId)
            loadScript("~/Content/js/register.js", function(){
            //initialization code
            });
            break;
        }
    case ConfigDataType.Bool:
        {
            @Html.EditorFor(m => Model.Value, "", Model.PostId)
            loadScript("~/Content/js/register.js", function(){
            //initialization code
            });
            break;
        }
    case ConfigDataType.Image:
        {
            @Html.ConfigImage(Model.Key, m => Model.Value, Url.Action(ApplicationController.ActionUploadImage), Model.PostId)
            loadScript("~/Content/js/register.js", function(){
            //initialization code
            });
            break;
        }
}
  

~/Content/js/register.js замените требуемым JavaScript

надеюсь, это вам поможет.

Спасибо

Комментарии:

1. Большое спасибо за ваш ответ. Это хороший метод для загрузки сценариев. Но я не хочу связываться с js там и вместо этого использую функции mvc, которые генерируют правильные атрибуты html. Если в моем свойстве viewmodel определен атрибут [Required], я хочу, чтобы мои помощники автоматически генерировали атрибут html aria-required=»true». Поэтому помощникам нужен правильный контекст модели / свойства. Я ценю вашу помощь, спасибо!

2. Я думаю, что этот атрибут уже есть, только вы не получаете unobtrusive js в свой частичный вид. С этой проблемой я также столкнулся, моя проверка (проверка аннотаций данных) не работает в частичном представлении. Затем я вызываю ненавязчивый js с этим кодом, и у меня все работает нормально.

3. Конечно, пожалуйста, отметьте и поддержите мое решение, если оно вам поможет, спасибо