I have a module in Angular that is structured likes this:
moduleName
componentA
componentB
Now componentA
and componentB
are very similar, as they share some attributes and methods, e.g.:
protected available: boolean = true;
As I don't want to repeat myself, I've created a base class, that stores all this:
export abstract class BaseComponent {
protected available: boolean = true;
}
And both controllers inherit from that class:
import { BaseComponent } from '../baseponent';
export class ComponentA extends BaseComponent implements OnInit {
constructor() {
super();
}
ngOnInit() {
console.log(this.available);
}
}
This works just fine. However, when I research this soultion a lot of people are saying:
Don't use inheritance, use composition in this case.
Alright, but how can I use composition instead? And is the gain really that big over the current solution?
Thanks a lot for your time.
I have a module in Angular that is structured likes this:
moduleName
componentA
componentB
Now componentA
and componentB
are very similar, as they share some attributes and methods, e.g.:
protected available: boolean = true;
As I don't want to repeat myself, I've created a base class, that stores all this:
export abstract class BaseComponent {
protected available: boolean = true;
}
And both controllers inherit from that class:
import { BaseComponent } from '../base.component';
export class ComponentA extends BaseComponent implements OnInit {
constructor() {
super();
}
ngOnInit() {
console.log(this.available);
}
}
This works just fine. However, when I research this soultion a lot of people are saying:
Don't use inheritance, use composition in this case.
Alright, but how can I use composition instead? And is the gain really that big over the current solution?
Thanks a lot for your time.
Share Improve this question asked Sep 14, 2018 at 13:58 someone.else.2020someone.else.2020 1531 silver badge4 bronze badges 8 | Show 3 more comments3 Answers
Reset to default 12For composing objects in angular you need to have a reference to that object inside of your class, which shares data and functionality. To do that you need to use Angular services, and inject them to your class, and there should be 1 instance of service per component.
- Create a new service by running
ng g s my-service
, removeprovidedIn: 'root'
from your service annotation (We want to provide instance per component) - Add
public available: boolean = true;
to the service provide
the service through the components, in@Component
configs on your components- inject the service in your both component constructors,
constructor(private myService:MyService)
Now you have a composition that keeps data and functionality
@Component({
selector: 'app',
templateUrl: './app.my-component.html',
styleUrls: ['./app.my-component.css'],
providers: [MyService]
})
export class MyComponent {
constructor(private myService: MyService) {
}
}
If you create same components with big part same logic. you can use inheritance for example controlSelectComponent and controlInputComponent stackblitz example
For composition you need to create service and provide it to both components. But you dont keep component state in service becose all service are singletone. And when one component change state another component crash.
You also can provide service to each component in providers section
@Component({
selector: 'app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [MyService]
})
export class AppComponent {
constructor(private myService: MyService) {
}
}
But in case with saving state in service is not the best solution
Conclusion
Use services and composition for share helper methods between components.
Use abstract class and inheritance for components with same logic and state changes.
I would also recommend to read about Composition over Inheritance. The syntax(InversifyJs) is very similar that Angular uses. Please see this blog
validator = new Validator()
and later dovalidator.check(input)
in many classes. As opposed to each class extendingValidator
and inheriting thecheck()
functionality. – VLAZ Commented Sep 14, 2018 at 14:16serviceName.available
to access a property. But the advantage is, that the service is coupled more loosely, right? And a service is not necessarily global in Angular - I mean: the injected services are all individual instances for their component, correct? @KirkLarkin – someone.else.2020 Commented Sep 14, 2018 at 14:18