Josh
Josh

Reputation: 331

How to create multiple components with same logic or 1 component with multiple templates?

I built a header row component for table-styled data in a report that allows multi-column sorting. It's pretty simple: one property, two functions and an @Output() to let the parent component know when the order has changed.

I'd like to use now use that component in all of the other reports I have - every one will have the same logic, but they'll each have a different display.

I know than I can add an @Input() for reportType and then *ngSwitch code in my template, but I'd love to find a way to actually isolate the HTML for each header into it's own file (possibly with it's own SCSS file too) without creating a bunch of components with exactly the same logic.

That logic is included below just for fun.

import { Component, EventEmitter, Output } from '@angular/core';

@Component({
  selector: 'sort-row',
  templateUrl: './sort-row.component.html',
  styleUrls: ['./sort-row.component.scss']
})
export class SortRowComponent {

  sortOrder: string[] = [];

  @Output() sortChanged: EventEmitter<string[]> = new EventEmitter<string[]>();

  constructor() {}

  sortingBy(field, dir?) {
    if (dir) {
      if (dir === 'desc') {
        field = '-' + field;
      }
      return this.sortOrder.indexOf(field) !== -1;
    } else {
      return this.sortOrder.indexOf(field) !== -1 || this.sortOrder.indexOf('-' + field) !== -1;
    }

  }

  toggleSortCol(col, evt) {

    const ascIdx = this.sortOrder.indexOf(col);
    const descIdx = this.sortOrder.indexOf('-' + col);

    if (!evt.shiftKey) {

      if (ascIdx !== -1) {
        this.sortOrder = ['-' + col];
      } else if (descIdx !== -1) {
        this.sortOrder = [col.replace('-', '')];
      } else {
        this.sortOrder = [col];
      }

    } else {

      if (ascIdx !== -1) {
        this.sortOrder[ascIdx] = '-' + col;
      } else if (descIdx !== -1) {
        this.sortOrder[descIdx] = col.replace('-', '');
      } else {
        this.sortOrder.push(col);
      }
    }

    this.sortChanged.next(this.sortOrder);
  }
}

Upvotes: 0

Views: 819

Answers (2)

Sergey
Sergey

Reputation: 7682

So when you want to have several components using same logic while having different markups you neeed to simply create another component. Extend the one with the logic. And use all the benefits of OOP (inherited props and methods).

Upvotes: 1

Abdelrhman ElSayed
Abdelrhman ElSayed

Reputation: 439

I think you can just add new @Input() customCSSClasses: Object to your generic component and pass the new CSS classes from host component and use ngClass on selected elements to apply those custom classes (you need to add those custom classes in your global styles.css file.)

For example:

// Host component.html
<sort-row [customCSSClasses]="{input: 'dark-input', select: 'dark-lg-select'}" 
          // the other config
></sort-row>


// sort-row component.ts
@Input() customCSSClasses?: Object;

// sort-row component.html
<input [ngClass]="customCSSClasses?.input ? customCSSClasses?.input : 'default-input'">
<select [ngClass]="customCSSClasses?.select ? customCSSClasses?.select : 'default-select'"></select

Upvotes: 0

Related Questions