Проверка на основе ViewModel с помощью Angular

Я хотел бы иметь объект модели представления JavaScript, который содержит правила проверки, похожие на модели просмотра ASP.NET MVC с аннотациями данных, которые я могу привязать к представлениям Angular. Тогда я бы, например, например, вызвать метод Validate для этого объекта на определенных этапах его жизни, прежде чем отправлять его на сервер.

Это позволило бы мне оставаться близким к MVVM-подобному подходу, где пользовательский интерфейс довольно легкий и не интеллектуальный, а модель представления, любая модель представления, представленная представлением, должна требовать изменений в разметку вида для изменения правил проверки.

Таким образом, я даже могу использовать аннотации данных MVC для создания сериализуемой модели представления с правилами на сервере и возврата этой модели и всех ее валидаций и т.д. клиенту как JSON.

Как я могу добиться такого типа проверки в Angular, по сравнению с гораздо более распространенной проверкой свойств элемента/модели, достигнутой с помощью директив?

Ответ 1

Я реализовал что-то, что может помочь вам в самом последнем проекте, над которым я работаю. Мы используем AngularJS на интерфейсе и ASP.NET WEB API на внутреннем сервере. Все формы HTML генерируются автоматически на основе свойств и аннотаций данных, содержащихся в моих классах POCO.

На стороне сервера у меня есть сущности и DTO. Мои сущности содержат аннотации, специфичные для базы данных, и DTO содержат мои аннотации, специфичные для просмотра. Я приведу краткий пример, показывающий одно свойство в одном классе и как я создаю интерфейс для этого. Вот серверные объекты:

public class Discount
{
    [StringLength(40)]
    [Required]
    public String Name { get; set; } 
}

public class DiscountDto : IDto<Discount>
{
    [Display(ResourceType = typeof(ApplicationStrings), Name = "Name", ShortName = "Name_Placeholder")]
    [UI(Row = 1, Width = 6)]
    public String Name { get; set; }
}

Это свойство отображается в пользовательском интерфейсе следующим образом:

<div class="form-group">
  <label class="col-sm-2 control-label"> Name: </label> 
  <div class="col-sm-6"> 
    <input class="form-control" ng-model="model[options.key]"  required="required" maxlength="40" placeholder="Enter the name...">
  </div>
</div>

Поле <input /> имеет автоматические настройки свойств required, placeholder и maxlength. Метка HTML, ширина столбца начальной загрузки также автоматически настраиваются на основе пользовательской аннотации данных UI. Строка = 1 означает отображение этого поля сначала в форме, а ширина = 6 означает, что поле должно занимать ширину столбца 6: class="col-sm-6". Текст ярлыка и текст заполнителя извлекаются из файлов ресурсов. Если это то, что вы ищете, тогда прочитайте: -)

Я создал контроллер MetaController, который принимает имя DTO как параметр: api/Meta/DiscountDTO например. Этот контроллер просто выполняет все свойства объекта DTO и связанного с ним объекта и вытаскивает аннотации данных, преобразует их в класс FormMetadata и возвращает List<FormMetadata> клиенту. Класс FormMetadata просто содержит такие свойства, как IsRequired, IsDisplayed, IsReadonly и т.д., Чтобы превратить аннотации во что-то более читаемое для разработчиков интерфейсов. Вот фрагмент из MetaController:

var type = Type.GetType("<DTO_goes_here>");
List<FormMetadata> formMetadata = new List<FormMetadata>();

foreach (var prop in type.GetProperties())
{
    var metadata = new FormMetadata();
    metadata.Key = prop.Name.ToLower().Substring(0, 1) + prop.Name.Substring(1, prop.Name.Length - 1);
    metadata.Type = prop.PropertyType.FullName;

    object[] attrs = prop.GetCustomAttributes(true);

    foreach (Attribute attr in attrs)
    {
        if (attr is RequiredAttribute)
        {
            metadata.IsRequired = true;
        }
        else if (attr is StringLengthAttribute)
        {
            var sla = (attr as StringLengthAttribute);
            metadata.MinLength = sla.MinimumLength; 
            metadata.MaxLength = sla.MaximumLength;
        }
        // etc.
    }

    formMetadata.Add(metadata);
}

Эта конечная точка вернет следующий JSON для свойства Name:

{  
   "$id":"3",
   "key":"name",
   "display":"Name",
   "type":"System.String",
   "placeholder":"Enter the name...",
   "isRequired":true,
   "isEditable":true,
   "isDisplayed":true,
   "isReadonly":false,
   "displayInList":true,
   "width":6,
   "row":1,
   "col":0,
   "order":0,
   "maxLength":40,
   "minLength":0,
   "lookup":null,
   "displayAs":null
}

На стороне клиента я создал настраиваемую директиву Angular <entity-form />, которая принимает имя DTO как параметр:

<entity-form entity-type="DiscountDTO"></entity-form>. Затем эта директива вызовет MetaController, чтобы получить правила проверки для объекта Discount и отобразить форму на основе возвращенных правил. Чтобы отобразить форму, я использую огромную библиотеку под названием angular-formly. Эта библиотека позволяет создавать формы из javascript без написания HTML. Я не буду подробно описывать здесь angular -formly, но вы в основном создаете объект Javascript с информацией о форме, которую хотите отобразить, и передаете ее в директиву angular -formly, и она заботится о предоставляя форму для вас. Это базовый пример типа объекта, который вы передаете angular -формативно, для рендеринга окна <input /> с меткой "Текст":

{
  "key": "text",
  "type": "input",
  "templateOptions": {
    "label": "Text",
    "placeholder": "Type here to see the other field become enabled..."
  }
}

Итак, я в основном беру метаданные, возвращенные из MetaController, и создаю объект, который angular -форменно понимает и передает его в директиву angular -formly, и он отображает форму для меня. Я знаю, что этот ответ мог бы быть намного длиннее с большим количеством примеров и т.д., Но я чувствовал, что это было много, чтобы читать, как есть. Надеюсь, это даст вам достаточно информации.

Я хотел бы сделать это более общим и открытым исходным кодом - если кто-то заинтересован в том, чтобы работать над чем-то вроде этого, дайте мне знать: -)

Ответ 2

В соответствии с MVC и MVVM с AngularJS, AngularJS следует за шаблоном проектирования MVVM.

Я думаю, вам нужно что-то вроде Добавление ненавязчивой проверки клиента с Microsoft.NET MVC Framework на Angular.

Если вы хотите создать специальный HTML-помощник для Razor, см. Проверка в формах Angular, которая состоит из двух частей.

Я также нашел ngval, который кажется нестабильным.