How To Make Angular Code More Reusable

Поделиться
HTML-код
  • Опубликовано: 11 июл 2024
  • Console Ninja Extension for your VS Code - bit.ly/console-ninja
    Level up your Angular skills with my advanced courses 🚀
    bit.ly/advanced-angular-courses
    From this video, you will learn why composition is much better than inheritance and Angular 15 makes directive composition much easier by introducing the new Dirctive Composition API. It helps you to split behavior among different directives and reuse them in components that need that behavior. I hope you will like the video and if so, please share it with your friends and colleagues. Enjoy!
    Source code for this tutorial:
    github.com/DMezhenskyi/angula...
    💡 Short Frontend Snacks (Tips) every week here:
    Twitter - / decodedfrontend
    Instagram - / decodedfrontend
    LinkedIn - / dmezhenskyi
    🕒 Time Codes:
    00:00:00 - Intro;
    00:00:44 - Inheritance vs Composition in Action;
    00:06:03 - Angular Composition API in Action;
    00:14:04 - Console Ninja Integration;
    00:15:21 - Other tips about HostDirectives;
    00:18:36 - Outro;
    #angular
  • НаукаНаука

Комментарии • 113

  • @DecodedFrontend
    @DecodedFrontend  11 месяцев назад +5

    Console Ninja Extension for your VS Code - bit.ly/console-ninja
    💡 Short Frontend Snacks (Tips) every week here:
    Twitter - twitter.com/DecodedFrontend
    Instagram - instagram.com/decodedfrontend
    LinkedIn - www.linkedin.com/in/dmezhenskyi

  • @haroldpepete
    @haroldpepete 11 месяцев назад +20

    you should change the channel's name, this channel deserves to be called "Angular master" or "Angular sensei"

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад +6

      Haha :) I will leave those names for real Masters and Sensei. I am just a regular Angular dev with relatively good experience and some video editing skills ;)

  • @lhargil
    @lhargil 11 месяцев назад +2

    As always, very well explained Dmytro! Love this feature.

  • @oleksandrvorovchenko8674
    @oleksandrvorovchenko8674 11 месяцев назад +2

    Great, as usual! Thanks!

  • @israellucena926
    @israellucena926 11 месяцев назад

    Fantastic video, my friend!!! I genuinely admire both your content and your teaching style. Thank you wholeheartedly for generously sharing your expertise with us humble learners.

  • @danywalls
    @danywalls 11 месяцев назад +2

    Very well explain as always!!!!

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад

      Thank you, Dany :) Glad to hear that from you.

  • @Tobawa2601
    @Tobawa2601 10 месяцев назад +2

    That is an incredible feature, that will make my component library at work so much better!
    I just wish that we can fill inputs of host-directives somehow in the component. You injected the disabled-directive into prevent-default-directive, which softly connects those directives. Sure it can be made optional, but we need to add every directive that wanna use the prevent-default-directive.

  • @alexshubin1
    @alexshubin1 11 месяцев назад +1

    Thank you a lot! Really cool feature. I wish I learned it months ago! I used to use inheritance.

  • @svitlana_tanasiichuk
    @svitlana_tanasiichuk 11 месяцев назад +2

    Thank you very much for such a thorough explanation, it was very usefull!

  • @v_korol
    @v_korol 10 месяцев назад

    Thanks for providing very interesting insights and techniques about using directives.

  • @demidovmaxim1008
    @demidovmaxim1008 10 месяцев назад

    Thanks a lot ! This is a very informative video. The best Angluar channel for me.

  • @zertyfield
    @zertyfield 6 месяцев назад

    Wow, this was incredibly informative! I can definitely use for my reusable components. Many thanks!

  • @vOnez212
    @vOnez212 4 месяца назад

    Another great video. Thanks for sharing!

  • @ugochukwuumerie6378
    @ugochukwuumerie6378 11 месяцев назад +1

    Thanks, well explained.

  • @gagiksimonyan3782
    @gagiksimonyan3782 11 месяцев назад +2

    Thanks for another useful video, Dmytro ) I just started researching this topic today) p.s special thanks for adding source codes to tutorials, it helps a lot)

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад

      You are welcome, Gagik! Thank you for your feedback :)

  • @andriideiak4323
    @andriideiak4323 11 месяцев назад

    Great stuff!!!

  • @golotus
    @golotus 11 месяцев назад +1

    Nice technique!

  • @user-rg7ij6yo8t
    @user-rg7ij6yo8t 10 месяцев назад

    Great video!

  • @nklaveren
    @nklaveren 11 месяцев назад +1

    amazing, thank you for sharing

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад +1

      You are welcome 🤗 there will be more.

  • @adriannlara
    @adriannlara 11 месяцев назад +1

    great video!!!

  • @zoxx972
    @zoxx972 11 месяцев назад +1

    Brilliant!!

  • @jaypatel-dt8bw
    @jaypatel-dt8bw 10 месяцев назад

    Heads of to you man for deep content

  • @nickpravda3249
    @nickpravda3249 11 месяцев назад +1

    Awesome, thank you

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад

      You're welcome! There will be more :)

  • @StephaneSEGURA
    @StephaneSEGURA 3 месяца назад +1

    Clear and interesting. I will continue to follow you.

  • @alphamarouanadiallo8238
    @alphamarouanadiallo8238 11 месяцев назад +1

    thanks again !

  • @ytamb01
    @ytamb01 11 месяцев назад +2

    Thanks for another great video. I liked the intro for the insight into HostBinding. I've heard that directives aren't used enough by developers. I wonder if it's because it's quite a low level thing that you would use if you were building your own UI library, whereas a lot of Angular devs (I presume) are working with external UI libraries like material, ng-bootstrap, primeng etc)

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад +5

      Glad you liked it :) Yeah, I also have a feeling that the angular directives are quite underestimated and are used not as often as they could be. One of my theories is that many people come to Angular from other frameworks like React where there is no such concept of Directives and they tend to move the already familiar way based on components. Also, maybe there are luck of educational materials that highlight the strengths of angular directives... but this is something that I could fix ;)

  • @JimmiJohnJunnior
    @JimmiJohnJunnior 10 месяцев назад

    I would be very interested in your take on how to structure a modern angular project(standalone only/ngrx..).Great videos all around.😊

  • @MrKOHKyPEHT
    @MrKOHKyPEHT 11 месяцев назад +2

    Aaagh, I was about to go crazy with directive composition, but fortunately watched video till the end :D

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад +1

      :) Don’t afraid to use Composition API, just keep in mind that moment with extra memory allocation and avoid it when it makes sense. In most cases you should not experience any problems with Composition API 😉

    • @ugochukwuumerie6378
      @ugochukwuumerie6378 11 месяцев назад

      Me too 😄

  • @gund_ua
    @gund_ua 11 месяцев назад +8

    Hey Dmytro! Nice video, this API is quite nice for simple use cases indeed. But what I do not like is that you have to manually type out all the inputs and outputs of each directive, it would've been really great to have an option to just enable all inputs/outputs on the host directive without typing each of them separately.
    Also I wonder if this feature only available at a build time phase or is there a way to dynamically add host directives to already existing directives that you do not have control over, for example can you add host directives to existing 3rd party directive from another library?
    And finally, there is just one more way to avoid code duplication without using this angular feature - use mixin pattern, you can easily make each directive as a mixin and then apply them on specific components exactly where needed, so you would still technically use inheritance but it will not be static and you will be able to compose multiple mixins where and how you want to =)
    But mixins are purely static and applied at class definition so you definitely will not be able to augment existing directives/components with them but with angular host directives it seems like it should be possible to achieve dynamic augmentation at least in theory but I'm not sure if angular team implemented/exposed such feature, so would be cool to hear what you know about it!
    Thanks for your videos, I'm not working with Angular for a long time but you are keeping me up-to-date with all latest angular stuff =)
    Stay safe, cheers!

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад +8

      Hey Alex! Thank you for your as-always detailed feedback and thoughts, I always much much appreciated it :)
      By "enabling all inputs/outputs" do you mean by default or your idea is to have something like hostDirectives: ['*']? I think it would be an interesting idea and worth a dedicated GitHub issue because indeed it might be sometimes useful.
      Regarding the 3rd party directives and dynamic directive augmenting. As far as I know, currently, it is possible only at build time :(
      Yep, mixins are also an option and it is used by Angular Material, however, with mixins you can inherit only class properties/methods but Angular features like @Input(), etc will not be working there and mixins are problematic for template type checking. Also, mixins syntax looks a little bit clumsy and boilerplate-ish but it is a matter of taste :D
      Regarding the dynamic directive augmenting at runtime, tbh I don't have any information about it but my quick research led me to this comment github.com/angular/angular/issues/11716#issuecomment-373193097 which made me think that it won't be probably implemented but who knows, maybe something will change. Angular evolves so much and fast last time.
      Glad to hear that my videos help you :) Get back to Angular family soon :D
      Good luck anyway!

  • @nouchance
    @nouchance 11 месяцев назад +1

    Amazing

  • @PauloSantos-yu1tn
    @PauloSantos-yu1tn 11 месяцев назад +1

    Cool stuff

  • @artavazdavagyan
    @artavazdavagyan 11 месяцев назад +2

    yes learned something new

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад

      Awesome! That was the goal of the video and the whole channel ;)

  • @beodan9219
    @beodan9219 11 месяцев назад +1

    Greate!

  • @hassangolzari6694
    @hassangolzari6694 11 месяцев назад +1

    It was great

  • @FredDukker
    @FredDukker 11 месяцев назад +1

    Thanks for this clear explanation about Directive Composition API. Very interesting topic.
    Also interesting to know that a directive can also uses hostdirectives. I didn't like the example of it because it has bidirectional dependency between the two directives.
    Wonder if there is a better usecase for it.

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад +2

      An alternative approach (without using DI) that first came to my mind is introducing the @Input() disabled; also for the CanPreventDefault directive and exposing it from CanDisable one too. Then the 'disabled' input should be always in sync for both directives in this case and it removes coupling via DI. (here is the code example - github.com/DMezhenskyi/angular-directive-composition-api-demo/blob/alternative-without-di/src/app/directives/can-disable.directive.ts#L9).
      If by bidirectional dependency you mean "circular dependency" I wouldn't say that it is the one. The circular dependency you would get if CanDisable injects CanPreventDefault and at the same time CanPreventDefault injects CanDisable. The hostDirective doesn't inject declared directives but just instructs that the directives should be applied to the host when the component is initialized and it is pretty much the same as if declaring them explicitly in the template.
      This pattern (when one directive injects another one) you can see quite often in Angular source code too. For example, the NgModel directive injects the same way ControlValueAccessor directives in Angular Forms :)

  • @thirukumaran6034
    @thirukumaran6034 11 месяцев назад +1

    Your way of teaching and explaining the concept was a real game changer🎉🎉🎉. Please keep it up.
    I noticed that injecting canDisable directive into CanPreventDirective can cause circular dependency. Please validate

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад

      Hi! Thank you for your kind words. Regarding your question: You will get circular dependency if the CanDisable directive injects CanPreventDefault one and at the same time CanPreventDefault injects CanDisable. The hostDirective doesn't inject the declared directives but just instructs that the directives should be applied to the host when the component is initialized and it is pretty much the same as if declaring them explicitly in the template.

  • @osamaabozahra
    @osamaabozahra 11 месяцев назад

    Great video as usual. Thank you.
    I have a question about the part when you used inject function to inject CanDisable directive, where it will get the correct instance?
    Also what if the host component didn't have the CanDisable directive?

  • @pedrofernandes2005
    @pedrofernandes2005 11 месяцев назад

    Thanks for the video!
    Similar to another one I've seen before, but would like to know if this pattern makes sense when you have "base" logic to share between components that have small different details (Also thinking that initial data set on OnInit). Or using BaseComponents is still the best practice?

  • @JujaiJujai
    @JujaiJujai 11 месяцев назад +1

    Love the thumbnail 😆👍

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад +1

      Thank you! I was trying hard to make it happen :D

    • @JujaiJujai
      @JujaiJujai 11 месяцев назад

      @@DecodedFrontend Hardwork paid off, you nailed the pose 😎
      And the video is amazing as always, can't wait to play around with Directives. Thanks and keep up the quality content 👍

  • @haroldpepete
    @haroldpepete 11 месяцев назад +1

    i would like to see a video about decorators in angular

  • @rajeshpoudel06
    @rajeshpoudel06 11 месяцев назад +1

    Very informative video.
    I just have a question, as you said after adding hostDirectives array in the component.
    Does it add the directive to all the elements available in the html?

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад

      Hi! Thanks for your feedback.
      No, directives will be applied only to the component host element

  • @justinnobles3659
    @justinnobles3659 10 месяцев назад

    Great video! Was wondering if you could do a video on how to import an external Javascript File into Angular 16. I know it sounds simple, but I haven’t seen any tutorial that actually works in the new Angular version

  • @aamirkhan-ql8er
    @aamirkhan-ql8er 11 месяцев назад

    Hey Dmytro, Nice Video. I have question regarding dynamic CSS file loading. In my project, I am using multiple lazy loaded module. I want to load specific module related global css file. That global css file will only apply to its child components.

  • @timothyalcaide
    @timothyalcaide 11 месяцев назад +1

    So it is a good practice to remove the selector directive to avoid it being displayed elsewhere than in hostdirective ? Thanks for this amazing video !

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад

      I think it needs some time to understand it because this feature is relatively new. I see it useful if the directive is intentionally designed in a way that can work only with specific directives in tandem as a hostDirective, so removing the selector can guarantee that this directive won't be applied by mistake anywhere else in the application... but also, can't come up so far with an explicit real-life example of it... And this is the reason why I asked to discuss this because I hope to learn something from the community :)

  • @wiliam334
    @wiliam334 9 месяцев назад

    Ta for the video. Can u explain how can u define a hostdirective and inject the directive onto its declared host direcrive. Isnt it circular depwndemcy?

  • @mohammadharb613
    @mohammadharb613 11 месяцев назад +1

    I have a question regarding passing multiple input props to an Angular component. In your previous videos, you demonstrated how to pass individual props like this:
    I'm curious to know if there is a way to pass all the props using a single object, like this: . Is it possible to achieve this in Angular?

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад +1

      It looks like you are coming from React world and looking for {...props} option :) Unfortunately, it is not possible in Angular yet.

  • @ridermonkyt
    @ridermonkyt 11 месяцев назад +2

    reason to mark base class with @directive() ?

    • @MichalSmolinsky
      @MichalSmolinsky 11 месяцев назад +3

      Technically component is directive with a template. You wouldn't have lifecycle hooks if you didn't mark the base class as a directive.

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад +1

      Yep, as @MichalSmolinsky said, you have to decorate base class with @Directive annotation to inherit Angular features like @Input(), @HostBinding(), etc. it is required since Angular 9 when Ivy renderer became default.

  • @PauloSantos-yu1tn
    @PauloSantos-yu1tn 11 месяцев назад

    If i am using a directive wrapper for another directives "hostDirective" how can i achieve the exportAs from the nested directives in the top level directive?

  • @wasifmehmood6519
    @wasifmehmood6519 9 месяцев назад

    So for the large datatable, if we cannot go this way performance-wise for a button with its reusability, what do you suggest then?

  • @daguttt
    @daguttt 11 месяцев назад +1

    Amazing video! 🚀
    How could you make the Console Ninja extension work with Angular? 🤔

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад +1

      Hey :) Thanks for your comment. As far as I remember I didn’t do anything extra with Console Ninja. I just installed it and just worked.

  • @MichielKikkert
    @MichielKikkert 9 месяцев назад

    Just as a side note: directives used in hostDirectives need to standalone. Also, in this scenario you could also solve this without hostDirectives by simply using the directive selectors to target only the components you need to apply them to. Seeing Material directives can’t be used yet with this APi, that might be a good alternative.

  • @o0Fable0o
    @o0Fable0o 8 месяцев назад

    If you put those buttons in a table, how about the performance? Btw is there any chance you do it using decorator class?

  • @Andriy_Moskalenko
    @Andriy_Moskalenko 9 месяцев назад +1

    Is it possible to add a hostDirective conditionally? For instance, based on a value that we recieve in constructor of a host component.
    Maybe by wrapping a directive in another directive that has boolean input parameter 🙂

    • @DecodedFrontend
      @DecodedFrontend  9 месяцев назад +1

      Hi Andriy! Thanks for your question. Unfortunately, it is not possible as far as I know :)

    • @Andriy_Moskalenko
      @Andriy_Moskalenko 9 месяцев назад

      ​​@@DecodedFrontend Appriciate an instance response, Дмитро 🇺🇦 :D
      At least I found another useful feature:
      We can provide input params from inside the host element, since we can set propreties of an injected directive, not only get them as you showed at 14:00
      private canDisableDir = inject(canDisableDirective);
      this.canDisableDir.disabled = isDisabled;

  • @necrotikS
    @necrotikS 5 месяцев назад +1

    I don't understand how you can inject(CanDisableDirective) into the CanPreventDefaultDirective, how does it work? Do you have some video explaining it? How the injector knows which directive to inject?

    • @DecodedFrontend
      @DecodedFrontend  5 месяцев назад +1

      Hi 🙂Try to check my video about Dependency Injection - ruclips.net/video/G8zXugcYd7o/видео.htmlsi=TMcQ_4XF8BlU6dqG

  • @stepandemchenko9870
    @stepandemchenko9870 11 месяцев назад +1

    Do we realy need use separate component for the button tag? Its just simple element and you can mix styles of button applies different global class for this purpose, without any wrapper of angular component.

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад +2

      In general, it depends on the features that the button should have. If the button has its own HTML structure, makes a content projection, etc that it makes sense to have it as a component. If it has only some custom props like 'color' then it could be just a directive. If it is only about styling - your approach can also be a working option. In the video, the button was made as a component just for demo purposes, so please don't take it as an example of the proper component architecture design or production-ready code :) For tutorials, the implementation of some indirectly related building blocks is very often intentionally simplified or artificially adjusted to some concrete demo use cases.

  • @akashchandran1
    @akashchandran1 11 месяцев назад

    Hi, Could you create a video on Angular Universal? It is so confusing to understand how things are happening in the background.

  • @enverusta7811
    @enverusta7811 10 дней назад

    I have a question. Let's say that I have 8 common inputs in 2 different components. I can't handle them with binding a class or something since they are all object types. How can i handle this case? Should i stick with directives or abstract component?

  • @MichalSmolinsky
    @MichalSmolinsky 11 месяцев назад +1

    It looks strange to me that you have to inject a directive that composes host-directive inside host-directive to reach its fields. What should I do if I want to use that host-directive with different directives?

    • @MichalSmolinsky
      @MichalSmolinsky 11 месяцев назад

      There is only one way I can see to add to directive provider `providers: [{ provide: Preventable, useExisting: CanDisableDirective }]` where Preventable is the base class for directives that compose host-directive. Then reach these directives inside the host-directive by `preventable = inject(Preventable);`.

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад

      You can use the "optional" resolution modifier to prevent failing if some directive wasn't found and adjust your logic accordingly but it depends on the concrete use case. The goal was just to show that it is possible to access directives via DI rather than to show a production-ready code snipped. Also, if you don't mind I will copy-paste my answer for a similar question here above :)
      "An alternative approach (without using DI) that first came to my mind is introducing the @Input() disabled; also for the CanPreventDefault directive and exposing it from CanDisable one too. Then the 'disabled' input should be always in sync for both directives in this case and it removes coupling via DI. (here is the code example - github.com/DMezhenskyi/angular-directive-composition-api-demo/blob/alternative-without-di/src/app/directives/can-disable.directive.ts#L9).
      If by bidirectional dependency you mean "circular dependency" I wouldn't say that it is the one. The circular dependency you would get if CanDisable injects CanPreventDefault and at the same time CanPreventDefault injects CanDisable. The hostDirective doesn't inject declared directives but just instructs that the directives should be applied to the host when the component is initialized and it is pretty much the same as if declaring them explicitly in the template.
      This pattern (when one directive injects another one) can see quite often in Angular source code too. For example, the NgModel directive injects the same way ControlValueAccessor directives in Angular Forms :)"

  • @IceBreakerGamer
    @IceBreakerGamer 8 месяцев назад

    W thumbnail

  • @_Greenflag_
    @_Greenflag_ 11 месяцев назад +1

    Well nice, but all directives have to be on the same level of the component ... if they are spread in the HTML inside the component, how will Angular knows which directive is applied on which element ?

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад +1

      but that's actually the point and that's why they are called hostDirective because are being added to the component host element :) The directives that have to be used in the component view, you have to apply manually to a DOM elements as before.

    • @_Greenflag_
      @_Greenflag_ 11 месяцев назад

      @@DecodedFrontend :)

  • @ppedro6477
    @ppedro6477 9 месяцев назад

    I have a doubt about, how can i implement @ContentChild in a hostDirective ? I tried to but all i get is undefined

  • @leakyabstraction
    @leakyabstraction 10 месяцев назад

    It seems that applying styles with directives is still not supported properly? :( That's a bummer, because it makes a lot of functionality composition scenarios awkward, since plenty of functionality has corresponding complex styling.

  • @manojv2893
    @manojv2893 4 часа назад

    Cool... But what's wrong with copy paste of the same code in all the components😬😬😬

  • @n8_may
    @n8_may 10 месяцев назад +2

    Topic Suggestion: Component composition through mixins (such as those used in Angular Material)

    • @standardname9829
      @standardname9829 3 месяца назад

      Mixins are bad practice, since they can lead to an excessive amount of logic.

  • @FrancisRodrigues
    @FrancisRodrigues 11 месяцев назад +1

    so, hostDirective needs to be repetitive each time you need to use it in the template.. hmm

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад

      Am not sure I understand you correct :) Actually, other way around, the hostDirective allows you to avoid code duplication in the template

  • @GuiSeek
    @GuiSeek 11 месяцев назад +1

    run the build of your angular application and see the code generated inside the dist directory. maybe you uninstall the ninja extension

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад +1

      Thanks for your comment. I just did it but I don't see anything unexpected. Am I missing something?

    • @GuiSeek
      @GuiSeek 11 месяцев назад

      @@DecodedFrontend after a few days I installed the extension I realized that it was injecting totally obfuscated javascript code in the middle of my build files for production

    • @GuiSeek
      @GuiSeek 11 месяцев назад

      It's been about 2 months since this happened to me.

    • @DecodedFrontend
      @DecodedFrontend  11 месяцев назад

      @@GuiSeek Maybe they fixed that because I didn't experience anything like that... and tbh I can hardly imagine how the extension code could be leaked into the application bundle 🤔

    • @GuiSeek
      @GuiSeek 11 месяцев назад

      @@DecodedFrontend Unfortunately it still is, I just reinstalled and found the injected and obfuscated code here again... run the build configured for production and search for "_console_ninja"