Why I decided to switch to the inject() function in Angular

Поделиться
HTML-код
  • Опубликовано: 19 июл 2024
  • My modern Angular course: angularstart.com/
    Angular 14 gave us the ability to use the inject() function more generally in our projects, including replacing constructor based dependency injection. But is it a good idea to switch to it?
    More on Dependency Injection: • Can AI explain the mos...
    Get weekly content and tips exclusive to my newsletter: mobirony.ck.page/4a331b9076
    Learn Angular with Ionic: ionicstart.com
    #angular
    - More tutorials: eliteionic.com
    - Follow me on Twitter: / joshuamorony
    0:00 Introduction
    0:54 inject() benefits
    1:53 Inheritance
    4:05 The problem with inject()
    5:36 Conclusion

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

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

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

  • @DannyMcPfister
    @DannyMcPfister Год назад +86

    I’m a dirty filthy junior dev who loves Angular and I just have to say, your passion for Angular and your gift for explaining things has been a great addition for my day to day learning. You have a way for taking tricky concepts and packaging them together into easy to consume format and you do it with a positive energy. I appreciate your work and am always glad to see new Angular content from you pop up on my feed. Cheers!

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

      I’m a Junior dev with no experience so far and I do have to tell that inject is very clear and obvious, you understand right there that it is for “dependency injection” - it must be the default option to simplify angular for newcomers.
      I took me around 40 ministers to understand with the help of chat gpt the structure of a component and what exactly constructor did there, turns out it was used to simply inject a dependency which is a throw off in terms of the naming…
      I also tried vue previously as a framework and it’s very simple and really beginner friendly - but I’m glad I can just use inject and be cool

  • @MickR412
    @MickR412 Год назад +94

    Another two potential downsides of using the inject method in my opinion:
    1. The dependencies are maybe a bit less obvious. All you add to look at was at the constructor arguments, every injected dependencies would be there. Now they could be scattered around the constructor arguments and defined properties above the constructor. Not necessarily a big problem but sometimes we can miss the big picture, especially in code reviews and if the class is big (which could be another problem in itself). I understand your point about younger developers and constructor arguments being less obvious that it's injected dependencies, but at the same time it's base Angular knowledge and should be assumed pretty early on.
    2. When it comes to testing. If you are using a TestBed, it's pretty straightforward as nothing really changes. But it is not uncommon to write Isolated tests for pipes, directives or services (even components sometimes), when you are not testing in a TestBed environment, but are simply instantiating the class directly while providing the mocked dependencies directly in the constructors arguments. Now probably there are workarounds, like using _jest.mock('@angular/core', { inject: () => { ... } });_ or something like that (haven't tested), but that feels a bit dirtier and less "by the book".
    I see them very useful in the base/abstract classes use cases like you mentioned, or to create utility inject methods. For example if you want to inject a Store, then select a part of the store, you can create a custom inject function that abstract some things.
    const select = (stateSelector: Selector) => inject(Store).select(stateSelector);
    ...
    class MyComponent {
    private myState$ = select(MyState);
    }
    There are many cool ideas this potentially opens up! I'm just not convinced yet that we should get rid of any and all constructor parameters.

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

      Good points, and yes the testing situation is something that does stick out - for me I always use TestBed anyway so it wasn't a concern, and I guess you could argue TestBed is the "default Angular way" to test, but yes I know a lot of people aren't using TestBed.

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

      @@JoshuaMorony If you are not testing the DOM (which is a pain in the ass for everything jasmine/jest based) you don't really need TestBed, right?
      I think the best combination to test an angular app is spectator (to test everything which is not a component), cypress component testing (to test components in isolation), and cypress e2e (for full integration/e2e tests). What do you think about that?

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

      @@gioelegentile I think there are lots of good ways to tests apps and your approach sounds great, for me I go with Jest/Cypress(for E2E)/TestBed. I am a bit biased toward what is the most "default" or "out of the box" since I do a lot of teaching, so I'll generally only reach for other libraries/tools if they are particularly obvious/compelling (e.g. I've obviously decided to switch to Jest/Cypress).

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

      ​@@JoshuaMorony you should consider Testing Library, it don't change much the setup but it's way faster / cleaner to get DOM element and handle detect changes for us

    • @JohnWII
      @JohnWII Год назад +4

      Yeah #1 is the main reason why constructor injection is what we are sticking with. We basically equate the inject() style to normal Property Injection which is available in most modern languages with di frameworks and is often considered an anti pattern unless used explicitly for optional dependencies (which happens basically never for us). But of course a lot of this depends on your usage, muddying your dependencies like that in some little trivial app is all good.

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

    Thank you for keeping us updated with the updates. Great use case demonstrated I have faced this issue with the super

  • @chaos_monster
    @chaos_monster Год назад +31

    inject() is a service locator pattern and in many cases it get's easy to fall into anti pattern. So be aware what you teach. But I must admit the use-case for inheritance can be considered useful, especially when you go with mixins instead of classical inheritance.

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

      I've seen this criticism but haven't seen any examples yet of where this distinction might matter (not saying they don't exist, just something I haven't come across yet) - do you have an example of an anti-pattern you think inject() might encourage?

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

      @@JoshuaMorony Basically the entire argument about the service locator pattern being an anti-pattern evolves around testing.
      The most "common" situation I've encountered is when you use inject() in another function that encapsulates some behaviour. Those functions are hard to test and even harder to mock.

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

      @@chaos_monster thanks - personally I have no intention to do anything fancy with inject() and will just use it as a direct replacement for constructor based injection, but certainly the ability is there to do some trickier things (especially for library authors) that we haven't been able to experiment with (and I guess potentially get burned by) yet

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

      I don't mind the inject() keyword, but I think the runInInjectionContext method is problematic-- that is where we start to fall heavily into the anti-pattern.

  • @toxaq
    @toxaq Год назад +10

    Would use it for the inheritance example but otherwise stick with constructor injection. I like knowing all the dependencies in one spot.

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

    Never stop producing content please, I think you are the Matt Pocock of Angular!

  • @piotrjarzabek-up9jc
    @piotrjarzabek-up9jc Год назад +1

    Perfect, this is very good solution for all base components :) great job

  • @Blafasel3
    @Blafasel3 Год назад +27

    Considering many other DI frameworks tried similiar techniques to the inject function and backed off it again (e.g. Spring Boot @Autowired which is essentially the same thing) and are encouraging constructor injection again. I don't like the turn the Angular team took by the inject function, but I see why people would like it. It feels like a shortcut to me and shortcuts tend to encourage anti patterns ;)

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

      The only question I care about is, why? There are many things about Java that might make sense in other contexts but definitely suck in front and stuff

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

      @mikepearsonengineering8793 with the annotations like autowired or functions like inject it's easily possible to instantiate a class with null fields and running into compile time npes. With constructor injection it's not. Another thing, it's a little harder to realise that your class has too many dependencies since they are not bundled in the constructor but instead are cluttered around the class. I have seen epic classes with 15 dependencies cluttered between methods and other fields.

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

      One of the reasons why I still like XML based Injections in spring over annotations. Where I have clarity on how many Resources are being Injected by looking at the xml configurations

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

      Java is a different beast compared to JavaScript.
      TypeScript has to do some extra work and emit additional code to allow constructor injection to work at all, this as well as decorators are non-standard extra layers on top of the runtime, you could say they are workarounds. The inject function is just pure JavaScript and doesn't need any additional transformation or runtime information to work.
      inject really is just what context is in React/Svelte/Vue, and I think it makes a lot more sense in the JS/TS world.

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

    Well it's a nice information, starting Angular from v2 until v4 then switching to react it's the problem i've always faced when working with inheritance components, huge thank you

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

    Excellent argument for inject function Josh !
    I have a few examples in mind of codebase with inheritance and this switch will indded be welcome !

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

    Thank you for the pros and cons, nicely explained.
    For your poll:
    +1 for the inject( ) team, I already use it and I like it.

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

    Damn you surprised me, i was sure that todays video will be about the Signals RFC :D
    But I myself am used to DI from developing BE (spring), so both ways are good for me.
    I do like the inject function though, opens up quite a few simplifications like functional guards and resolvers 😁

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

    Just in time Joshua! Yesterday, I came to the same conclusion whilst refactoring old routing guards.

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

    Some good ideas here. I've mostly continued to use constructor injection, mainly through inertia, though have made good use of inject() in inheritance hierarchies. I guess it takes some discipline to structure code so that all the dependencies are declared together - which isn't quite as cohesive as having them declared as parameters to a constructor.

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

    very well explained. love this video.

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

    You can also inject inside routes (title, can activate,resolve etc..) which I can't think how else you could with a constructor.. Btw, now that standalone components are out you could redo your angular code structure video to address the removal of the routing module as a shell feature since all you need is an extra routes file now. 🥂

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

    I hope this is expanded to inputs, outputs, and all other class member decorators eventually!

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

    Awesome. Definitely will switch

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

    Thanks for this video, will help me convince my team

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

    If you want a balanced mix, only ever DI the Injector service given by Angular. Then super the injector to the base component. The base class can then use the injector service to get the required services. Meaning you can add new injections to the base without needing to update all components inheriting the base.

  • @teckasm
    @teckasm 10 месяцев назад +1

    Makes usage with the occasional, unavoidable inheritance much nicer.

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

    Some people are saying that inject is a magic keyword, but I would argue that dependency injection is equally magic, just some different syntactic sugar. I can see the advantages in case of inheritance, but in the apps I work on this rarely happens. After watching the video I got excited about using inject, but then I thought about it some more and I think I'll stick with DI in the constructor (mostly because I like the syntax better)

  • @ali-celebi
    @ali-celebi Год назад

    Great video, as usual :)

  • @HassanRaza-ym3uf
    @HassanRaza-ym3uf Год назад

    Going to start using it right now

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

    This is MAGICAL!!

  • @JozefRzadkosz
    @JozefRzadkosz 2 месяца назад

    What is your IDE? Great video tbh, the way how you explain things is amazing, your voice doesn't make you tired of listening, keep doing this we need you! :D

  • @o_glethorpe
    @o_glethorpe Год назад +5

    Will stick with the constructor approach.

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

    The only benefit i can think of is some services that require heavy initialisation code that is only useful when you do an action in your application. I noticed dependency injection in the constructor is in particular more liked by backend developers then frontend developers

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

    This is a hard one for. Coming from a Java/Spring World, where basically everyone started with setter injection and switched to constructor injection it's hard to bring me to "switch back". I personally ran into the problem you described (with inheritance and having to change the super() call in every component), so I'll certainly switch to inject() for THOSE cases at least after this video

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

      To expand on this. Now that I think about it, I believe the reason why that movement happened in string, was because setter injection was always a bit akward there. It happened at an undefined time after construction, so you could not use the injected services in the constructor and such. So a @PostConstruct hook was mostly used for stuff that actually "should have been in the constructor, but couldn't, due to setter injection". Constructor injection fixed THAT + made sure that you can't construct classes with only half their dependencies. This is mostly relevant for testing, though I can imagine this point could be true for Angular as well. The first (and more important) point isn't though, so there is a strong case for inject()

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

    The video started saying that is better for juniors to see inject so they can see what's going on, and then automatically is criticising the use is super explicitly adding all the dependencies(which it will hide for junior the behaviour). And worst is magic, because inject is working there as a decorator, in order to be able to inject those things. There's a reason of explicity telling things to another dev. I believe that inject on constructor is cleaner because you can use the same idea with other injectors. If you want to reuse those classes in whatever place outside angular, it will still work. Also, you will know explicitly what classes depends and you can use it event without a fancy injector.

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

    I made this transition months ago in four different projects, no problems!

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

    for the longest time i used the constructor DI and inheritance but i realized sooner than later with new requirements it makes a hell of editing cycle so i switched to the inject() but using some backdoor way that allows injecting in ngoninit and so on by making custom AppInjector that gets injected in AppModule, that way it will be available to use whenever you need instead of constructor context too.
    I don't understand perfectly why angular team didn't include this approach to be in their default injector, mostly something that has to do with lazy loaded modules/services and TreeShaking builds yet i find it very solid for most use cases.
    SO in short HELL YES I AM WITH THE inject(service); to hell with constructor injection unless if you are forced to for some reason.
    Or to be reasonable a mix and match might make sense in some cases when you need to make sure that who ever is extending your class knows it's a must to have these services. lot's of other frameworks stayed on the constructor injection and i do believe it's one of the reasons for that.

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

    I switched to inject and I love it, no regrets at all! :)

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

    I also prefer composition to inheritance. none the less, my project has an area with lots of inheritance, however, none of it is within the injection context, so i gotta call super with all the services. One thing I considered was creating a ctx object that gets passed to super each time with all the services. This is a similar problem to prop drilling though. In the end i just call super everywhere with the services, not too bad.

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

    Hey, can you make a video on zoneless change detection. Would really help

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

    This is so neat. I don't know why Angular doesn't mention it as an option in the Dependency Injection documentation page.

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

    Do you see any problem with mixing these two approches?
    In our codebase we have the case, that we would have a circular dependency, cause two services depend on one other (one mostly on on the other, but the other uses a variable of the one). so that would be a circualr dependency. We solved that by using the inject method inline for just this service to get the property. No CircularDependencyError. So would that be a disadvantage? Angular not detecting circular dependencies?

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

    great tuts

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

    That adding removing in baseclass could break on runtime than compile time like constructor injection

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

    The writing on the wall for constructor for me was when Minko Gechev used it while teaching Ryan Carniato Angular.
    I don't think constructor based injection can even disappear though because it's part of js classes so if you want to use it you can and I don't think it will be deprecated it would take more effort than it's worth to disable it.

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

      I think it's like @Autowired on Spring, not recommended for several versions but it's still there

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

      It's not part of js classes by default. Angular holds the references and injects them

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

      @@rumble1925 I meant the constructor itself, if constructor is nothing special in js syntax you could easily see both co-existing.

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

      @@TayambaMwanza Oh alright I misunderstood

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

    As C# backend developer, I prefer constructor based injection

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

    I have this exact same case where i have to import a serviceA in the ComponentA for inherence, i'll try this but im in angular 13, i have to see if it works.

  • @JohnConnorTM
    @JohnConnorTM 7 месяцев назад

    I primarily see its advantage for base classes, not sure the esthetics of it bothers me either way. Thanks for an informative video!

  • @johangustafsson6121
    @johangustafsson6121 Год назад +4

    The convention in many frameworks for many languages is that dependencies are provided in the constructor, this breaks that pattern. "feels nicer" is not a strong enough argument for changing that IMO. The times we (my company) extended components like in your example is so rare that it's not a strong argument for it either. Convention or "we always do it this way" is in itself not really a strong argument, but the reason for change is neither.

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

      Define many frameworks and many languages? You do realize you're working with a web framework here?
      Vue - inject()
      React - useContext()
      Qwik - useContext()
      Solid - useContext()
      Svelte - getContext()
      Angular was the only one doing constructor based dependency injection since it's the only one still clinging to OOP concepts. This is a move towards a more functional and composable approach. I'd wager we'll see an alternative to Class components very soon.

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

      @@jasonrooney1368 Perhaps, perhaps not. For now, I consider it to be more of a bike shedding problem than anything else, having two different ways of doing the same thing just introduces unnecessary friction, in the class and when testing. One of the things I appreciate working on many different teams is the consistency and similarities between projects that comes from using Angular.

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

    thank you for th calrification. Just one thing. how do we use the services inside spec for testing?

  • @danielguzman8607
    @danielguzman8607 2 месяца назад

    I just hate having a lot of dependencies inside constructur(), I looks quite ugly and kinda annoying for me, and also hate the super() (specially with many dependencies), so you just convinced. I'm switching to it. Thanks!

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

    I think I'll use inject function mostly in cases when I want to extract some logic to outside the class. But I wonder how to test something like this 🤔
    I think I will continue using constructors by default to be consistent with the rest of my codebase

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

      I think you will have to use TestBed, which wasn't a concern for me as its what I always use anyway

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

      This is the perfect example of the service locator pattern being an anti-pattern. Thank you 🤗

  • @NickTsitlakidis
    @NickTsitlakidis Год назад +6

    I'm not sure if it was mentioned in another comment, but there is another downside which doesn't have to do with technical limitations or ease of coding. And that's the meaning of the constructor. If we see this from a strict OOP standpoint, the constructor of the object should be the point where you pass the object dependencies and where your object is instantiated based on these dependencies. That's the whole meaning of the function. So if you pass object dependencies to the object using the inject() method, essentially you ignore what the constructor is meant to do and you hide this "logic" somewhere else. Not a great deal for any dev who doesn't care about OOP "theory" but it's worth mentioning because consistency and best practices are important in large projects. To be clear, I'm not saying that inject() is a mistake, it makes sense for functional cases (guards for example), but if you're in the OOP context, I think it's not the right option.

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

      Let's see it other way around: in case all classes are using the exact same service the base class does, inject is the way to handle it like a standard property of the base class, so the others don't need to care.
      If you need different services to inject, depending on the class you use, do it the constructor way.
      So everything will be OOP.

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

      @@holger3526 I can see why such a case would make the usage of a base class easier. It still doesn't change the fact that you hide a possibly important dependency though. Think of it another way, how would this class work if a developer tried to use it without Angular? If all the dependencies are in the constructor, it's clear what you need to do. If they are not and you don't have Angular doing its magic, then you'll have to know that you need to set this dependency some other way. It's also understandable to think that working without Angular's DI won't make sense for your case. But personally if I can make a class easier to move to another project/context/whatever, I prefer doing that.

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

      @@NickTsitlakidis I don't see this. If you are trying to use Angular style somewhere else, it won't work. But there are Inject decorators in other languages too, like Spring.
      So you always need to be aware of this.
      But you can also use it this way:
      Define the service in the class and set it using inject function inside the constructor. Maybe this is more obvious then.

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

      @@holger3526 What is the benefit of using the inject function inside the constructor? To avoid having a lot of parameters? If so, maybe we're focusing on the wrong thing. A class with many dependencies should probably be refactored because it does more than one thing. I would argue that having the parameters in the constructor makes this even more obvious for the dev to refactor it.
      Regarding your comment about using the class somewhere else, a well designed angular service is basically a simple TS class with the Injectable decorator. If that's all you use from Angular then it's easy to migrate this class to another project. To compare this with Spring (although it's been some time since I've used it), I would make a Bean function for the service I want to provide, and the service class would be clear of annotations if possible.

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

      @@NickTsitlakidis it's not "just" having a lot of parameters. I faced the problem a couple of years and it was like told here: every class extending the base needs to link and inject the exact same service. This is going to become a nightmare when you need to change the base, like adding a new service. In this case every child needs to do the same too. And now think about micro frontends where you aren't able to update everything. In this case your stuff will crash.

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

    I stumbled across exactly that just recently - thanks for the clarification!
    Question, though: How does this affect unit testing, im my case with jest? Can I provide mocked dependency injections for these `inject(…)` statements just like I would have for the `constructor()` injections?

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

      Was wondering this too. I tend to avoid TestBed as I found it clunky and provide my own mocks when unit testing. I like this inject() style, but I'm not sure how it would work with our unit testing conventions.

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

    If you don't need the dependencies / different instances, use abstract class.

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

    How about 'private' constructor injections? Can the inject() approach replace the those? Like. Is a private variable deceleration for an inject(service) as private as when declared private in a constructor injection?

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

    What about creating a decorator to do this same as well?

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

    Personally prefer constructor based injection. The inject function just looks “hacky” maybe because I’ve been to used to the old ways. Main concern either way is the constructor gives you a single source of truth. Injects can be added on like 6 or on line 100 and yes it’s up to developers to be smart about it but at least the constructor enforced the pattern :) anyways have used it for factory’s so it deffo is in my toolbox

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

    Josh -- Your email that went out had mismatched text to go with the video link. Just FYI.

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

      Thanks, I didn't even notice! I'll pin this for anyone confused, the service with a signal video will be next week's video!

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

    What about conditional injection?

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

    I must say, I'm not agreeing with you on this one. I find the constructor a nice a easy to find point of entry for the component and it's easy to see what is injected and what is created/managed only in my component(well, the components of the colleagues). And from an architecture standpoind, I love the concept of saying: Okay, that service is required to build this component, and you cannot instantiate it without providing an implementation.

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

    What about when you have @Optional() or @SkipSelf() etc? You'd still to do that via the constructor, or? I'm sticking (and liking) the constructor way (although not having to pass them when inheriting seems niiiiiice...) :)

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

      You can optionally pass InjectOptions to the inject() function which allows you to provide skipSelf etc.

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

      @@JoshuaMorony Oh okay, thanks for lettig me know. :)

  • @josecarloss.a.tissei4841
    @josecarloss.a.tissei4841 Год назад

    The inject function is basically a service locator wich is an anti-pattern, there's a lot of content online from people a lot smarter than me explaining why we shouldn't use service locators

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

    inject function looks cool, it's an angular 14 feature, we still use angular 12 at work. but i'll be sure to use it in the future, thank you for the showcase :)

  • @JakeAndDaddy
    @JakeAndDaddy 21 день назад

    You had me sold on not needing to mess away with child classes.
    Does it still work ok with factory methods?
    The only thing I’d add is making the injectable read only. I do that on the constructor version

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

    How often do you do component inheritance in Angular? I avoid it like the plague (inheritance) in general. I don't think I've ever used in for components in Angular.

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

    A better option would be to use annotations. Like @Autowired in spring.

  • @3htomit
    @3htomit Год назад

    Josh,
    Thanks a lot for your video. After watching your video I wanted to try the inject() method.
    I struggle with the token injection, such as:
    constructor(
    @Inject(FEATURE_TRANSLOCO_SCOPE) private readonly _scope: ProviderScope,
    ) {}
    When I replace it by:
    private readonly injectedScope = inject(ProviderScope);
    I get the following error from my IDE:
    TS2693: 'ProviderScope' only refers to a type, but is being used as a value here.

    • @3htomit
      @3htomit Год назад

      I found the solution for the token injection:
      private readonly injectedScope: ProviderScope = inject(FEATURE_TRANSLOCO_SCOPE);

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

    Using the inject function in the context of extending a BaseComponent seems huge! So many constructors used where I only did `super()` lol. This is great :D

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

    What about for unit testing?

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

    I like point with BaseComponent

  • @lightyagami5963
    @lightyagami5963 2 месяца назад

    the injector function would work for the lazy injection places where inject function thorws error.

  • @manit77
    @manit77 7 месяцев назад

    inject (Location) throws an error inside a component of a component hard to track down.

  •  Год назад +1

    what about the decorators @skipSelf and the others? Anyway inject its nice to avoid inheritance

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

      You can still optionally provide InjectOptions to the inject function where you can specify skipSelf etc.

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

    It doesnt look nicer.. but.. the inheritence issue is a valid argument to give this a try.. gj, tx for the explonation..

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

    True, I always annoyed with lots of parameters in constructor!!

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

    Angular noob here ...I recently switched to:
    constructor(private categoriesService: CategoriesService){
    from:
    private categoriesService: CategoriesService
    constructor(private categoriesService: CategoriesService){
    this.categoriesService = categoriesService
    }
    lol, it also feels weird to me that I am putting stuff in a constructor, but I am not instantiating the objects (Angular is)... So I don't actually pass these services to the constructor

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

    service locator pattern hides the implementation and introduce DI concept in the class dependecies. For instance to test a class using inject() would only work using the container or you should be able mock or stub the inject function, while in constructors can work also outside Angular as long as you dependency's are proxy's. (ex a proxy to httpclient type ) It's nothing new, most of the time it's much better to use constructor injections because inject pattern risks seems unharmful but delivers coupled code to the injector. also when using a function using internally inject... why not pass the dependency to the function argument instead? it's bad, maybe looks cool but I only see drawbacks especially in large codebases where many people working on it with various expertise levels..

  • @r-naotwo6290
    @r-naotwo6290 Год назад

    Does it work with ActivatedRoute?

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

    inject crate new instance of service? and you can't share data between 2 component?

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

      No the singleton pattern is not affected by the inject function. It behaves the same way it does with the constructor based Dependency injection

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

      No, same instance. You can share

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

    i've liked the inject change... plus.... you missed the bonus fact that they can be used inside FUNCTIONS.. which dont have constructors... (like functional guards)

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

      Yeah. and readability, design patterns and other small things are overrated anyway.

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

    show us your neovim config

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

    I’ll stick to constructor for now. I’m working on a angular 12 project 😢

  • @ucnguyenphanhuynh3134
    @ucnguyenphanhuynh3134 19 дней назад

    good

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

    But how often you use inheritance? 2 times in 1 year? Is this so big problem add super() and have contructor order if its so rare?
    How you will construct isolated component for unit testing?

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

      Some people might use it more heavily, but for me the inheritance problem was just a small added bonus - mostly I see the two approaches as being pretty equivalent, I mostly just think inject() is nicer from a syntax/DX point of view. As for testing, I use TestBed anyway so it isn't a problem but yes this would be a factor for people who want to create tests by passing deps through the constructor

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

      @@JoshuaMorony also you know compound components pattern? Following this concept its possible inject parent component into child bus also child can live without parent, in that case we use @Optional decorator on dependency in constructor (also in some cases build will be smaller). Injecting in that way we cant use decoraters anymore i guess, right?

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

    I was hoping it was a way around circular injection problems.... but alas😢

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

    Seems more declarative to me. I kind of like it.

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

    for those working with Angular and Spring, isn't this the same idea used by @Autowired for fields?

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

      100%. i'm kinda surprised to see a known antipattern promoted like this.

    • @rened.lacruzibarra5974
      @rened.lacruzibarra5974 Год назад

      @@adambickford8720 the good pattern is use constructors instead of autowired ?

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

      @@rened.lacruzibarra5974 Really just a constructor, no annotations required. Spring will infer the types and supply them automatically by looking at the available factories. Then you use lombok to generate the constructors so it *looks* like field injection again lol!
      But now your core logic is completely isolated from your container. This really helps in testing, evolving, aggregating/composing, etc.
      The container is for keeping your business code isolated from the 'real world' concerns (I/O and all the issues that come with it).

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

    huhu I've got a question and would love if someone could answer. So I do prefer using the inject function, but I run into the following problem: I mostly want to have the injected Services private as there is no need for accessing them outside of the component. And I mostly want to use the declerative approach and make my members constants. So it would look like this:
    public readonly someObservable$ = someService.doSomething$();
    private readonly someService = inject(someService);
    this code obviously fails as I use the service before I declare it. But if I move the service up, then I have the problem with eslint and member ordering; it says that private members are to be declared after the public ones. I wonder, how can we fix this problem? I can of course just ignore the tslint rule for this case but is this the best practice?

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

      I've been using private fields to deal with this (e.g. #someService = ....) this makes it private (and also has the side benefit of being enforced at run time but I don't really care so much about that) and ESLint won't complain about the ordering.

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

      @@JoshuaMorony hey only saw it now, thank you I'll try it out!

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

    sort of a @autowire in sprinboot

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

    Exactly to the point. Not just in Angular but NestJs, we also switch to inject() function. It's boost our develop experience as we can take advanced of OOP.

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

    How do you determine if the injection is private or public? (tbh, I don't know any usecases for public but it seems like a difference between the two.)

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

      It's public by default, if you want to make that explicit you just prefix with public just like in the constructor, or if you want it to be only accessible to the class you prefix with private, if you explicitly want the class and the template to be able to access it but nothing outside then you can use protected

  • @40fps143
    @40fps143 Год назад

    What IDE is that ?

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

      It's neovim, using this config: github.com/joshuamorony/nvim

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

    lol other DI frameworks switched from field injection to constructor injection to prevent missing dependencies.

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

    A way to "inject" some service inside the ngOnInit would be to inject the Injector first and then using that in ngOnInit. But prob not the best idea 😂

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

    Funny/interesting that Spring Framework has shifted from field injection to constructor injection and Angular might be doing the opposite.

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

      Angular doesn't do the opposite. Some people think that injecting above the constructor is the way to go due to lack of OOP knowledge.

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

      @@merlinwarage Angular is certainly embracing field injection, documenting it in their latest First Angular App tutorial and Learning Angular youtube series.

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

    I actually don't like this trend for 2 reasons :
    1. In this example, it is far from obvious that you can use "history" or "username" in your component, and you might simply inject it again not knowing that you have access to these properties from the BaseComponent class directly, especially if someone else arrive in your project later and don't know how things were set up this way. If you stick to the constructor method, you'll get an error which is a good thing to remind you what the BaseComponent class needs (and offer in exchange).
    2. When you use a constructor, you can refer to this part of the component to check all the dependencies in one and only one place. Using the inject function, your dependency can be declared anywhere in your code (as long as it's been declared in the class scope and not in a function as you've shown).
    There are probably other use cases where the inject function can be neat, but i'll stick with the constructor injection in component and services to make sure my team doesn't make my code a hell to read.

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

    Yes I will Switch jeje is more simple

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

    You can achieve the same thing by using a static class with a reference to the main injectors from the module classes

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

    Nope , definitely not for me from my experience. I understand your intention, but I would still recommend sticking with the regular Angular DI pattern. I have been working with Angular since AngularJs and have been mentoring the Angular community on different projects through all versions up to the latest. The default pattern works great, is stable, and has been industry-proven and trusted by the community.
    Although Angular as a framework has added new options to attract React developers, I don't think that the Angular community, who have been using the framework for a long time, will appreciate if the framework tries to be another React. The trend of trying to 'React'ify Angular goes against the established Angular patterns and will create clutter for the community.
    One of the things that I love about Angular is that everything works and there are no 1000 ways to do the same thing. I understand that there is a new trend of trying to make Angular more like React, but from my experience, that is the wrong way to use Angular (although no one is stopping you from doing it).
    One advantage that I have found when working with Angular over the years is that there is a clear defined way to do everything. This makes things easy to maintain. For large teams with a lot of developers with different experiences working to build an enterprise application, this kind of organized way of doing things makes everything easy to scale, modify, and maintain.
    For example, if you are a frontend developer who has worked in Angular and React across different projects, even if you change to a different company, the pattern for Angular will remain the same, making it easy to understand and maintain.
    However, in the case of React, each and every developer/team/company has their way of doing things, resulting in 1000 ways of doing the same thing. Trust me, it's too cluttered. There is even a joke about it among the developers I know: "My way of using ReactJS is unique to me and differs from yours." Well, they are all right, but that is the problem itself.
    The above well-defined way of doing things made Angular popular among enterprise software development.
    I would also like to know what others in Angular community thinks about this. So, I invite you to share your video here: facebook.com/groups/angular.developers.community/"

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

    I changed to it as soon as I saw that Brandon R. used it in one of his live streams. Angular should really update their docs and tutorial to use this instead of constructor cause it's so much clearner and easier to write

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

      I like the idea of just doing whatever Brandon does, this is a good strategy

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

    inject(UpvoteService)

  • @razt3757
    @razt3757 Год назад +5

    This is a bad idea. IMO.
    The reason injections are done through constructors by default is because it's impossible to miss an injections while constructing the service by hand, for example when testing.
    Property injection is a bit of an anti pattern because of that, as many have already pointed out in the comments.
    People have tried to use property injections in Java for a long time, and to be fair, Java developers had an even more convincing reason: Java constructors can't promote constructor parameters directly to class properties, like you can in TS or other languages.
    You would have to manually assign them the old way: this.myProp1 = myProp1.
    But even that was not convincing enough because nobody uses prop injection anymore, or at least they shouldn't.

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

    and testing? is more more complicated