Pull to refresh

AngularJS vs IML

Reading time 7 min
Views 8.5K
image

disclaimer: сравнение не подразумевает поднятие “холивара”, а делает обзор задач, решаемых одним инструментом в сравнении с другим. Я не являюсь знатоком всех тонкостей angularJs, но прочитав 10 статьей обзора этого инструмента, привожу альтернативный пример решения тех же самых задач на IML.


Что будем сравнивать ?


  • Controller
  • Inheritance
    примечание: отсутствует в IML
  • Accessing server
  • Push data
  • Submit form
  • Template
  • Promises
    примечание: отсутствует в IML и может быть полезным только при работе со сторонними сервисами, а так решается все с помощью продуманного выбора данных для возврата.


Я выбрал те возможности, которые имеют смысл, потому что в рамках asp.net mvc пользу в перемененных, константах, а также в поддержке локализации не вижу.
примечание: далее часто будет учитываться то, что разработка проходит в рамках asp.net mvc

Как будем сравнивать ?


Методика очень простая, привожу листинг AngularJS ( View и Js ) и IML ( только View ) варианта, далее аргументирую чем же IML лучше. Я буду выделять только плюсы, но буду рад увидеть и отрицательные стороны IML в комментариях, поэтому все свои замечания можно высказать.

Controller

Angular JS View

<div ng-controller="angularController">
<button ng-click="sayHello()">Say</button>
</div>

Angular JS

app.controller('angualrController', function ($scope) {
  $scope.sayHello = function(){
      alert('Hello')  
  } 
});

IML

@(Html.When(JqueryBind.Click)
      .Do()
      .Direct()
      .OnSuccess(dsl => dsl.Utilities.Window.Alert("Hello"))
      .AsHtmlAttributes()
      .ToButton("Say"))


Чем лучше :

  • Поведение и разметка вместе
    примечание: многим данный момент покажется спорным, из-за того, что логика усложняет работу верстальщикам страниц, но в рамках asp.net mvc, C# код во View ( cshtml ) неотъемлемая часть и поэтому те преимущества, которые можно получить полностью перекрываю довольно таки абстрактную модель разработки логики отдельно от разметки.
  • Поддержка Initilesence
    примечание: атрибуты AngularJs не являются стандартом html, поэтому подсветки синтаксиса или авто-дополнения не будет, а IML это C# библиотека.
  • События представляют флаги
    примечание: упрощает группировку, когда надо продублировать действия для другого события When(JqueryBind.Click | JqueryBind.Focus)
  • Управлением поведением события ( Prevent Default, Stop Propagation)
    примечание: AngularJS позволяет управлять этим в рамках метода контроллера, но IML включает это как часть общей схемы


Accessing Server

Серверный код

public ActionResult Get(GetProductByCodeQuery query)
{
 List  vms = dispatcher.Query(query);
 return IncJson(vms); // for AngularJs need use Json with AllowGet
}

примечание: серверная часть одинакова, как для AngularJS, так и для IML
Angular Html

<div ng-conroller="productController">
 @Html.TextBoxFor(r => r.Code)
 <label>{{model.Name}}</label>
 <button>Get name</button>
</div>

Angular Js

kitchen.controller('productController', function ($scope, $http) {
  $scope.get = function(){
    $http.get({
                url:'product/get',
                params:{Code:$('[Name="Code"]').val()}
              })
          .success(function(data) { 
              $scope.Name = data.Name
           });
 }
});

IML

@{ var labelId = Guid.NewGuid().ToString(); }
@Html.TextBoxFor(r=>r.Code)
@(Html.When(JqueryBind.Click)
  .Do()
  .AjaxGet(Url.Action("Product","Get",new {
                       Code = Html.Selector().Name(r=>r.Code)
                      })
  .OnSuccess(dsl => dsl.WithId(labelId).Core().Insert.For(r=>r.Name).Text())
  .AsHtmlAttributes()
  .ToButton("Get name"))

примечание: при построение url, можно использовать в качестве Routes не только анонимный объект, но и типизированный вариант Url.Action(“Product”,”Get”,new GetProductQuery() { Code = Html.Selector().Name(r=>r.Code) })

Чем лучше:

  • Типизация на всех этапах
    • Url – адрес в AngularJs строится без серверной части, что не позволяет учитывать route и отсутствие возможности перейти ( переименовать ) в Action из кода.
      примечание: по скольку руководство по AngularJs рекомендует выносить JavaScript код во внешний файл, то по этой причине не получится использовать серверные переменные в рамках js кода.
    • Query – AngularJs не связан с серверной моделью и не позволяет получить схему модели, что как и в случае с Url не позволяет использовать инструменты для переименования и go to declaration
      примечание: в случаи с IML, если мы переименуем поле Name или Code в GetProductQuery, то изменения отразятся и на клиентскую часть, но для AngularJs придется дополнительно заменить {{model.Name}} и $(‘[Name=«code»]‘) на новые значения.
    • Selector – для указания параметров запроса в рамках IML можно использовать мощный инструмент для получения значений из Dom ( hash, cookies, js variable and etc ) объектов

  • MVD

В Incoding Framework можно обойтись без написания дополнительных Controller и Action если в качестве url применить MVD
Url.Dispatcher().Query(new GetProductQuery() {Code = Html.Selector().Name(r=>r.Code)}).AsJson()


Push data

Серверный код

public ActionResult Add(AddCommand input)
{ 
dispatcher.Push(input);
return IncJson(); // for AngularJS need use Json()
}

примечание: серверная часть одинакова, как для AngularJS, так и для IML

Angular View

<div ng-controller="productController">
  @Html.TextBoxFor(r => r.Name) 
  @Html.CheckboxFor(r => r.IsGood)
  <button ng-click="add"> Add </button>
</div>

Angular JS

kitchen.controller('productController', function ($scope, $http) {
 $scope.add = function(){ 
   $http({
       url: 'product/Add',
       method: "POST",
       data: { 
             Name : $('[name="Name"]').val(),
             IsGood : $('name="IsGood"]').is(':checked')
             }
         })
      .success(function(data) { alert('success') });
});

IML

@Html.TextBoxFor(r=>r.Name)
@Html.CheckboxFor(r=>r.IsGood)
@(Html.When(JqueryBind.Click)
      .Do()
      .AjaxPost(Url.Action("Product","Add",new {
                                                 Name = Html.Selector().Name(r=>r.Name),
                                                 IsGood = Html.Selector().Name(r=>r.IsGood)
                                               }))
      .OnSuccess(dsl => dsl.Utilities.Window.Alert("Success"))
      .AsHtmlAttributes()
      .ToButton("Add"))


Чем лучше:

  • MVD
    как и в предыдущем примере когда мы делали Query, в Incoding Framework можно выполнять push без написания Action
    Url.Disaptcher().Push( new {
                                       Name = Html.Selector().Name(r=>r.Name),
                                       IsGood = Html.Selector().Name(r=>r.IsGood)
                                })
    

  • Selector абстрагирует от способа получения значения
    примечание: на примере видно, что для получения значения из checkbox нужно использовать is(‘:checked’), но в IML этот момент не требуется указывать


Submit Form

Angular View

<div ng-controller="productController"> 
  <form name="AddForm">
    @Html.TextBoxFor(r => r.Name)
    @Html.CheckboxFor(r => r.IsGood) 
    <input type="submit" value="save"  ng-submit="submit" />
  </form>
</div>

Angular JS

controller('productController', function ($scope, $http) {
 $scope.submit = function(){ 
   $http({
       url: 'product/Add',
       method: "POST",
       data: angular.toJson($scope.addForm)
        }).success(function(data) { alert('success') });
});

IML

@using(Html.When(JqueryBind.Submit)
           .DoWithPreventDefault()
           .Submit()
           .OnSuccess(dsl => dsl.Utilities.Window.Alert("Success"))
           .AsHtmlAttributes()
           .ToBeginForm(Url.Action("Product","Add")))
 {
    @Html.TextBoxFor(r=>r.Name)
    @Html.CheckboxFor(r=>r.IsGood)
    <input type="submit" value="add">
 }

Чем лучше:

  • Отправка формы в одну строку
    примечание: angularJs работает с формой точно так же, как и с обычным ajax запросом, что требует указания параметров Url, Type, Data

Template


Серверный код

public ActionResult Fetch()
{
   var vms = new List()
     {
      new PersonVm(){ Last= "Vasy", First = "Smith", Middle = "Junior"},
      new PersonVm(){ Last= "Vlad", First = "Smith", Middle = "Mr"},
     };
  return IncJson(vms); // for angular need use Json with AllowGet
}

примечание: серверная часть одинакова, как для AngularJS, так и для IML
Angular Template

<script id="person.html" type="text/ng-template">
{{person.last}}, {{person.first}} {{person.middle}}
</script>

Angular View

<div ng-controller="productAddForm">
  <div ng-repear="person in persons" ng-template="person.html">   
  </div>
</div>

Angular JS

app.controller('personController', function ($scope,$http) {
   $scope.refresh= function(){
      $http.get('person/fetch', function(data){ 
                          $scope.Persons= data 
      });
   } 
});

IML Template

@{
    var tmplId = Guid.NewGuid().ToString();
    using (var template = Html.Incoding().Template(tmplId))
    {
      using (var each = template.ForEach())
      {  @each.For(r=>r.First),@each.For(r=>r.Middle),@each.For(r=>r.Last) }
    }
}

IML View

@(Html.When(JqueryBind.InitIncoding)
 .Do()
 .AjaxGet(Url.Action("Personal","Fetch"))
 .OnSuccess(dsl => dsl.Self().Core().Insert.WithTemplate(tmplId.ToId()).Html())
 .AsHtmlAttributes()
 .ToDiv())

Чем лучше :


  • Опять типизация
    примечание: Incoding template требует больше кода для реализации типизированного синтаксиса, но это окупается при дальнейшей поддержке
  • Один template для одного или многих объектов
  • Замена template engine
  • Поиск template по Selector, что имеет больше возможностей ( ajax, cookies and etc )
  • Cache
    AngularJs имеет механизм работы с Cache, но с очень важными отличиями
    • Требует настройки для каждого template отдельно
      myApp.run(function($templateCache) {
        $templateCache.put('templateId.html', 'This is the content of the template');
      });
      

    • Не хранится между сессиями
      примечание: Incoding Framework сохраняет пре-компилированную версию template в local storage, что позволяет после первого прохода пользователем все последующие обращения к template брать сразу из local storage.



В чем же общие преимущество:

  • Да, да и снова это типизация – это достигается за счет использования C# на всех этапах ( template, client scenario and etc ) разработки
  • Один язык для backend и frontend — разработчик знающий C# может без проблем освоить IML и далее вызывать свои Command и Query на клиенте


Вывод: AngularJs разворачивает mvc архитектуру на клиенте, что с одной стороны позволяет структурировать код, но так же добавляет дополнительные проблемы в поддержке. Разработчик asp.net mvc имеет серверную реализацию mvc, где применяя более мощные и подходящие языки, можно избежать усложнения.
Tags:
Hubs:
-14
Comments 68
Comments Comments 68

Articles