65.9K
CodeProject 正在变化。 阅读更多。
Home

Incoding Framework - IML TODO MVC(示例应用程序)

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2015年9月10日

CPOL

12分钟阅读

viewsIcon

17075

downloadIcon

253

在流行的 App ToDo MVC 的示例中展示 IML

“Incoding Framework” 系列中的其他文章

为什么要选择 ToDo?

 这是实现“Todo MVC”作为 IML 功能证明的提案。结果在这里。首先,与 JS 框架不同,测试版本不使用“本地存储”作为容器,而是使用数据库和源代码(或附件文件)。我们将进一步探讨这一点。在实现过程中,我在客户端构建了整个物流(底部计算、隐藏元素等),尽管任务是这样布置的。更新元素“逐点”更容易(有时也是必要的),而 IML 代码知道如何计算和反映自身。

代码审查

今天我们不比较两种解决方案(这样的话材料会非常多)。我们将审查在实现“todo”应用程序时将获得的代码。我上面提到,IML 实现是服务器端的,但为了使任务更具可比性,我们只关注客户端。

它包含什么

代码被分成 3 个视图

  • Index - 主页(实际上是单页)
  • Todo_List_Tmpl - 中心列表的模板
  • Todo_Footer_Tmpl - – 构建底部区域的模板

图形表示的位置

用于添加 TODO 的表单

@using (Html.When(JqueryBind.Submit)
            .DoWithPreventDefault()
            .Submit(options =>
                   {
              options.Url = Url.Dispatcher()
                               .Push(new AddTodoCommand { 
                         ClientId = Selector.Incoding.Cookie(CookieManager.ClientId) 
                                                        });
                   })
            .OnSuccess(dsl =>
                           {
                               dsl.WithId(containerId).Core().Trigger.Incoding();
                               dsl.Self().Core().Form.Reset();
                           })
            .AsHtmlAttributes()
            .ToBeginTag(Html, HtmlTag.Form))
{
    @Html.TextBoxFor(r => r.Title, new { placeholder = "What needs to be done?", autofocus = "" })
}

注意: 预期会出现“嘿,这不严肃,代码量大多了,你需要在到处复制,看看别人怎么做的!!!”之类的说法。我有一个论点——有“C# 扩展”允许封装 IML 构造。在文章的后面,我将提供使用 C# 扩展的任务解决方案的替代方案(还有 GitHub 上的“repository”和修改后的代码)。

这是什么?
  • When(JqueryBind.Submit) - 表示目标事件
  • DoWithPreventDefault - 事件行为(取消浏览器默认行为)
  • Submit - – 通过 ajax 发送表单

注意: 关于所呈现实现的几点评论

    • Url 在哪里发送表单在选项中设置(而不是通过“form”上的“action”属性变量)
    • ClientId 可以作为隐藏字段导出,该隐藏字段在 InitIncoding 时从 Cookie 获取值,以便提交时无需参数
  • OnSuccess - 在提交完成后成功执行
    • Trigger Incoding to containerId - 为 Container 元素启动所有**IML**代码(下文详述)

注意: 预期会出现“嘿,这不严肃,代码量大多了,你需要在到处复制,看看别人怎么做的!!!”之类的说法。我有一个论点——有“C# 扩展”允许封装 IML 构造。在文章的后面,我将提供使用 C# 扩展的任务解决方案的替代方案(还有 GitHub 上的“repository”和修改后的代码)。

    • Form reset - 重置表单元素
  • AsHtmlAttributes - 将 IML 代码收集为方便 asp.net mvc 使用的格式(**RouteValueDictionary**)
  • ToBeginTag - – 将属性打包到“form”标签中(工作原理类似于**Html.BeginForm**)

注意:可以使用 Html.BeginForm(“action”,“controller”,Post,iml.AsHtmlAttributes())

用于添加 TODO 的表单(替代方案)
@using (Html.Todo().BeginForm(setting =>
                             {
                setting.TargetId = containerId;
                setting.Routes = new { ClientId = Selector.Incoding.Cookie(CookieManager.ClientId) };
                             }))
{
    @Html.TextBoxFor(r => r.Title, new { placeholder = "What needs to be done?", autofocus = "" })
}

注意:代码变少了,最重要的是现在你可以扩展方法以满足特定项目的需求(验证、提交后重定向等) 

public class BeginFormSetting
{
    public string TargetId { get; set; }

    public object Routes { get; set; }
}

public BeginTag BeginForm(Action configure)
{
    var setting = new BeginFormSetting();
    configure(setting);

    var url = new UrlHelper(HttpContext.Current.Request.RequestContext);
    return this.helper.When(JqueryBind.Submit)
               .DoWithPreventDefault()
               .Submit(options =>
                           {
                               options.Url = url.Dispatcher()
                                                .Push(setting.Routes);
                           })
               .OnSuccess(dsl =>
                              {
                               dsl.WithId(setting.TargetId).Core().Trigger.Incoding();
                               dsl.Self().Core().Form.Reset();
                              })
               .AsHtmlAttributes()
               .ToBeginTag(this.helper, HtmlTag.Form);
}

注意:你们中的大多数人都熟悉 asp.net mvc,但有必要指出,我们用匿名方法代替了“普通的”参数,该方法接收设置类。

容器

@(Html.When(JqueryBind.InitIncoding | JqueryBind.IncChangeUrl)
      .Do()
      .AjaxGet(Url.Dispatcher()
                  .Query(new
                         {
                          ClientId = Selector.Incoding.Cookie(CookieManager.ClientId),
                          Type = Selector.Incoding.HashQueryString(r => r.Type)
                         })
                  .AsJson())
      .OnSuccess(dsl =>
                     {
                       string urlTmpl = Url.Dispatcher()
                                  .Model(new GetTodoByClientQuery.Tmpl { FooterId = footerId })
                                  .AsView("~/Views/Home/Todo_List_Tmpl.cshtml");
                       dsl.Self().Core().Insert.WithTemplateByUrl(urlTmpl).Html();
                       dsl.WithId(footerId).Core().Trigger.Incoding();
                     })
      .AsHtmlAttributes(new { id = containerId })
      .ToDiv())
这是什么?
  • When(JqueryBind.InitIncoding | IncChangeUrl) - – 指定目标事件
    • InitIncoding - – 在元素首次出现在页面上时执行(无论是否通过 ajax,也无论是否通常)
    • IncChangeUrl - – 在“hash”改变时执行
  • Do - 事件行为
  • AjaxGet - 指定将发送 ajax 请求的 url
    • ClientId - 从“cookie”获取值
    • Type - 从“Hash Query String”获取值
  • OnSuccess - 在 AjaxGet 完成后成功执行
    • Insert data to self by template - 通过模板(下文的 Todo_List_Tmpl )将来自请求(json)的结果插入到当前元素中。

注意:模板可以通过任何可用的选择器获取,例如,以前 Jquery.Id 是基础,但 ajax 加载更可取。

    • Trigger incoding to footerId - 为 footer 元素启动所有 IML 代码(上文详述)
  • AsHtmlAttributes - 收集 IML 代码并将值 containerId(guid)设置为 Id 属性

注意:使用 guid 作为 Id 保证了页面元素的唯一性,对于单页应用程序尤其重要。

  • ToDiv - 将属性打包到 div 标签中

注意:ToDiv 是 RouteValueDictionary 之上的 C# 扩展,因此编写所需的变体很容易。

容器(替代方法)
@Html.Todo().Container(setting =>
             {
                setting.Id = containerId;
                setting.Url = Url.Dispatcher()
                                 .Query(new
                                              {
                          ClientId = Selector.Incoding.Cookie(CookieManager.ClientId),
                          Type = Selector.Incoding.HashQueryString(r => r.Type)
                                              })
                                 .AsJson();
                setting.Tmpl = Url.Dispatcher()
                                  .Model(new GetTodoByClientQuery.Tmpl { FooterId = footerId })
                                  .AsView("~/Views/Home/Todo_List_Tmpl.cshtml");
                setting.DependencyId = footerId;
             })

注意:将来需要添加块 UI 或其他操作,现在可以集中处理。

public class ContainerSetting
{
    public string Id { get; set; }

    public string Url { get; set; }

    public string Tmpl { get; set; }

    public string DependencyId { get; set; }
}

public MvcHtmlString Container(Action configure)
{
    var setting = new ContainerSetting();
    configure(setting);

    return helper.When(JqueryBind.InitIncoding | JqueryBind.IncChangeUrl)
                 .Do()
                 .AjaxGet(setting.Url)
                 .OnSuccess(dsl =>
                                {
                          dsl.Self().Core().Insert.WithTemplateByUrl(setting.Tmpl).Html();
                          dsl.WithId(setting.DependencyId).Core().Trigger.Incoding();
                                })
                 .AsHtmlAttributes(new { id = setting.Id })
                 .ToDiv();
}

页脚

@(Html.When(JqueryBind.None)
      .Do()
      .Direct(new FooterVm
                        {
        AllCount = Selector.Jquery.Class("toggle").Length(),
        IsCompleted = Selector.Jquery.Class("toggle").Is(JqueryExpression.Checked),
        CompletedCount = Selector.Jquery.Class("toggle")
                                        .Expression(JqueryExpression.Checked)
                                        .Length(),
                        }))
      .OnSuccess(dsl =>
                     {
                      string urlTmpl = Url.Dispatcher()
                                          .Model(new TodoFooterTmplVm
                                                     {
                                                           ContainerId = containerId
                                                     })
                                          .AsView("~/Views/Home/Todo_Footer_Tmpl.cshtml");
                       dsl.Self().Core().Insert.Prepare().WithTemplateByUrl(urlTmpl).Html();
                     })
      .AsHtmlAttributes(new { id = footerId })
      .ToDiv())
这是什么?
  • When(JqueryBind.None) - 指定目标事件
    • None - When 允许将任何用户事件指定为“MySpecialEvent”这样的字符串,但经验表明,对于许多脚本来说,一个就足够了。
  • Do - 事件行为
  • Direct - 可以看作是一个不执行任何操作,但可以处理数据的动作库。
    • AllCount - 获取具有“toggle”类的对象的数量

注意:可以通过增强方法(而不是 Length)来调用任何 jquery 方法,并编写 C# 扩展来覆盖 JquerySelectorExtend。

    • IsCompleted - 检查带有“toggle”类的已标记对象

注意:如果现有的 jquery 选择器不够用,则可以使用 Selector.Jquery.Custom(“your jquery selector”)

    • CompletedCount - 获取带有“toggle”类的已标记对象的数量

注意:获取 JS 函数的值

Selector.JS.Call("MyFunc",new []
                              {
                                  Selector.Jquery.Self(),
                                  "Arg2"                 
                              })
  • OnSuccess - 在 AjaxGet 成功完成后执行
    • Insert prepare data to self by template  - 将 Direct 准备好的数据( prepare )通过模板(下文的 Todo_Footer_Tmpl )放入当前元素。

注意:在将数据放入“prepare”之前,请先执行字段中的选择器。

  • AsHtmlAttributes - 收集 IML 代码
  • ToDiv - 将属性打包到 div 标签中

Todo List Tmpl

用于构建待办事项列表的模板标记

@using (var template = Html.Incoding().Template())
{
 <ul>
  @using (var each = template.ForEach()) 
   {
    @using (each.Is(r => r.Active)) 
    { @createCheckBox(true) }
    @using (each.Not(r => r.Active))
    { @createCheckBox(false) }

    <li class="@each.IsInline(r=>r.Active,"completed")">
      <label>@each.For(r=>r.Title)</label>
    </li>
</ul>
}

注意:后端代码比示例中显示的要多(元素的逻辑已被删除)。这是为了方便解释模板。

这是什么?
  • Html.Incoding().Template() - 打开上下文(在使用的上下文中)模板构建
  • template.ForEach() - 开始迭代元素(在使用的上下文中)
  • using(each.Is(r=>r.Active)) - 开始迭代元素(在使用的上下文中)
  • createCheckBox - 用于创建复选框的匿名函数 C# 函数(下文详述)
  • each.IsInline(r=>r.Active,"completed") - 如果 Active 为 true,则返回“completed”

注意:还有 IsNotLine 和 IsLine。

  • each.For(r => r.Title) - 显示 Title 字段的值

注意:所有字段访问都基于指定的模型(是的,我又在说类型化了)。

其他元素

删除按钮

@(Html.When(JqueryBind.Click)
      .Do()
      .AjaxPost(Url.Dispatcher().Push(new DeleteEntityByIdCommand
                                 {
                                         Id = each.For(r => r.Id),
                                         AssemblyQualifiedName = typeof(Todo).AssemblyQualifiedName
                                 }))
      .OnBegin(r =>
                   {
                       r.WithSelf(s => s.Closest(HtmlTag.Li)).Core().JQuery.Manipulation.Remove();
                       r.WithId(Model.FooterId).Core().Trigger.Incoding();
                       r.WithId(toggleAllId).Core().Trigger.None();
                   })
      .AsHtmlAttributes(new { @class = "destroy" })
      .ToButton(""))
这是什么?
  • When(JqueryBind.Click) - – 指定目标事件
  • Do - 事件行为
  • AjaxPost- 指定将发送 ajax 请求的 Url
    • Id- 来自 Todo 的值
    • AssemblyQualifiedName - 获取元素类型(或另一个 C# 代码)的名称
  • OnBegin- 在操作开始之前执行(AjaxPost)

注意:当然,最好使用 OnSuccess,因为服务器上可能会发生错误(超时或其他问题),并且事务将不会完成,因为 OnBegin 在 AjaxPost 调用之前运行,但 JS 框架上的 TodoMVC 示例使用本地存储(比 ajax 快),这就是我回避它的原因,以免丢失操作速度。

    • Remove closest LI   - 删除最近的 LI
    • Trigger incoding to footer id - 为 footer 元素启动所有 IML 代码(上文详述)
    • Trigger none to toggle all - 为 Toggle All 元素启动 IML 代码(仅 None 链)(下文详述)

注意:如果对这两个调用使用相同的触发器,则可以使用以下变体

dsl.WithId(Model.FooterId, toggleAllId).Core().Trigger.Incoding();
  • AsHtmlAttributes - 收集 IML 代码
  • ToButton- 将属性打包到 button 标签中

注意:ToButton 允许指定内容,但在此情况下不是必需的,因为图像通过 CSS 安装。

删除按钮(替代方案)
@Html.Todo().Verb(setting =>
       {
           setting.Url = Url.Dispatcher().Push(new DeleteEntityByIdCommand
                                                   {
                                 Id = each.For(r => r.Id),
                                 AssemblyQualifiedName = typeof(Todo).AssemblyQualifiedName
                                                   });
           setting.OnBegin = dsl =>
                                 {
                   dsl.WithSelf(s => s.Closest(HtmlTag.Li)).Core().JQuery.Manipulation.Remove();
                   dsl.WithId(Model.FooterId).Core().Trigger.Incoding();
                   dsl.WithId(toggleAllId).Core().Trigger.None();
                                 };
           setting.Attr = new { @class = "destroy" };
       })

注意:OnBegin 接受 Action,允许您轻松地将扩展“实例化”到其中,其中包含 IML。(更多示例将在后面给出)   

public class VerbSetting
{
    public string Url { get; set; }

    public Action<IIncodingMetaLanguageCallbackBodyDsl> OnBegin { get; set; }

    public Action<IIncodingMetaLanguageCallbackBodyDsl> OnSuccess { get; set; }

    public object Attr { get; set; }

    public string Content { get; set; }
}

public MvcHtmlString Verb(Action<VerbSetting> configure)
{
    var setting = new VerbSetting();
    configure(setting);

    return this.helper.When(JqueryBind.Click)
               .Do()
               .AjaxPost(setting.Url)
               .OnBegin(dsl =>
                            {
                                if (setting.OnBegin != null)
                                    setting.OnBegin(dsl);
                            })
               .OnSuccess(dsl =>
                              {
                                  if (setting.OnSuccess != null)
                                      setting.OnSuccess(dsl);
                              })
               .AsHtmlAttributes(setting.Attr)
               .ToButton(setting.Content);
}

注意:由于 Verb 在某些脚本中使用,因此很容易创建可选参数。我检查它们是否为“null”并为其分配默认值。 

 完成复选框

var createCheckBox = isValue => Html.When(JqueryBind.Change)
                                    .Do()
                                    .AjaxPost(Url.Dispatcher().Push(new ToggleTodoCommand
                                                       {
                                                     Id = each.For(r => r.Id)
                                                       }))
                                    .OnBegin(dsl =>
                                                  {
                             dsl.WithSelf(r => r.Closest(HtmlTag.Li))
                                .Behaviors(inDsl =>
                                                        {
                   inDsl.Core().JQuery.Attributes.RemoveClass("completed");
                   inDsl.Core().JQuery.Attributes.AddClass("completed")
                                      .If(builder => builder.Is(() => Selector.Jquery.Self()));
                                                         });

                             dsl.WithId(Model.FooterId).Core().Trigger.Incoding();
                             dsl.WithId(toggleAllId).Core().Trigger.None();
                                                  })
                                     .AsHtmlAttributes(new {@class="toggle" })
                                     .ToCheckBox(isValue);

注意:由于 Verb 在某些脚本中使用,因此很容易创建可选参数。我检查它们是否为“null”并为其分配默认值。

这是什么?
  • When(JqueryBind.Change) - 指定目标事件
  • Do - – 事件行为
  • AjaxPost - 指定将发送 ajax 请求的 Url

注意:AjaxPost 和 AjaxGet 是 Ajax 的“命名”版本,具有许多额外的调整。OnBegin – 在操作开始之前执行(AjaxPost)

  • OnBegin - 在操作开始之前执行(AjaxPost)
    • Remove class on closest LI -  删除最近 LI 上的“completed”类
    • Add class on closest LI  if self is true- 添加“completed”类

注意:IML 目前不实现“else”的可能性,但在 2.0 版本中将实现。

  • AsHtmlAttributes - 收集 IML 代码并将值“toggle”设置为“class”属性
  • ToCheckBox - 打包

按待办事项类型过滤

@{
    const string classSelected = "selected";
    var createLi = (typeOfTodo,isFirst) => Html.When(JqueryBind.InitIncoding)
                                               .Do()
                                               .Direct()
                                               .OnSuccess(dsl =>
                                                           {
           var type = Selector.Incoding.HashQueryString(r => r.Type);
               if (isFirst)
           dsl.Self().Core().JQuery.Attributes.AddClass(classSelected)
                                   .If(s => s.Is(() => type == ""));

           dsl.Self().Core().JQuery.Attributes.AddClass(classSelected)
                                   .If(s => s.Is(() => type == typeOfTodo.ToString()));
                                                              })
                                               .When(JqueryBind.Click)
                                               .Do()
                                               .Direct()
                                               .OnSuccess(dsl =>
                                                           {
           dsl.WithSelf(r => r.Closest(HtmlTag.Ul).Find(HtmlTag.A))
              .Core().JQuery.Attributes.RemoveClass(classSelected);
           dsl.Self().Core().JQuery.Attributes.AddClass(classSelected);                                          
                                                           })
                                               .AsHtmlAttributes(new { 
                          href = "#!".AppendToHashQueryString(new { Type = typeOfTodo })
                                                                     })
                                               .ToLink(typeOfTodo.ToString());
}

 <li>  @createLi(GetTodoByClientQuery.TypeOfTodo.All,true)        </li>  
 <li>  @createLi(GetTodoByClientQuery.TypeOfTodo.Active,false)    </li>
 <li>  @createLi(GetTodoByClientQuery.TypeOfTodo.Completed,false) </li>

注意:这是在“razor 视图”上下文中实现匿名函数的另一个示例。

这是什么?
  • When(JqueryBind.InitIncoding) - 指定目标事件
  • Do - – 事件行为
  • Direct - 什么都不做
  • OnSuccess - 执行成功后完成

注意:“Direct”的“OnBegin”和“OnSuccess”之间没有区别,但 OnError 和 OnBreak 与其他情况下的工作方式相同。

    • var type - 声明一个将在表达式中使用的变量。
    • add class to self if IsFirst is true And type is Empty - 如果当前元素是第一个且“type”为空,则添加类
    • add class to self if type is current type - 如果“type”等于 argument typeOfTodo,则向当前元素添加类
  • When(JqueryBind.Click) - 指定目标事件
  • Do - 事件行为

注意:我们不取消超链接的行为,因为我们需要浏览器更新位置。

  • Direct - 什么都不做
    • remove class - 删除位于最近 UL 中所有 A 上的选定类
    • add class to self - 将选定的类添加到当前元素
  • AsHtmlAttributes - 收集 IML 代码并设置“href”属性

 

按待办事项类型过滤(替代方法)
<li>
    @Html.Todo().LiHash(setting =>
                            {
                         setting.IsFirst = true;
                         setting.SelectedClass = classSelected;
                         setting.Type = GetTodoByClientQuery.TypeOfTodo.All;
                            })                    
</li>
public class LiHashSetting
{            
    public bool IsFirst { get; set; }

    public string SelectedClass { get; set; }

    public GetTodoByClientQuery.TypeOfTodo Type { get; set; }
}

public MvcHtmlString LiHash(Action configure)
{
    var setting = new LiHashSetting();
    configure(setting);

    return helper.When(JqueryBind.InitIncoding)
                 .Do()
                 .Direct()
                 .OnSuccess(dsl =>
                                {
     var type = Selector.Incoding.HashQueryString(r => r.Type);
          if (setting.IsFirst)
     dsl.Self().Core().JQuery.Attributes.AddClass(setting.SelectedClass)
                             .If(s => s.Is(() => type == ""));

     dsl.Self().Core().JQuery.Attributes.AddClass(setting.SelectedClass)
                             .If(s => s.Is(() => type == setting.Type.ToString()));
                                })
                 .When(JqueryBind.Click)
                 .Do()
                 .Direct()
                 .OnSuccess(dsl =>
                                {
     dsl.WithSelf(r => r.Closest(HtmlTag.Ul).Find(HtmlTag.A))
        .Core().JQuery.Attributes.RemoveClass(setting.SelectedClass);
     dsl.Self().Core().JQuery.Attributes.AddClass(setting.SelectedClass);
                                })
                 .AsHtmlAttributes(new { 
                       href = "#!".AppendToHashQueryString(new { Type = setting.Type })
                                       })
                 .ToLink(setting.Type.ToString());
}

绝对优势!

我在上一篇文章中试图展示 IML 的优势,但这并不令人信服,所以我将再次尝试。

  • 类型化 - 当然,每个人都从自己的角度看待类型化。有人认为这里必须写更多代码(这是正确的),其他人认为缺乏非类型化语言固有的灵活性,但 IML 首先是 C#,所以那些选择它的开发者,我认为会欣赏这个优势。
  • 强大的扩展 - 我在文章中提供了一些,但实践中还有更多。我再举一些例子来说明。
    • 下拉菜单
 @Html.For(r=>r.HcsId).DropDown(control =>
                                {
                 control.Url = Url.Action("HealthCareSystems", "Shared");
                 control.OnInit = dsl => dsl.Self().Core().Rap().DropDown();
                 control.Attr(new { @class = "selectInput", style = "width:375px" });
                                })

примечание:OnInit 接受 Action<IIncodingMetaLanguageCallbackDsl>,这使得轻松扩展你的 extensions 并将其嵌入 IML 成为可能!

    • 对话框
@Html.ProjectName().OpenDialog(setting =>
                         {
                            setting.Url = Url.Dispatcher()
                                             .Model<GroupEditProviderOrderCommand>()
                                             .AsView("~/Views/ProviderOrder/Edit.cshtml");
                            setting.Content = "Edit";
                            setting.Options = options => { options.Title = "Edit Order"; };
                         })

注意:OnInit 接受 Action<JqueryUIDialogOptions>,这使得轻松扩展你的 extensions 并将其嵌入 IML 成为可能。 列表可能无穷无尽,但主要思想是 IML 允许执行任何任务,而 html 扩展解决了设计重用的问题。

  • 更强大的扩展
@(Html.ProjectName()
      .Grid<CTRPrintLogModel>()
      .Columns(dsl =>
               {
            dsl.Template(@<text>
                          <span>@item.For(r=>r.Comment)</span>
                          </text>)           
                .Title("Comment");

            const string classVerticalTop = "vertical_top";
            dsl.Bound(r => r.Time).Title("Time").HtmlAttributes(new { @class = classVerticalTop });   
            dsl.Bound(r => r.Version).Title("Type").HtmlAttributes(new { @class = classVerticalTop });              dsl.Bound(r => r.Staff.FirstAndLastName).Title("Staff")
                                                 .HtmlAttributes(new { @class = classVerticalTop });   
            dsl.Bound(r => r.PrintDate).Title("Date");
            dsl.Bound(r => r.Comment).Raw();
               })
      .AjaxGet(Url.RootAction("GetCTRPrintLogModel", "CTR")))
    •  Tabs - 
@(Html.Rap()
      .Tabs<Enums.CarePlanTabs>()
      .Items(dsl =>
             {
   dsl.AddTab(Url.Action("GapsAndBarriersInc", "GapsAndBarriers"), Enums.CarePlanTabs.GapsAndBarriers);    dsl.AddTab(Url.Action("RedFlags", "PatientRedFlag"), Enums.CarePlanTabs.RedFlags);                      dsl.AddTab(Url.Action("Goals", "IncGoal"), Enums.CarePlanTabs.SelfCareGoals);
   dsl.AddTab(Url.Action("Index", "IncAppointment"), Enums.CarePlanTabs.Appointments);        
             }))

 注意:每个了解 html 扩展的开发人员都可以为他们的项目需求构建此类元素。

  • • Hash 的工作 - 在本文中只检查了 IncChangeUrl 级别,但我们有
    •  Hash.Fetch - 将哈希值放入(沙盒)元素
    •  Hash.Insert/Update - – 将元素的值放入哈希
    •  Hash.Manipulate - 允许精细地(按键设置/删除)调整当前哈希
    • AjaxHash - 是 Submit 的模拟,不是用于表单,而是用于 Hash
  • Insert 的工作 - – 对于 TOSO 的实现我没用到,但在实际项目中它无处不在。
    • Insert Generic  - 以上所有示例都基于一个模型,但脚本中经常发生返回值是“容器”。在这种情况下,Insert 可以通过 For 指示我们正在处理模型的哪个部分,并且“模板”也可以各自独立。
Html.When(JqueryBind.InitIncoding)
    .Do()
    .AjaxGet(Url.Action("FetchComplex", "Data"))
    .OnSuccess(dsl =>
                   {
         dsl.WithId(newsContainerId).Core()
            .Insert.For<ComplexVm>(r => r.News).WithTemplateByUrl(urlTemplateNews).Html();
         dsl.WithId(contactContainerId).Core()
            .Insert.For<ComplexVm>(r => r.Contacts).WithTemplateByUrl(urlTemplateContacts).Html();
                   })
    .AsHtmlAttributes()
    .ToDiv()
  • 验证的工作(服务器端和客户端) - 许多 JS 框架都有验证工具,但 IML 集成了服务器端,并且可以支持任何验证引擎(FluentValidation、标准 MVC),无需编写额外代码。
    • 命令代码
if (device != null)
   throw IncWebException.For<AddDeviceCommand>(r => r.Pin, "Device with same pin is already exist");
    •  视图代码
.OnError(dsl => dsl.Self().Core().Form.Validation.Refresh())

 注意:OnError 处理程序必须附加到引起操作(submit、ajaxpost 或其他)的元素上。

  • 更少的脚本 - 随着项目 JS 框架需求的增加,需要大量 JS 文件,但 IML 具有固定的库集(不包括插件)。
  • 类型化模板 - 关于类型化,但对于模板构建来说非常重要。
  • 模板替换为引擎 - 选择其中任何一个,语法相同。
  • 复杂的解决方案 - IML 是 Incoding Framework 的一部分,与 JS 框架不同,我们拥有完整的项目开发基础设施(服务器/客户端/单元测试),它们彼此紧密集成。

结论

在实现 IML 时,我遵循了一条规则:减少对页面的更新。我的意思是,我都在客户端重新计算了,但在实践中(在我们的项目中),服务器通常是薄弱环节,因为许多操作在客户端上是不可能的或不推荐的。例如,不可能(由于生产力原因)。

  • 分页 - 数据库包含数十万条记录,将容量全部发送到客户端是错误的。
  • 排序 - 同一原因。
  • where - 同一原因。
  • 以及其他与数据库相关的操作。

基于字段值的复杂计算(包括税费的总订单金额)可能不被推荐。最好将请求(带有字段值)发送到服务器并将结果放回。

 在 IML 的上下文中,计算可以通过以下方式解决:

  • 单个值
var val = Selector.Incoding.AjaxGet(url);
dsl.WithId(yourId).Core().JQuery.Attributes.Val(val);
  • 数据集
dsl.With(r => r.Name(s => s.Last)).Core().Insert.For<ContactVm>(r => r.Last).Val();
dsl.With(r => r.Name(s => s.First)).Core().Insert.For<ContactVm>(r => r.First).Val(); 
dsl.With(r => r.Name(s => s.City)).Core().Insert.For<ContactVm>(r => r.City).Val();

我可以继续讲述 IML 的可能性(以及 Incoding Framework),但文章已经很长了。因此,那些想了解更多关于我们工具的人可以在网上找到资料。我明白,证明 IML 能够解决任务不亚于流行的 JS 框架是很困难的,但在接下来的文章中,我将审查自动完成、Tree View、grid 和其他流行脚本的实现,这将展示我们工具的更多可能性。

© . All rights reserved.