Angular: prevent re render of component inside it

645 Views Asked by At

I'm writing a table component that will need to be very open to modification for my company. And i decided to go for this:

table.component.html

<tbody>
  <tr *ngFor="let resource of results">
    <td *ngFor="let col of columns">
      <ng-container *ngComponentOutlet="col.component; injector: createInjector(resource, col.accessors)"></ng-container>
    </td>
  </tr>
</tbody>

In table.ts (just the interesting code):

  results: any[];



createInjector(resource: Resource, accessors: Accessors) {
    const columnConf = new ColumnConf();
    columnConf.resource = resource;
    columnConf.accessors = accessors;
    const options = {
      providers: [{ provide: ColumnConf, useValue: columnConf }],
      parent: this.injector,
    };
    return Injector.create(options);
  }

the injectable is like this

@Injectable()
export class ColumnConf {
  resource: Resource;
  accessors: Accessors;
}

accessors is a custom type i created to keep it readable:

export interface Accessors {
  [key: string]: (resource: Resource) => string | number;
}

and with this code, I can use the ngTemplateOutlet, pass custom value for column by row , put specific configuration to draw a component each time. But I also need my columns to be interactives.

trouble is: I can't use this to display component with some states, for example this one:

@Component({
  selector: 'col-actions',
  template: `
    <div ngbDropdown class="d-inline-block">
      <button type="button" class="btn btn-outline-primary" id="{{ id }}" ngbDropdownToggle>
        Toggle dropdown
      </button>
      <div ngbDropdownMenu [attr.aria-labelledby]="id">
        <button ngbDropdownItem>Action - 1</button>
        <button ngbDropdownItem>Another Action</button>
        <button ngbDropdownItem>Something else is here</button>
      </div>
    </div>
  `,
  styles: [],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ActionsComponent implements OnInit {
  id = Math.floor(Math.random() * 10000 + 1);
  constructor() {}

  ngOnInit(): void {}
}

It got a drop down menu, but it redraw immediately without keeping it state, so i can't keep it open. Any idea how to do so ?

I thought about ngtrack, but it didn't seem to work. Also tried to change the change detection strategy no luck either.

It seems it redraw every time, when i click anywhere on the screen, anf i want it to not or keep it state. Any ideas on how to do so?

1

There are 1 best solutions below

0
On

Find a solution, Turned out you should not create injector on the fly in the template, I now create the injectors directly when i get the API such as

  this.itemsToDisplay = [];
    let i = 0;
    this.results.forEach((resource) => {
      this.itemsToDisplay[i++] = this.columns.map((column) => {
        return {
          resource: resource,
          injector: this.createInjector(resource, column.accessors),
          column: column,
        };
      });