2

Let's say we have an application with a lot of lists and therefor some basic components

export class SimpleListComponent { ... }

export class ExtendedListComponent extends SimpleListComponent { ... }

... which we can easily extend. They carry all the basic functionality for our lists (e.g. switch pages, count results,...). We use those two basic components for two different lists of heroes:

export class HeroSimpleListComponent extends SimpleListComponent { ... }

export class HeroExtendedListComponent extends ExtendedListComponent { ... }

Unfortunately we still would have to duplicate a lot of our code because HeroSlimListComponent and HeroExtendedListComponent share a lot of their functionalites (e.g. load heroes, route to hero, ...).

My first try was to pass the class which we need to extend

export class ExtendedListComponent<T = SimpleListComponent> extends T { ... }

but that does not work. Additionally I found this post which states, that multiple inheritance is not possible within typescript. Still I have the feeling that I'm missing some basic angular component connected solution here.

Thanks in advance for your help!

sevic
  • 879
  • 11
  • 36

1 Answers1

1

You are correct, multiple inheritance is not a thing available (unfortunately because it'd be super cool).

Possibility 1 It seems like your common actions could live inside of the simple list component and you could provide the properties needed in the extending components (like paths) in the constructor. When you call super(), the config options can be passed down.

export class SimpleListComponent {
    constructor(
        routePath: string,
    ) {}
}

// extending component
export class HeroSlimListComponent extends SimpleListComponent {
    constructor() {
        super('<my-route-path>');
    }
}

Possibility 2 It might be worth checking out mixins! I have not played with these though, so maybe someone with some experience can weigh in? They don't seem like they'd fully solve the problem as you still have to implement the interface, but it could be a good common set of functionality for the parent components.

Possibility 3 (possibly my personal fav) Keep the generic list and extended list components as components that accept inputs and give outputs and don't extend them. Instead, use them in html. For example, navigation paths can be passed in, and data services can be provided at the parent level component and injected into the child components in the tree. To configure the list items, you can pass in template refs (see the material tables examples). This is just a rough example and would need optimization, but here you go:

// simple list component
// selector = simple-list
constructor(simpleListService: SimpleListService) {}

// hero simple list component
@Component({
    ....
    providers: [
        { provide: SimpleListService, useClass: HeroSimpleListService },
    ],
})

// html
<simple-list [navPath]='heroNavPath' <...other templates / props>>

Something to keep in mind is that every piece of code from a class you extend is added again to your final build as duplicated code in each extending component (check out the output from prod builds, it's kinda interesting).

  • First: thanks a lot for the time and effort you put in that answer! i really appreciate it a lot. **Possibility 2** same here. I already tried but failed so far. I will keep trying. – sevic Feb 10 '19 at 07:18
  • 1
    **Possibility 3** when the project started there was one generic `ListComponent`. From time to time the differences between the different lists grew. Some special pipes, icons, `*ngIf`, classes for specific cells ... I started to write config files and in the end I ended up into managing my list's rather by a lot of small extensions than by one component that can handle everything. It increased the readability and maintainability of the code a lot. I am about 51% sure this is the best practice but please correct me if I'm wrong. – sevic Feb 10 '19 at 07:19
  • 1
    The real issue I have with answering that is "best practice" in that Angular is an opinionated framework- and what may work for one team may not for another. From the guides from the Angular team it **seems** like your practice is more how they intended things to be done (helping support the **single purpose** comments). I do generally agree with what you are describing as a list page can have many working pieces. Pagination, data display, load state, search fields, etc. with a general wrapper. Angular's **single purpose** suggestion (and material2 components) support these being separated. –  Feb 10 '19 at 13:43