47

I want to enable or disable a textarea depending on a condition that evalueates from the model, and I am using the textarea tag helper. In other words, something like this:

<textarea asp-for="Doc" @(Model.MustDisable ? "disabled" : "")></textarea>

But I got the following design-time error: The tag helper 'textarea' must not have C# in element's attribute declaration area.

Then I tried:

<textarea asp-for="Doc" disabled='@(Model.MustDisable ? "disabled" : "")'></textarea>

which did not show any design time error but it renders like this: Model.MustDisable==true renders disabled='disabled' AND Model.MustDisable==false renders disabled. So the text area will always be disabled.

Then I tried (removing the 's):

textarea asp-for="Doc" disabled=@(Model.MustDisable ? "disabled" : "")></textarea>

which did not show any design time error but it renders the same as the previous one.

How can I implement this the right way?

Shyju
  • 214,206
  • 104
  • 411
  • 497
VMh
  • 1,300
  • 1
  • 13
  • 19

4 Answers4

54

It is actually very simple, the disable attribute is already working as you want - you can pass in a boolean value:

<textarea asp-for="Doc" disabled="@Model.MustDisable"></textarea>

if false the disabled attribute is not rendered:

<textarea></textarea>

if true the disabled attribute is set to "disabled":

<textarea disabled="disabled"></textarea>
Daniel Stackenland
  • 3,149
  • 1
  • 19
  • 22
  • Although this might work, it could break on different browsers or later versions of those browsers as it is not standard and depends how the browser vendor interprets the disabled attribute. In brief, if disabled is output at all then that field will be disabled. The value true/false should not matter, just the attribute on it's own should be output. For an enabled field, omit the attribute completely. Hence why this is not the chosen answer. – Ryan O'Neill Oct 31 '19 at 18:19
  • 4
    @RyanO'Neill That's how it works! Try it out and you'll see :-). If you send in false the TagHelper will not print out the attribute at all.I update my answer to clarify also. – Daniel Stackenland Nov 01 '19 at 08:02
  • 1
    @Jess - it's a built-in Tag Helper (I don't know if I'd call it magic) https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers – Daniel Stackenland Dec 16 '19 at 15:59
  • Confirmed. This does indeed work - Razor or MVC is doing some magic to make this happen. (using .NET Core 2.2.) – Jess Dec 16 '19 at 16:25
  • 2
    Wow, magic. Confirmed in Core 3.1 - this should be the accepted answer. – Brian MacKay Jan 07 '20 at 19:01
  • if you use a variable, you need to place it between braces: disabled="@(inputDisabled)" – Bluesight Feb 04 '20 at 12:14
  • 1
    @vmh Please accept this as the answer. it works as expected, without rendering the `disabled` attribute when the value `false` is passed. – RoLYroLLs Dec 18 '20 at 14:06
  • @DanielStackenland How can I use the ! operator? writing ``will cause an error. – Abol_Fa Jul 14 '21 at 16:08
  • 1
    @Abol_Fa I haven't tried, but I think you can add a paranteces . Otherwise, it's easy to add an extra method in your Model with the !-operator. – Daniel Stackenland Jul 15 '21 at 07:02
48

I was facing the same issue with select tag helper, i tried few things and it worked. Try this-

<textarea asp-for="Doc" disabled="@(Model.MustDisable ? "disabled" : null)"></textarea>
GauravD
  • 489
  • 4
  • 2
  • 5
    I don't think this will work on all browsers. ' disabled="" ' will cause an input to be disabled. – user942620 Aug 09 '16 at 17:30
  • @user942620 you are right but just in case of using "" instead of null – Mohamed Badr Dec 28 '16 at 12:15
  • This!!! Thanks a lot! I still wonder why MS doesn't allow a regular @(condition ? "disabled" : ""), but I was going to extend the TagHelper (too much work for such a small thing!) and this solution saved my day! ;) – Fábio Duque Silva Apr 26 '17 at 15:33
  • 2
    @user942620 I know this is very old, but your comment needs to be corrected. It's true that ALL browsers should render `disabled="false"` as disabled, but we're not actually writing HTML here. The **tag helper** is writing HTML. And if the tag helper sees `disabled="false"`, it doesn't render a `disabled` attribute. – Auspex Jul 15 '21 at 17:10
19

The textarea tag helper does not have direct support to conditionally render a disabled text area. But you can always extend the TextAreaTagHelper and add this feature.

So create a new class which inherits from the TextAreaTagHelper class.

[HtmlTargetElement("textarea", Attributes = ForAttributeName)]
public class MyCustomTextArea : TextAreaTagHelper
{
    private const string ForAttributeName = "asp-for";

    [HtmlAttributeName("asp-is-disabled")]
    public bool IsDisabled { set; get; }

    public MyCustomTextArea(IHtmlGenerator generator) : base(generator)
    {
    }

    public override void Process(TagHelperContext context, TagHelperOutput output)
    {
        if (IsDisabled)
        {
            output.Attributes["disabled"] = "disabled";
        }           
        base.Process(context, output);
    }
}

In your _ViewImports.cshtml file, using the @addTagHelper directive, specify the assembly where the above class is defined so that our new tag helper is available in other razor views.

@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
@addTagHelper "*,YourAssemblyNameHere"

Now in your views, you can use it like

@model YourSomeViewModel
<textarea asp-for="Doc" asp-is-disabled="Model.MustDisable"></textarea>

where SomeViewModel has a Doc and MustDisable property.

public class YourSomeViewModel
{
  public string Doc { set;get; }
  public bool MustDisable  { set;get; }
}
Shyju
  • 214,206
  • 104
  • 411
  • 497
  • 1
    Works better than the top upvoted answer and is also a bit nicer than using a ternary expression to add the disabled attribute. Thanks! – nbokmans Nov 03 '17 at 10:13
3

I am posting this separately since I don't have enough reputation to add a comment to Shyju's answer.

If you inherit from one of the default tag helpers and then register both the default tag helpers and your custom tag helper in _ViewImports.cshtml, then both tag helpers will be executed for the specified tags.

For the following:

[HtmlTargetElement("textarea", Attributes = ForAttributeName)]
public class MyCustomTextArea : TextAreaTagHelper
{
    private const string ForAttributeName = "asp-for";
...

With the following _ViewImports.cshtml:

@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
@addTagHelper "*,YourAssemblyNameHere"

Both MyCustomTextArea and TextAreaTagHelper will be executed for each textarea tag.

I did not notice any problems with the output generated for textareas, but I have run into problems inheriting from other default tag helpers. The solution is to remove the default tag helper in _ViewImports.cshtml.

@addTagHelper "*, Microsoft.AspNet.Mvc.TagHelpers"
@addTagHelper "*,YourAssemblyNameHere"
@removeTagHelper "Microsoft.AspNet.Mvc.TagHelpers.TextAreaTagHelper, Microsoft.AspNet.Mvc.TagHelpers"
Eric Scott
  • 189
  • 1
  • 8