Erm … if this is ugly then please tell me how to do it right. The aim is: I have a model and I try to use services in it but I want to keep the constructors of the models clean. So new MyModel() is nicer than new MyModel(this.myService), because then I would have to constructor(private myService: MyService) in the above class that executes this line new MyModel(this.myService) and every inheriting class would have to constructor(myService: MyService) { super(myService); } … so this way works but is more ugly …
Your answer to your question above:
// In app.modules.ts ...
export let AppInjector: Injector;
export class AppModule {
constructor(private injector: Injector) {
AppInjector = this.injector;
}
}
// Later somewhere in the code ...
AppInjector.get(MyService);
Keep your ugly code snippets at a dark, cold and dry place
By the way: It does not look so ugly … and it keeps ugly constructors away
Options aren’t always a good thing to have. In fact, I spend a lot of my time figuring out heuristics for limiting my options to only the ones that I’m not going to end up yelling at myself in the future for having taken.
I’m not a big fan of dogmatic OOP in general, but doubly so when working in a language that has no core support for it at all, such as JavaScript. When I started learning OO concepts in C++ over 20 years ago, I tried to put as much intelligence in my data containers as possible. I found those designs did not age well, for a variety of reasons. A couple:
Logic gets scattered all over the place, so you end up going up and down rabbitholes trying to understand the gestalt of what is going on.
Classes, while a convenient concept for language implementors, aren’t really particularly relevant for application writers. In an application, all you really have are objects, and you don’t gain much value by pretending otherwise.
So I prefer putting all intelligence in objects that do not carry data, but instead operate on ones that do. For objects that do carry data, that is their only role.
I find this structure aligns very naturally with the Angular framework. Absolutely no code is needed to animate JSON that comes from an external source into an interface. The fact that it is an interface and not a class reinforces the fact that all the methods are in the service provider instead of the data container. I don’t have to worry about lifecycle management for data containers because there is nothing to manage. I don’t have to worry about lifecycle management for service providers because Angular’s DI does that for me.
Following these rules protects me from the temptation to try implementation techniques that I am going to look back at in a few months when doing maintenance and say “why did I create all these hoops for myself to jump through and now how do I move any of them around without having to rewrite everything?”.
@rapropos
THIS is a really good answer Thanks for your advice, I’ll keep this in mind. The only ugly part of thing is that all methods are placed into one big service class and not to there, where they logically could be. But if I understand you right, you mean: “Less is More”
I have a list with items … The model holds an array of those lists: Three classes: Model, List, Item. When adding lists to the model I need to do some tasks that could find their place in a method, called “addList()”, of the model class for the list … this was my intention when writing methods in models. But when I “listened” right, I should move them all to the service.
It’s hard to say much more specific without knowing more about the nature of the lists and tasks. In general, I would try as hard as possible to design away the tasks. For example, say we have a field in each list that knows what position it holds in its model. You could have a moveDownWithinModel() method in the list that increments the internal index. The problem with that is that it becomes nigh-impossible to avoid bugs where we get collisions when two separate lists think they’re #3. So the first thing I would do is to try to see if I could do whatever it is that I need to do without needing this index being stored anywhere at all. If I end up needing it, I would put the shiftListDownWithinModel() into the service provider, where it can look at the actual array contained in the model and make the necessary modification. Since the array itself is the authoritative and singular place where ordering information is kept, it becomes impossible to have collision bugs.
I haven’t found this very much of a concern in practice, but if you do, then I think it would be perfectly reasonable to break the “one big service class” into several smaller service classes with their own area of responsibility. Injecting services into other services works just fine with Angular, if needed. The place I’m suggesting drawing the bright line is between “things that know specific information” (model) and “things that know how to do stuff” (service).
IOW, I would treat the very premise that started this thread as an alarm bell that is warning us that we’ve drifted out of our lane. A service class is managed by DI, and a model class (if you’re still not convinced about just using interfaces) needs to be able to live its entire existence completely unaware of anybody in service-land, so the second we find ourselves needing a reference to a service in a model, something is broken at the design level.
I’m always nervous when somebody says at the beginning of a topic “it’s really a simple question”. Quite frequently, it turns out to be anything but, and this one was no exception.
But isn’t this exactly what you want when your model does depend on something? Only then you can replace it with a mock or other implementation depending on your need. Only then you can be sure to be aware of this “dependency” inside the model.
Thanks for your answer. I got what I need. I think this topic is allthough self explenary when I think about … I would ask you as a moderator to delete this hole topic … I think no one can really do something meaningful with this posts if I interpret your reactions right.
We don’t delete topics around here. You selected a response as solution, so anybody trying to do a similar thing can use that if he wants to follow your route.
I actually just asked a rethorical question and explained the motivations behind it again. You can of course ignore it, reply with “Yeah, but I want to do it anyway” or whatever you like.
Thanks … So this topic makes sense … after calling it “ugly” and “alarm sirene ringing” code. Right? … just smile, I’m joking Your answers helped me and showed me a mistake that could be done by many newbies in Ionic2 like me. Perhaps this topic could be seen as a hint.
I have no idea where you are taking your quotes from or whose messages you are attributing to me. Maybe take a minute and skim through all my messages again.
No you’re right. I mixed all answers to one bundle. So again: Thank you for all your answers. It helped me. As I deleted the message I sent to @rapropos above: "Please help me out. This hole topic sucks my balls ", if I may say so.
I think this topic can be closed now. Have a nice evening everybody and again: Thanks for your help and advices
To anyone who wants to use Injector instead of a constructor to inject a service: I hope you read the “Disadvantages” section of the link I posted in my previous comment. If you use reflection instead of dependency to inject services, you expose your app to security risks and other issues. There might be some rare meta-programming situation where you have to do it, but “it works this way,” or, “it looks nicer this way,” aren’t strong arguments for that approach.
… or shorter: Just use the regular way of targeting services (over constructor parameters) than using any reflective or manually lifetime cycling objects to access a service instance of the DI.
Longer: If you inherit the parent class that uses a service over it’s constructor parameters, like constructor(private myService: MyService){}, then you’ll need to call constructor(myService: MyService) { super(myService); } in your child class and every other child class that inherits from this child class. For sure, the child classes allthoug need to import MyService else you don’t have a value that you can super() to the parent class. Ugly? Nooo … Regular, even if the parameters are private or optional or should get their values from a DI or whatever … standard oop allthough.
Sure, if you use the new keyword to instanciate the above parent class, it would look like let whatever: MyService = new MyService(this.myService), but don’t do it as @AaronSterling mentioned for security risks etc. By the way: The new way is not the right way to get the instance of a service from the DI, the same for the reflective way. Just use the parameter-in-constructor way to fetch the instance of a “singleton” service instance.
If you think, something looks ugly, just don’t care about: It’s “regular” . Like it to be newbie and talk with professionals for answers … oh yeah: Just read the docs … and don’t ask again or for details or you’ll be separated from the “future readers” (just kidding, read yourself above) .
First off, that won’t work. In order for the provider to be usable in the component, it still has to be injected in the constructor. Secondly, unless you are certain of what you are doing, you don’t want to put providers on components. That results in a separate object of each provided class per component, which is rarely desired.
Oh all right. I solved the task by another way, simplyfied usage of the constructor parameters to get the access to the service instances, like in doc told. You’re right: Why make things complicated, when there’s a simple way