2017-05-26 2 views
0

Le Razor "TagHelper" asp-items ajoutera un <option> à un <select> pour chaque valeur dans le SelectList. Je veux modifier chacun de ces enfants.TagHelper; comment modifier les enfants dynamiquement ajoutés

Spécifiquement je veux désactiver certains d'entre eux (c'est-à-dire ajouter disabled="disabled").

Encore plus spécifiquement je veux désactiver dynamiquement certains d'entre eux; J'utilise angulaire donc je pourrais ng-disabled="{dynamic_boolean_which_determines_disabled}". Cela signifie que l'option peut être désactivée au début, mais une fois que l'utilisateur a effectué une modification, l'option peut être désactivée (sans rechargement de page). Angulaire devrait prendre soin de cela; Je pense que angulaire et TagHelpers devraient travailler ensemble en théorie ...

Je pensais:

je pouvais accéder en quelque sorte un IEnumerable des enfants <option> balises qui seraient créés (soit un pour chaque élément de la SelectList), itérer les enfants balises et SetAttribute ("désactivé") ou SetAttribute ("ng-handicapés") ...

J'ai essayé:

  1. Créer mon propre TagHelper qui cible le select[asp-items], et essaye de GetChildContentAsync() et/ou SetContent pour atteindre un IEnumerable <option> tags et les itérer et traiter chaque, mais je pense que cela me permettra seulement de modifier le InnerHtml entier comme une chaîne; se sent hacky pour faire un String.replace, mais je pourrait le faire si c'est ma seule option? à savoir ChildrenContent.Replace("<option", "<option disabled=\"...\"")
  2. Créer ma propre TagHelper qui cible les option éléments qui sont des enfants de la select[asp-items], donc je peux individuellement processus chacun. Cela fonctionne, mais pas sur le <option> ajouté dynamiquement créé par asp-items, il fonctionne uniquement sur les balises "littérales" <option> que je mets effectivement dans mon balisage cshtml.

Je pense que ça va fonctionner, mais pas idéale:

  1. Comme je l'ai dit plus haut, je pense que je peux obtenir le résultat de asp-éléments dynamiques <option></option> <option></option>, en tant que chaîne de TagHelper, et faire une chaîne de remplacement, mais je préfère ne pas travailler avec des chaînes directement ...
  2. Je suspecte (je ne l'ai pas essayé) que je puisse faire le travail de asp-items moi-même; c'est-à-dire custom-items. Mais ensuite, je recréais la roue en refaisant le travail que asp-items aurait pu faire pour moi?
+0

Tout va mentionner [@ Daniel J.G.] (https://stackoverflow.com/users/1836935/daniel-j-g) parce qu'ils semblent savoir beaucoup. Mais je suppose que "@" ing cet utilisateur [peut ne pas fonctionner comme je l'espère:)] (https://meta.stackexchange.com/questions/43019/how-do-comment-replies-work) –

Répondre

0

donc je n'avais pas encore lu le « AutoLinkHttpTagHelper » in the example qui utilise le remplacement de chaîne (regex spécifiquement remplacer) pour remplacer toutes les occurrences d'une URL, avec un <a> a souligné à cette URL. Les cas sont légèrement différents *, mais ...

Quoi qu'il en soit, voici ma solution une fois que j'appris à cesser de se soucier et aimer la modification de la chaîne:

[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); 

    } 

}

Peu d'opportunités d'apprentissage:

  1. Pensais je trouverais AspForTagHelper et AspItemsTagHelper, (le fond angulaire suggérait que les attributs correspondants: asp-for et asp-items, seraient séparés " directives "aka TagHelper".
    1. En fait, TagHelper « correspondant » se concentre sur le nom de l'élément (contrairement angulaire qui peut correspondre au nom de l'élément ... attribut ... classe ... sélecteur CSS)
    2. donc j'ai trouvé ce que je cherchais dans SelectTagHelper, qui a For et Items comme propriétés. Logique.
  2. Comme je l'ai dit plus haut, je tiens à SelectTagHelper, mais ce n'est pas nécessaire de répondre à ma question initiale. Il est nécessaire que si vous souhaitez accéder à la this.For.Name comme je l'ai fait, mais il peut même être un moyen de contourner cela (c.-à-re-lier son propre Pour les biens ici?)
    1. je suis arrivé sur une pensée de distraction je voudrais besoin de remplacer le comportement de SelectTagHelper pour atteindre mes objectifs; c'est-à-dire la pensée orientée objet. En fait, même si j'ai étendu SelectTagHelper, cela n'empêche pas une instance distincte de la base SelectTagHelper de correspondre et de traiter l'élément. En d'autres termes, le traitement des éléments se produit dans un pipeline.
    2. Cela explique pourquoi l'extension et l'appel de base.Process() entraînent le fait que Select effectue son travail deux fois; une fois lorsque votre instance correspond, et à nouveau lorsque l'instance de base correspond.
    3. (je suppose aurais pu empêcher SelectTagHelper de correspondre en créant comme <asp-items-select> un nouveau nom de l'élément? Mais, pas nécessaire ... J'évite simplement d'appeler base.Process(). Donc, à moins que ce soit une mauvaise pratique ...)

* différent de cette façon:

  1. Ils veulent créer une étiquette qui n'existe, alors que je veux ajouter un attribut une balise qui est déjà là; à savoir le <option>
    1. Bien que le <option> « tag » est généré par le SelectTagHelper dans son PostContent (s'attendait à trouver dans Content), et je ne pense pas que les balises générées en-chaînes par cas Content-mods peut être associé avec leur TagHelper correspondant - donc peut-être nous sommes vraiment les mêmes en ce sens que nous traitons avec des vieilles chaînes
  2. Leurs "données" aka "modèle" est implicite dans le texte lui-même ; ils trouvent une URL et cette chaîne d'URL devient une unité de sens qu'ils utilisent.Dans mon cas, il existe une classe explicite pour la modélisation; le SelectList (<select>) qui se compose de certains SelectListItem (<option>) - mais cette classe ne m'aide pas non plus.
    1. Cette classe me donne que des attributs comme public bool Disabled (rappelez-vous, cela ne suffit pas pour moi parce que la valeur des personnes handicapées pourrait changer pour vrai ou faux dans les navigateur, à savoir côté client uniquement), et public SelectListGroup Group - certainement rien comme non standard comme ng-disabled, ni une propriété "attrape-tout" comme les attributs qui pourraient me laisser mettre des attributs arbitraires (ng-disabled ou autre chose) là-dedans.