0

What I want to do using Angular is to create a "directive" that adds a something to my component, lets say a myPortlet with myHasCloseButton gives myPortlet a close button.

<myPortlet myHasCloseButton>...</myPortlet>

I found three options how to approach this and I'm not sure which one is the correct one or if I missed a better option.

Option 1: Create a directive that does something like

this.el.nativeElement.querySelector('.myCloseButton').style.visibility = 'visible';
  • Presence of directive enables the button which is syntactically awesome (see above).
  • Can be applied to more than myPortlets which allows a more flexible use.
  • Does not allow for *ngIf, thus forcing each myPortlet and other components to carry a hidden myCloseButton which feels awkward and appears to be not recommended.
  • Does not allow to bind to some boolean property.

Option 1a: Just like Option 1, but give the directive an boolean @Input that switches the application of the visibility.

  • Allows to bind some boolean property.
  • Presence of directive no longer sufficient, usage is now

    ...

Option 2: Give myPortlet a boolean @Input and a *ngIf directive at the right place.

  • No close-button generated where unnecessary.
  • Allows for binding a boolean.
  • Must be implemented seperatly for each component using it.
  • Presence of directive no longer sufficient, see above.

Option 2b: "Hackily" give a string @Input instead and check if it's empty (as that's what happens when you just give the input name without anything after) and treat it as true.

  • Presence of directive enables the button which is syntactically awesome (see above).
  • Does not allow to bind to some boolean property except maybe by typecasting boolean to string.

Option 3: Create a directive that actually injects the myCloseButton via something like

ElementRef.nativeElement.querySelector('.myCloseButton').addComponent(myCloseButton)

[No actual tested Syntax, just an example, not sure if addComponent is the correct function and how to use it]

  • Somehow feels awkward, seems like bad practice and overcomplicated.
  • Using Elementref is warned against in Angular Docs, appears dangerous.
  • Forces each myPortlet and other components to carry a hidden myCloseButton container.
  • myPortlet (or other component) no longer has control over the embedded myCloseButton.
  • Due to that, it might be more difficult to achieve communication between myPortlet and the embedded myCloseButton (especially of myCloseButton is something more complex).

So my question is: Which is the recommended approach? Am I missing any option? Any best practices? None of those options feels right.

2
  • I seriously have no idea why the format brakes at Option1a code sample and after. If some mod got an idea... Commented Jan 24, 2018 at 17:29
  • 1
    @fortuneNxt about the formatting, the line breaks before the lists make a difference. I fixed it for you. Have a look at the diff (stackoverflow.com/posts/48428341/revisions). Commented Jan 25, 2018 at 14:43

1 Answer 1

2

Using @Input() is best for this use case.

It's simple, clean, and most importantly, it allows you to dynamically determine whether your component has a close button (a nice feature you could not get with the attribute directive). Example (this is terrible UX), but what if you only wanted to allow admin users to have a close button. Then, you could subscribe to your user service and set [hasCloseButton]="userIsAdmin$ | async". That's pretty powerful stuff you couldn't do (in a clean way) with an attribute directive.

Also, for testing, you can just set the input directly (testComponent.hasCloseButton = true), rather than having to create a test host component and create one case with the directive / one without.

To summarize: using @Input() will afford you more flexibility and make testing easier.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.