TagHelper;如何修改动态添加的孩子

时间:2017-05-26 18:56:04

标签: razorengine tag-helpers

asp-items Razor&#34; TagHelper&#34;将为<option>中的每个值为<select>添加SelectList。我想修改每个孩子。

具体来说我想禁用其中一些(即添加disabled="disabled")。

更具体地说,我想动态地禁用它们中的一些;我使用角度所以我可以ng-disabled="{dynamic_boolean_which_determines_disabled}"。这意味着可以首先禁用该选项,但在用户进行更改后,可以禁用该选项(无需重新加载页面)。 Angular应该照顾好这个;我认为Angular和TagHelpers应该在理论上合作......

我预计:

我可以某种方式访问​​将要创建的子<option>标签的IEnumerable(即SelectList中每个项目的一个),迭代子标签和SetAttribute(&#34;禁用& #34;)或SetAttribute(&#34; ng-disabled&#34;)...

我试过了:

  1. 创建我自己的TagHelper,其目标是select[asp-items],并尝试GetChildContentAsync()和/或SetContent来获取IEnumerable <option>标签并迭代它们并处理每个标签,但我认为这只会让我将整个InnerHtml修改为字符串;感觉hacky做一个String.replace,但我可以这样做,如果这是我唯一的选择吗?即ChildrenContent.Replace("<option", "<option disabled=\"...\"")
  2. 创建我自己的TagHelper,其目标是option的子select[asp-items]元素,因此我可以单独处理每个元素。这有效,但不适用于由<option>创建的动态添加的asp-items,它仅适用于&#34;字面值&#34; <option>标记我实际放入我的cshtml标记。
  3. 我认为这会起作用但不理想

    1. 正如我上面所说,我认为我可以将TagHelper的动态asp-items <option></option> <option></option>的结果作为字符串,并进行字符串替换,但我不想直接使用字符串...
    2. 我怀疑(我还没有尝试过)我可以自己做asp-items的工作;即custom-items。但是,我通过重新做asp-items可以为我做的工作来重新创造轮子?

1 个答案:

答案 0 :(得分:0)

所以我还没有读过&#34; AutoLinkHttpTagHelper&#34; in the example使用字符串替换(特别是RegEx替换)来替换每次出现的URL,并指向该URL的<a>。案件略有不同*,但......

无论如何,一旦我学会停止担心并喜欢字符串修改,这就是我的解决方案:

[HtmlTargetElement("select", Attributes = "asp-items")]
public class AspItemsNgDisabledTagHelper : SelectTagHelper
{
    //Need it to process *after* the SelectTagHelper
    public override int Order { get; } = int.MaxValue;

    //https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/authoring#ProcessAsync
    public AspItemsNgDisabledTagHelper(IHtmlGenerator gen) : base(gen) {}

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        //Notice I'm getting the PostContent; 
        //SelectTagHelper leaves its literal content (i.e. in your CSHTML, if there is any) alone ; that's Content
        //it only **appends** new options specified; that's PostContent
        //Makes sense, but I still wasn't expecting it
        var generated_options = output.PostContent.GetContent();

        //Note you do NOT need to extend SelectTagHelper as I've done here
        //I only did it to take advantage of the asp-for property, to get its Name, so I could pass that to the angular function
        var select_for = this.For.Name;

        //The heart of the processing is a Regex.Replace, just like
        //their example https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/authoring#inspecting-and-retrieving-child-content
        var ng_disabled_generated_options = Regex.Replace(
            generated_options,
            "<option value=\"(\\w+)\">",
            $"<option value=\"$1\" ng-disabled=\"is_disabled('{select_for}', '$1')\">");

        //Finally, you Set your modified Content
        output.PostContent.SetHtmlContent(ng_disabled_generated_options);

    }

}

很少有学习机会:

  1. 我想我会找到AspForTagHelperAspItemsTagHelper,(有角度的背景暗示相应的属性; asp-forasp-items将是分开的&#34 ;指令&#34;又名TagHelper)。
    1. 事实上,TagHelper&#34;匹配&#34;重点关注元素名称(不同于可以匹配元素名称的角度...属性...类... CSS选择器)
    2. 因此,我在SelectTagHelper中找到了我要查找的内容,其中ForItems属性。有道理。
  2. 正如我上面所述,我延长了SelectTagHelper,但那不是必要的来回答我原来的问题。只有在你想要访问this.For.Name时才有必要,但是甚至可能有办法解决这个问题(即在这里重新绑定自己的For属性?)
    1. 我开始分心,我需要覆盖SelectTagHelper的行为来实现我的目标;即面向对象的思维。实际上,即使我确实扩展了SelectTagHelper,也不会阻止基础SelectTagHelper的单独实例匹配和处理元素。换句话说,元素处理发生在管道中。
    2. 这解释了为什么扩展和调用base.Process()会导致Select执行其工作两次;一旦你的实例匹配,一次匹配基础实例时。
    3. (我想可以通过创建像<asp-items-select>之类的新元素来防止SelectTagHelper匹配?但是,没有必要......我只是避免调用base.Process()。所以除非那个&#39 ;不好的做法...)
  3. *以这种方式不同:

    1. 他们希望创建不存在的标记,而我想添加一个标记已经存在的标记;即<option>
      1. 虽然<option>&#34;标记&#34; SelectTagHelper中的PostContent 生成(期待在Content中找到它),我不认为标记生成了-strings-by-content-mods可以与它们相应的TagHelper匹配 - 所以也许我们真的是一样的,因为我们只处理普通的旧字符串
    2. 他们的数据&#34; aka&#34; model&#34;隐含在文本本身;他们找到一个URL,该URL字符串成为他们使用的意义单位。在我的例子中,有一个显式的建模类;由SelectList<select>)组成的SelectListItem<option>) - 但该课程对我也没有帮助。
      1. 该类只给我public bool Disabled这样的属性(记住,这对我来说不够,因为在浏览器中禁用的值可能会变为true或false;仅限客户端),以及{ {1}} - 当然没有像public SelectListGroup Group那样不标准,也没有&#34;全能&#34;像属性这样的属性可以让我把任意属性(ng-disabled或其他任何东西)放在那里。