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

  Рет қаралды 62,320

Joshua Morony

Joshua Morony

Күн бұрын

Пікірлер: 190
@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
@DannyMcPfister
@DannyMcPfister Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@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 Жыл бұрын
@@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 Жыл бұрын
​@@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 Жыл бұрын
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.
@vredurs
@vredurs Жыл бұрын
Never stop producing content please, I think you are the Matt Pocock of Angular!
@tntg5
@tntg5 3 ай бұрын
Great ! I saw that inject being used here and there but I didn't see in action the fact you don't have to worry about adding a new injection in Base class. That's for me, is the best benefits. I can't remember how many times I had to add a provider in a Base class and then run through all children to update them which always felt like torture. Thank you for sharing. As for niceness, I still think injecting in the constructor is better. But now I have a stronger reason to switch
@Thierry-m1d4y
@Thierry-m1d4y 6 ай бұрын
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
@Blafasel3
@Blafasel3 Жыл бұрын
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 Жыл бұрын
@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 Жыл бұрын
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 Жыл бұрын
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.
@piotrjarzabek-up9jc
@piotrjarzabek-up9jc Жыл бұрын
Perfect, this is very good solution for all base components :) great job
@ZuravvskiIT
@ZuravvskiIT Жыл бұрын
Just in time Joshua! Yesterday, I came to the same conclusion whilst refactoring old routing guards.
@FauzulChowdhury
@FauzulChowdhury Жыл бұрын
Thank you for keeping us updated with the updates. Great use case demonstrated I have faced this issue with the super
@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.
@chaos_monster
@chaos_monster Жыл бұрын
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 Жыл бұрын
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 Жыл бұрын
@@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 Жыл бұрын
@@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
@ramtennae
@ramtennae Жыл бұрын
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.
@aheendwhz1
@aheendwhz1 Ай бұрын
@@JoshuaMorony Also, as a replacement for constructor based injection, inject makes it really hard to test the component class in isolation. If you always test with a TestBed, that might not matter. But it removes the option to test the component class without, and in general, to create an instance without any "magical" global state dependencies. You certainly want to test your services in isolation. Therefore, you won't be able to use inject in services. So now, you have 2 ways of doing dependency injection, which does not make it easy for newcomers to read your code. Also, it is another decision to make. This might scare newcomers, and I have to say it would also scare me, because sometimes it's really hard and exhausting to make such a decision and try to keep all the consequences in mind. If you're stuck in inheritance, then inject might ease things up. But always remember you wouldn't have the problems inject solves in the first place if you didn't use inheritance. And composition is also much easier and robust to test (and IMHO in general to work with) than inheritance. So my recommendation is to always use compositiom and constructor injection and never use the inject function. I don't think it was a good step that the Angular team made us waste our time arguing about this in the first place.
@JeetuChoudhary001
@JeetuChoudhary001 Жыл бұрын
Awesome. Definitely will switch
@EER0000
@EER0000 Жыл бұрын
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)
@toxaq
@toxaq Жыл бұрын
Would use it for the inheritance example but otherwise stick with constructor injection. I like knowing all the dependencies in one spot.
@MrBloodWoork
@MrBloodWoork Жыл бұрын
I switched to inject and I love it, no regrets at all! :)
@JozefRzadkosz
@JozefRzadkosz 7 ай бұрын
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
@JoshuaMorony
@JoshuaMorony 7 ай бұрын
Thanks and I'm using neovim
@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.
@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 !
@theWorldOfIss
@theWorldOfIss 25 күн бұрын
sir we can do like this if the component we wanted to use it like inheritance : constructor ({ super (inject (BaseDependency)) })
@mystyani
@mystyani Жыл бұрын
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.
@GerZah
@GerZah Жыл бұрын
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.
@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()
@ArchitecturalAesthetics2046
@ArchitecturalAesthetics2046 11 ай бұрын
very well explained. love this video.
@ShaharHarshuv
@ShaharHarshuv Жыл бұрын
Thanks for this video, will help me convince my team
@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.
@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 Жыл бұрын
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 Жыл бұрын
@@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
@PatricioHondagneuRoig
@PatricioHondagneuRoig Жыл бұрын
I hope this is expanded to inputs, outputs, and all other class member decorators eventually!
@teckasm
@teckasm Жыл бұрын
Makes usage with the occasional, unavoidable inheritance much nicer.
@JimmiJohnJunnior
@JimmiJohnJunnior Жыл бұрын
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. 🥂
@VictorHugolorenzana
@VictorHugolorenzana 4 ай бұрын
I think that the constructor is better to inject dependencies considering testing as part of most important development phase, to inject mocks to ensuee the quality of the component
@JoshuaMorony
@JoshuaMorony 4 ай бұрын
With inject you can still use TestBed to do this
@ali-celebi
@ali-celebi Жыл бұрын
Great video, as usual :)
@clashclan4739
@clashclan4739 Жыл бұрын
That adding removing in baseclass could break on runtime than compile time like constructor injection
@eliotistube
@eliotistube Жыл бұрын
I made this transition months ago in four different projects, no problems!
@HackHeyner
@HackHeyner Жыл бұрын
This is MAGICAL!!
@AbnerJuarez97
@AbnerJuarez97 Жыл бұрын
What about creating a decorator to do this same as well?
@aleksandarbudic6462
@aleksandarbudic6462 Жыл бұрын
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.
@mehdimahmud5191
@mehdimahmud5191 Жыл бұрын
thank you for th calrification. Just one thing. how do we use the services inside spec for testing?
@HassanRaza-ym3uf
@HassanRaza-ym3uf Жыл бұрын
Going to start using it right now
@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.
@PieJee1
@PieJee1 Жыл бұрын
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
@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?
@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.
@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?
@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.
@FraserMcLean81
@FraserMcLean81 Жыл бұрын
As C# backend developer, I prefer constructor based injection
@merlinwarage
@merlinwarage Жыл бұрын
Because that's the proper way.
@JohnConnorTM
@JohnConnorTM Жыл бұрын
I primarily see its advantage for base classes, not sure the esthetics of it bothers me either way. Thanks for an informative video!
@LeviDPS
@LeviDPS Ай бұрын
The “benefit” of inheritance and not having to add the services to classes that extend base classes doesn’t really seem like a win. I get the theory that it’s simpler, but the issue in reality is it hides all the dependencies. The result being someone might go extending a base class to get access to a service and add a heap of dependencies they don’t really need. And/or we end up with a base class that has various dependencies that are only needed in some instances.
@NickTsitlakidis
@NickTsitlakidis Жыл бұрын
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.
@GLawSomnia
@GLawSomnia Жыл бұрын
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 😁
@danilobassi8
@danilobassi8 Жыл бұрын
What about conditional injection?
@danielguzman8607
@danielguzman8607 7 ай бұрын
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!
@JakeAndDaddy
@JakeAndDaddy 5 ай бұрын
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
@AleksandraSetsumei
@AleksandraSetsumei Жыл бұрын
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 Жыл бұрын
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.
@AleksandraSetsumei
@AleksandraSetsumei Жыл бұрын
@@JoshuaMorony hey only saw it now, thank you I'll try it out!
@johangustafsson6121
@johangustafsson6121 Жыл бұрын
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 Жыл бұрын
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.
@jaybee6382
@jaybee6382 Жыл бұрын
What about for unit testing?
@r-naotwo6290
@r-naotwo6290 Жыл бұрын
Does it work with ActivatedRoute?
@marekk9008
@marekk9008 Жыл бұрын
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 Жыл бұрын
This is the perfect example of the service locator pattern being an anti-pattern. Thank you 🤗
@merlinwarage
@merlinwarage Жыл бұрын
If you don't need the dependencies / different instances, use abstract class.
@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
@LilPozzer
@LilPozzer 20 күн бұрын
Imagine you have a base class A and it uses inject service X, the base class A has a lot of children and they have children as well, the base class is an abstract class, and all the leaf children are components, each component uses scoped service X provider, meaning each component uses : providers: [SeviceX], and here is the catch, if you don’t do this scoped dependency registration for one of the components, you will get to know about it only when you open that component on the ui (or if you have tests for that). Which is kinda implicit. With global registration that should not be a problem 😅
@lightyagami5963
@lightyagami5963 8 ай бұрын
the injector function would work for the lazy injection places where inject function thorws error.
Жыл бұрын
what about the decorators @skipSelf and the others? Anyway inject its nice to avoid inheritance
@JoshuaMorony
@JoshuaMorony Жыл бұрын
You can still optionally provide InjectOptions to the inject function where you can specify skipSelf etc.
@arturkalbukov6856
@arturkalbukov6856 Жыл бұрын
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
@cipherxen2
@cipherxen2 Жыл бұрын
A better option would be to use annotations. Like @Autowired in spring.
@RayZde
@RayZde Жыл бұрын
inject (Location) throws an error inside a component of a component hard to track down.
@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?
@Billiam112
@Billiam112 Жыл бұрын
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 Жыл бұрын
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. :)
@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);
@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.
@mattlaw4395
@mattlaw4395 Жыл бұрын
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
@o_glethorpe
@o_glethorpe Жыл бұрын
Will stick with the constructor approach.
@yousafraza7747
@yousafraza7747 Жыл бұрын
Hey, can you make a video on zoneless change detection. Would really help
@kumailn7662
@kumailn7662 Жыл бұрын
True, I always annoyed with lots of parameters in constructor!!
@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.
@danny24_24
@danny24_24 Жыл бұрын
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
@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
@yuriinadilnyi3029
@yuriinadilnyi3029 Жыл бұрын
great tuts
@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.
@CaseAhr
@CaseAhr Жыл бұрын
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!
@zikkrype
@zikkrype 9 ай бұрын
I like point with BaseComponent
@j4nch
@j4nch Жыл бұрын
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.
@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..
@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 :)
@flavioarantesdoamorimbarce95
@flavioarantesdoamorimbarce95 Жыл бұрын
I’ll stick to constructor for now. I’m working on a angular 12 project 😢
@LarsRyeJeppesen
@LarsRyeJeppesen Жыл бұрын
Why 12?
@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 Жыл бұрын
@@merlinwarage Angular is certainly embracing field injection, documenting it in their latest First Angular App tutorial and Learning Angular youtube series.
@40fps143
@40fps143 Жыл бұрын
What IDE is that ?
@JoshuaMorony
@JoshuaMorony Жыл бұрын
It's neovim, using this config: github.com/joshuamorony/nvim
@dimitritsikaridze6220
@dimitritsikaridze6220 Жыл бұрын
show us your neovim config
@DenisEneotescu
@DenisEneotescu Жыл бұрын
for those working with Angular and Spring, isn't this the same idea used by @Autowired for fields?
@adambickford8720
@adambickford8720 Жыл бұрын
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).
@aheendwhz1
@aheendwhz1 Ай бұрын
Doesn't that defeat the whole purpose of the dependency injection pattern (inversion of control)? Inject to me seems like It's just a lousy old procedural "give me a class instance" function with global state. You could as well use the Singleton pattern this way. The idea of "inversion of control" is that the _caller_ decides how to inject the dependencies. So if you create an instance of your component class in a different context - say, in a test - then you can decide which implementations and which data you want to inject, and for example, replace some services with mocked versions, or inject test data for configuration values. I don't see how this is given with the inject function. To me, it looks like the inject function is neither good functional programming, nor good OO programming, because of the global state.
@PeterKlausSchmelzer
@PeterKlausSchmelzer Жыл бұрын
It doesnt look nicer.. but.. the inheritence issue is a valid argument to give this a try.. gj, tx for the explonation..
@andrelouw2677
@andrelouw2677 Жыл бұрын
I was hoping it was a way around circular injection problems.... but alas😢
@theanswer1993
@theanswer1993 Жыл бұрын
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 Жыл бұрын
I like the idea of just doing whatever Brandon does, this is a good strategy
@cosmokenney
@cosmokenney Жыл бұрын
Seems more declarative to me. I kind of like it.
@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 😂
@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
@donwald3436
@donwald3436 7 ай бұрын
lol other DI frameworks switched from field injection to constructor injection to prevent missing dependencies.
@kumailn7662
@kumailn7662 Жыл бұрын
sort of a @autowire in sprinboot
@ucnguyenphanhuynh3134
@ucnguyenphanhuynh3134 5 ай бұрын
good
@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.
The easier way to code Angular apps
9:54
Joshua Morony
Рет қаралды 69 М.
Why Angular Signals? Write Your First Signal
14:25
Angular University
Рет қаралды 16 М.
99.9% IMPOSSIBLE
00:24
STORROR
Рет қаралды 31 МЛН
Support each other🤝
00:31
ISSEI / いっせい
Рет қаралды 81 МЛН
Angular Inject Function - New Way to Inject Services in Angular 14?
21:56
Angular is about to get its most IMPORTANT change in a long time...
10:15
SQLModel + FastAPI: Say Goodbye to Repetitive Database Code
19:50
WTF is "modern" Angular development?
10:46
Joshua Morony
Рет қаралды 70 М.
Dependency Injection, The Best Pattern
13:16
CodeAesthetic
Рет қаралды 901 М.
ngTemplateOutlet is WAY more useful than I realised
16:36
Joshua Morony
Рет қаралды 77 М.
First look at Signals in Angular
18:43
Decoded Frontend
Рет қаралды 46 М.
Angular Inject Function - Better Than Constructor
8:10
Monsterlessons Academy
Рет қаралды 13 М.
Why didn't the Angular team just use RxJS instead of Signals?
8:15
Joshua Morony
Рет қаралды 103 М.