02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium You have 2 free member-only stories left this month. Upgrade for unlimited access. Member-only story Angular directive composition Let’s take a look at one of the most awaited Angular features. Kevin Kreuzer · Follow 7 min read · Nov 2, 2022 Listen Share More Angular 15 is on the horizon, and with it, many great features. One I am incredibly excited about is directive composition. And I am not the only one. The directive composition has been one of the most upvoted Angular issues on GitHub. Let's see what it's all about. https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 1/18 02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium To explain directive composition, we will look at an actual use case in the form of a digital pinboard. We want to implement a pinboard that displays pins. Each pin should display an info text as a tooltip on hover. Furthermore, each pin can be dragged and dropped and initially rotated. Digital pinboard with a couple of displayed pins The code for such an application might look something like this. <pinboard> <pin image="rocket"></pin> <pin image="beer"></pin> <pin image="keyboard"></pin> <pin image="testing"></pin> <pin image="coffee"></pin> </pinboard> We have a Pinboard component and project a bunch of pins to it. At this point, our pins will be displayed as illustrated on the graphic on top. This means they aren't yet initially rotated, nor are they draggable, nor will we display a tooltip. All features mentioned on top are missing. Of course, we could go ahead and implement those features right in the pin component. But luckily, our code base already contains some handy directives with the desired functionality. https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 2/18 02/07/2023, 15:43 There's a Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium DragableDirective , a RotateDirective and a TooltipDirective at our disposal. Let's use those attribute directives to add the missing features to our pins. <pinboard #dragZone> <pin rotate="45deg" tooltip="Ship new products" dragable [dragzone]="pinboard" image="rocket" ></pin> <pin rotate="-20deg" tooltip="A good beer after a day of coding" dragable [dragzone]="pinboard" image="beer" ></pin> <pin rotate="0deg" tooltip="My favourite Keyboard, the Moonlander" dragable [dragzone]="pinboard" image="keyboard" ></pin> <pin rotate="10deg" tooltip="Write tests for better code" dragable [dragzone]="pinboard" image="testing" ></pin> <pin rotate="25deg" tooltip="No coffee no code" dragable [dragzone]="pinboard" image="coffee" ></pin> </pinboard> Each pin now applies the rotate attribute directive and passes the specified initial rotation degrees. Then there's the and last but not least, the dragable tooltip attribute directive with the tooltip text, attribute with an addtional dragZone input. The drag zone is necessary because you only want to be able to drag the pins inside the board. Nice. This is a good approach, but it has some downsides. To make the PinComponent feature complete; the developer has to remember which directives are needed and has to apply all directives by himself. Wouldn't it be cool if we could provide the PinComponent with drag, tooltip, and rotate features right out of the box and still reuse our directives? Why do we need directive composition? https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 3/18 02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium So far, we could reuse our directives in our components by using inheritance. To get the draggable functionality, for example, we could extend our PinComponent . export class PinComponent extends DragableDirective implements OnInit { } The nice thing is that by using inheritance, we can inherit all Angular features like HostBinding or HostListeners Open in app etc…. And it also works very well with template type checking and minifiers. But this approach has its limitations. What about the tooltip and the rotate functionality? We can only extend one class, right? Furthermore, we have no way of narrowing down the public API of the PinComponent . The public API of directives leaks into derived classes. This is not an optimal solution; that’s why we now get directive composition. If you’re interested in learning Angular or improving your coding skills, my Twitch channel is the perfect place for you! With live streams and interactive Q&A sessions, you’ll have the opportunity to chat, learn and get real-time feedback on your own projects. Directive composition The new directive composition API introduces a hostDirectives property on the Components and Directives decorator. The property value is an array of configuration objects. Each config objects contains a required directive attribute and two optional properties input and output . hostDirectives?: (Type<unknown> | { directive: Type<unknown>; inputs?: string[]; https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 4/18 02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium outputs?: string[]; })[]; Let's go ahead and try to use this brand-new property in our PinComponent to add the tooltip, rotate, and drag features. @Component({ selector: 'pin', template: ` <img [src]="'assets/' + image + '.svg'"/> `, hostDirectives: [ {directive: TooltipDirective}, {directive: DragableDirective}, {directive: RotateDirective}, ] }) export class PinComponent implements OnInit { With this, we can also remove the draggable attribute directive from the pins in our HTML. <pin rotate="25deg" tooltip="No coffee no code" [dragzone]="pinboard" image="coffee" (pinGrabbed)="pinGrabbed()" ></pin> If we would not need to pass a tooltip and rotate those attributes since they are now provided by PinComponent . input, we could also remove hostDirectives But we still need those attributes as well as the on the dragzone attribute because those attributes are inputs. Let's go ahead and run our app. Instead of excellent features, we get a bunch of compilation errors: ERROR src/app/pin.component.ts:20:17 - error NG2014: Host directive TooltipDirective must be standalone 20 {directive: TooltipDirective}, ~~~~~~~~~~~~~~~~ https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 5/18 02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium Well, that's a friendly error message which informs us about one of hostDirectives limitations. hostDirectives can only be used with standalone directives. No problem. Let's go ahead and convert our directives to standalone directives. Standalone, what is this? Standalone components were introduced as a Developer preview in Angular 14. If you want to learn more about it check out my article on standalone components. Angular standalone components How to generate, bootstrap, and lazy load Angular standalone components. kevinkreuzer.medium.com To convert our directives to standalone directives, we have to add the property with a value of declarations true array to the standalone in the directives decorator and move them from the imports array in the AppModule . Great, let's try it out! https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 6/18 02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium PinComponent's hover state with broken tooltip. The tooltip directive gets executed, but the tooltip text is undefined. The tooltip is broken on hover, the icon is not rotated, and the pin is not draggable. Why is that? It seems like the directives input doesn't work anymore. But why? we still pass them in the HTML as attributes on the pin component! Whenever you use hostDirectives all Inputs and Outputs We explicitly have to provide the public API on the inputs are hidden by default. and outputs config objects. hostDirectives: [ {directive: TooltipDirective, inputs: ['tooltip']}, {directive: DragableDirective, inputs: ['dragzone']}, https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 7/18 02/07/2023, 15:43 ] Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium {directive: RotateDirective, inputs: ['rotate']} This is an excellent feature since it gives us complete control over the public API of our component. Let's run our code. Rotated and Hovered PinComponent displays a Tooltip text and can be rearranged via drag & drop. Nice, we get the tooltip on hover, we get the rotation, and of course, the Pins are draggable. All features seem to work. What about the In the same way we configured our DragableDirective Inputs outputs property? we can also configure our Outputs . Our , for example, emits an event that notifies you once you grab a Pin. We can use the outputs property to include the pinGrabbed event in our public API. https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 8/18 02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium hostDirectives: [ {directive: TooltipDirective, inputs: ['tooltip']}, {directive: DragableDirective, inputs: ['dragzone'], outputs: ['pinGrabbed']}, {directive: RotateDirective, inputs: ['rotate']} ] Pretty exciting, right? But that's not all; there's even more. Aliases Another neat feature of directive composition is aliasing dragZone inputs and outputs . is a pretty generic name for our Input. In the context of pins, it would be more accurate to name the Input pinBoard Let's use the alias syntax to rename the instead of dragzone dragzone . property on the DragableDirective . hostDirectives: [ // ... {directive: DragableDirective, inputs: ['dragzone: pinBoard'], outputs: ['pinGrabbed']}, // ... ] Great. Once aliased, we can use the pinBoard input on the pin. <pin rotate="0deg" tooltip="My favourite Keyboard, the Moonlander" [pinBoard]="pinboard" image="keyboard" (pinGrabbed)="pinGrabbed()" ></pin> The aliasing works precisely the same for outputs . Summary Directive composition is a unique and exciting feature that offers the following benefits. We can apply as many directives to the host as we want. There are no limitations. https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 9/18 02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium By default, all the Inputs and Outputs are hidden. We can use the outputs inputs and properties to include in our public API and make them visible. Directive composition works with template type checking. All directive features, such as HostBinding , Injection Tokens, etc... work with directive composition. Host directives can be chained. You can have Host directives that are built on other host directives. As great as it is, it also has some limitations: As discovered throughout the post, host directives have to be standalone. Only one directive can match a component. Make sure to use a directive only once inside a chain. Components can not be used as host directives. Welcome to the world of Angular excellence — angularexperts.ch Do you find the information in this article useful? — We are providing tailored expert support for developing your Angular applications. Explore our wide range offers on angularexperts.ch Angular Angular 15 Directives Frontend Development https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 Programming 10/18 02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium Follow Written by Kevin Kreuzer 2.4K Followers Passionate freelance frontend engineer. ❤️ Always eager to learn, share and expand knowledge. More from Kevin Kreuzer Kevin Kreuzer in Angular In Depth Debug Angular apps in production without revealing source maps Alternate approaches to handle source maps · 12 min read · Dec 18, 2018 3K 8 https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 11/18 02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium Kevin Kreuzer ::ng-deep alternatives Explore alternate approaches to the deprecated::ng-deep Angular API to avoid legacy code and hard to debug side effects · 4 min read · May 25, 2022 154 2 Kevin Kreuzer https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 12/18 02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium Publishing a beta or alpha version to NPM Take advantage of NPM tags · 3 min read · Dec 23, 2017 1.4K 4 Kevin Kreuzer in Angular In Depth Retry failed HTTP requests in Angular Immediate retry, delayed retry and retry with backoff · 8 min read · Jul 3, 2019 2.5K 9 See all from Kevin Kreuzer Recommended from Medium https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 13/18 02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium Alberto García Ibáñez Angular tricks to become a pro Below you can find some useful tools and tricks to boost your Angular applications! The second part of this post is here: · 3 min read · Jan 13 341 8 Sam Redmond https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 14/18 02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium Standalone Components: Simplifying Angular Let’s explore how standalone components can make our Angular apps much easier to build and maintain. · 4 min read · Mar 7 31 Lists General Coding Knowledge 20 stories · 37 saves It's never too late or early to start something 10 stories · 13 saves Coding & Development 11 stories · 23 saves Stories to Help You Grow as a Software Developer 19 stories · 153 saves Alberto García Ibáñez Angular tricks to become a pro. RxJS operators In this post, I have gathered the RxJS tricks that I use the most to boost my Angular applications. https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 15/18 02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium · 4 min read · Jan 24 334 3 Aphinya Dechalert in Better Programming Should You Use Angular in 2023? Where does the framework stand now? · 8 min read · Apr 4 900 21 https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 16/18 02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium Kagklis Vasileios in JavaScript in Plain English 10 Things You Should Know About Zone.js in Angular What is Zone.js? How Angular uses it? This Q&A guide will answer these questions and more. · 5 min read · Jan 17 179 5 lavanya k in JavaScript in Plain English How to Upgrade From Angular 14 to Angular 15 https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 17/18 02/07/2023, 15:43 Angular directive composition. Let’s take a look at one of the most… | by Kevin Kreuzer | Medium Now, let’s see a tutorial of angular 14 to angular 15 upgrade. This article will give you a simple example of angular upgrade version 15. I… · 2 min read · Feb 10 100 1 See more recommendations https://kevinkreuzer.medium.com/angular-directive-composition-e7d9f789323 18/18