Too much junk in your Angular components? Try composition instead of inheritance!

Поделиться
HTML-код
  • Опубликовано: 4 авг 2024
  • My modern Angular course: angularstart.com/
    In this video, we take a look at how to keep your components DRY (Don't Repeat Yourself) by using both an inheritance pattern and a composition pattern with services.
    Get weekly content and tips exclusive to my newsletter: mobirony.ck.page/4a331b9076
    Learn Angular with Ionic: ionicstart.com
    Source code:
    ORIGINAL: github.com/joshuamorony/compo...
    INHERITANCE: github.com/joshuamorony/compo...
    COMPOSITION 1: github.com/joshuamorony/compo...
    COMPOSITION 2: github.com/joshuamorony/compo...
    More resources:
    - Dependency Inversion: en.wikipedia.org/wiki/Depende...
    - Introduce Inheritance & Object Composition: / inheritance-object-com...
    - Code Reuse in Angular with Object Composition & Inheritance: / code-reuse-in-angular-...
    0:00 Introduction
    1:49 Inheritance
    4:08 Composition vs Inheritance
    5:13 Composition
    9:34 Conclusion
    #angular #ionic #architecture
    - More tutorials: eliteionic.com/
    - Follow me on Twitter: / joshuamorony

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

  • @JoshuaMorony
    @JoshuaMorony  Год назад

    Join my mailing list for more exclusive content and access to the archive of my private tips of the week: mobirony.ck.page/4a331b9076

  •  Год назад +6

    So i adopted Angular from day 1 and yet your videos make me learn new things every time.

  • @chriskrezias293
    @chriskrezias293 Год назад +7

    This just moves inheritance to services. Take a look on the decorator pattern, it will also let you use lifecycles.

  • @alexle7895
    @alexle7895 Год назад

    @josh, you are amazing. Your explanation and videos are so clear that I even can follow them. Thank you.

  • @maxk9692
    @maxk9692 2 года назад +18

    Sorry but this is not even close to a composition. It's the same inheritance but with extra step of moving inheritance part into service. It doesn't give you benefits of composition and keeps all the downsides of inheritance, also now that you extend services you can't use things like angular decorators and component lifecycle methods. With composition you could compose out of many elements independently, but in this case you are still limited by 1 inheritance chain for your services, since you can't extend more than 1 class
    What is the point of `{ provide: AbstractListPageService, useClass: ProductsService }`? You say that if you wanted you could easily swap ProductsService into something else, but you could still do that if you defined constructor as `constructor(public listPage: ProductsService)`, you would just be swapping your implementation service in constructor instead of in prodivers array. Since ProductsService extends AbstractListPageService it's just the same thing anyway? Your providers array is still statically defined in the same file, it's inseparable from your class, it's not dynamic. You could do the same thing also by injecting listPage as ProductsService but referring to it as to AbstractListPageService (e.g. saving to a class field of type AbstractListPageService) - it doesn't make a difference

    • @JoshuaMorony
      @JoshuaMorony  2 года назад +2

      I'm certainly open to this being a bad example, it's been some months since I wrote this example but the motivation (and potential point/benefit of this particular approach - just composition with services, not so much providing abstractions of services) as I recall is: situations where you are implementing a lot of the same things across two or more components. A typical approach (at least one I see a lot) is extending the component, but particularly in Angular applications a noticeable downside is the situation where you need to provide injected dependencies back up to the base class with super(). Doing this with services instead (not necessarily services that use inheritance) is a compositional approach that avoids that particular problem with extending components. There's certainly better and worse approaches to composition, but I would say if you are pulling this stuff into a component with a service then that is composition - so my example might be a bad one, but I think it's still utilising composition.

    • @bsully75
      @bsully75 2 года назад

      I would love to see a video or StackBlitz example showing how you’d handle the situation.

    • @Almighty_Flat_Earth
      @Almighty_Flat_Earth Год назад +1

      @Max K, could you provide a stackblitz example link with your suggestion?

    • @maxk9692
      @maxk9692 Год назад +3

      @@Almighty_Flat_Earth it's actually simpler than that - Angular doesn't support any kind of real composition. You can't compose your components out of pieces where each piece contains specific, reusable, isolated piece functionality, which you could then reuse across many components in a generic way. So any claims to have achieved composition in Angular are false, usually it's just adding a few extra steps on top of inheritance to make it look "cool" or "easily swappable". Sometimes it helps a little, sometimes (like things I mentioned in my initial comment) they do nothing but confuse the learner; but in both cases these extra steps can not be called a composition

    • @JoepKockelkorn
      @JoepKockelkorn Месяц назад

      Wouldn’t hostDirectives allow composition?

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

    This is a fantastic video

  • @ilirbeqiri253
    @ilirbeqiri253 Год назад +2

    Great Explanation man!
    Does this means that service class is behaving like a component's typescript class?

    • @daguttt
      @daguttt Год назад

      That's what it looks like 🤔

  • @kamertonaudiophileplayer847
    @kamertonaudiophileplayer847 2 года назад

    divide and conquer? Indeed, it's a smart approach.

  • @ArchiRuban
    @ArchiRuban 2 года назад

    Thank you for this video, amazing explanation! I'd love to implement this logic to bring order to my components. However, I often have scenarios where I have duplicate logic in different components, but where that logic uses functions / variables which are part of a different system of logic of the component. Would there any way to still use composition or inheritance in that case?

    • @JoshuaMorony
      @JoshuaMorony  2 года назад +1

      Do you have an example you could link to? Without context, it sounds like maybe the solution would be to work on having your code be more loosely coupled in general - maybe things need to be broken out into smaller dumb/presentational components and then you might have less issues with your logic being intertwined into things.

    • @ArchiRuban
      @ArchiRuban 2 года назад

      ​@@JoshuaMorony Ah yes of course, makes sense! For example, I have this generic observable called "pageIsReady$", which must emit when the page is ready, and what that depends on is specific to the page, such as whether a particular service has been initialised yet, and/or whether a certain lifecycle hook like "ngAfterViewInit" has been triggered.

    • @AleaumeAnders
      @AleaumeAnders 2 года назад

      One way to handle such things is to work with callbacks.
      So you could include an abstract call in your pageIsReady$, which is then fleshed out via either inheritance or composition. This can get a tad tricky if used in the constructor (as not everything can be easily injected there), but usually works like a charm in later lifecycle stages.

  • @devman5813
    @devman5813 Год назад

    thank you

  • @NicoTasche
    @NicoTasche 2 года назад +3

    Hi,
    I know it‘s already 6 month, but I just watched you video and see one downside. I believe one very important downside (or at least good to know think) is, that you don‘t habe a singleton anymore in a way that the services keeps living after you left the page. Providing a service directly in the component is good if you want to separate the logic from the component. But if you want to yous caching for example you have to provide a service in root. (Correct me if I‘m wrong)
    E.g. I have a search field with categories, I don‘t want to retrieve the categories everytime from the backend.

    • @danandreev6673
      @danandreev6673 Год назад

      Hi,
      Providing a service in root isn't always best (if that logic isn't required in different parts of you application, than you should consider providing it in a specific module). For your example you could implement a global service that handles the caching, and use that service inside the service that fetches all the categories. That way you don't provide the categoriesService in the entire app but can still use caching.

  • @alessandrobruni568
    @alessandrobruni568 28 дней назад

    Thank you

  • @Iam_AndersonP
    @Iam_AndersonP 2 года назад

    If you use an abstract class and a base class, would it be better to have the repeated code in the abstract class directly? An abstract class can have actual code not only abstract methods

    • @JoshuaMorony
      @JoshuaMorony  2 года назад +1

      Yep! I made an update based on some feedback a little while ago, you can check out the change here: github.com/joshuamorony/composition-vs-inheritance/blob/service-composition-two/src/app/shared/page-base/list-page/list-page.service.ts (if only I could update the video so easily!)

    • @Iam_AndersonP
      @Iam_AndersonP 2 года назад +1

      @@JoshuaMorony yes it would be great a video git pull xD

  • @Fyasco_AlanChoufa
    @Fyasco_AlanChoufa 2 года назад

    Hello Joshua.. i really like your video and the content ! Great job =) He trigger me every time but.. you use ngIf="{data: data$ | async, ...}" but with this approch you loose the benefit of the ngIf because you pass an object. Why dont use rxjs with combinaLatest to create a array and pass in ngIf ? thx

    • @JoshuaMorony
      @JoshuaMorony  2 года назад +4

      This is a good point! This was just a quick/easy way to get the values out, but it probably sets a bad example to follow. It would be better to compose streams together in the class to create the view model (vm) to use in the template. I'll make sure to do this in future example :)

  • @Chris-jm2gx
    @Chris-jm2gx Год назад +7

    To me, this still looks like inheritance with some small sprinkles of composition.

  • @ToddHale
    @ToddHale 2 года назад

    Excellent! Could this commonly needed abstraction be put into an OSS package installable with npm? I would even love to see a great library of these types of abstracts in one npm package.

    • @JoshuaMorony
      @JoshuaMorony  2 года назад +2

      Perhaps, my initial thought is that these abstract classes would be too context/application specific to be of much use as a general library, but maybe there could be something useful there. I could certainly see making interesting kinds of pre-made themes/templates with this approach and then having people just wire up their own data etc. with the protection/type safety of the abstract classes

  • @nicksunny
    @nicksunny Год назад +1

    I think it's the bridge pattern. Not really composition.

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

      I agree, The composition means you could combine multiple different features onto any other service like delete, update individually. I have managed to get something similar of my github project angular-service-composition but RUclips keeps removing my comments everywhere lol

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

    9:10 couldn't you just have placed the content of ListPageService inside AbstractListPageService?
    You would have had an AbstractListPageService with common logic, that is reusable and extendable.
    I assume there's nothing wrong about having some logic inside abstract classes, in fact, there are examples of this in typescript official manuals.

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

    This is nice, but I still would prefer Inheritance. I don't like complicated things and inheritance is like a plug and play for me.

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

    Can we call it Foster Parent-Adopted Child inheritance?

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

    Your example is not actually composition ... it's still inheritance just moved the inheritance to the service. Composition would be MyComponent extends AComponent(BComponent(BaseComponent))) where all the logic within AComponent and BComponent is made available in MyComponent (or service).

  • @vandervise465
    @vandervise465 2 года назад +1

    I'm sorry, but all what I see now is that our "inheriting" was just moved from components level on services level.
    Of course it's better than base component inheritance, but it seems it will be better to move all that listSearch$ and data fetching logic into some wrapper component and just provides particular service from Employee and Products component to that wrapper.
    ** And that wrapper additional will solve problem with employee-list.component.html and products-list.component.html duplicating
    Please clarify that moment because I'm a little bit confused :)
    But anyway - thanks for your time!

    • @JoshuaMorony
      @JoshuaMorony  2 года назад +1

      I think the example I used would've been better if I had used different templates for the employee and product page - if the templates are the same then yes we could quite easily create a component and pass different data into it. This is more about how to share that logic from the class with multiple components that might have different templates. Using a service to do this is a compositional approach (unlike using inheritance which would allow us to share the logic without sharing the template). Creating components is also a compositional approach, as you "pull in'' what you need by adding a component to the template - but in this case (perhaps it would be more clear if I had used a better example) we just want to share the logic, not the template, so a component isn't needed.

    • @Almighty_Flat_Earth
      @Almighty_Flat_Earth Год назад +1

      @Antay Yuskovets , could you provide a stackblitz example link with your suggestion?