0

Since I haven't found any answer or similar case I'm posting this question here.

My App has the following structure:

  • AppModule
    • LayoutModule
      • MainComponent
      • SidebarComponent
      • SidebarService {providedIn: 'root'}
    • ContentModule
      • ContentComponent
      • ContentService {providedIn: 'ContentModule'}
      • ContentSidebarComponent
    • AnotherModule
      • AnotherComponent
      • AnotherService {providedIn: 'AnotherModule'}
      • AnotherSidebarComponent

There are a lot more modules in the style of ContentModule and AnotherModule.

Inside the SidebarComponent is a view container used for dynamic component generation.

The SidebarService contains a method like generateSidebar(component: any): void which is called inside ContentComponent: generateSidebar(ContentSidebarComponent) and AnotherComponent: generateSidebar(AnotherSidebarComponent) and handles the dynamic component loading like this:

Dynamic Component Loader with custom injector

const componentFactory = this.componentFactoryResolver.resolveComponentFactory(...);

const viewContainerRef = viewContainer.viewContainerRef;
viewContainerRef.clear();

let componentRef: ComponentRef<any>;
let injector: Injector|undefined = undefined;

injector = Injector.create({
  providers: [
    {
      provide: ContentService,     //AnotherService respectively
      useClass: ContentService,    //AnotherService respectively
      deps: []
    }
  ]
})

componentRef = viewContainerRef.createComponent(
  componentFactory,
  0,
  injector
);

There is no error like "No provider for ...".

When accessing the ContentComponent, ContentSidebarComponent is generated inside SidebarComponent properly.

When accessing the AnotherComponent, AnotherSidebarComponent is generated inside SidebarComponeent properly.

The Problem ContentService is also used inside ContentComponent, and there are some properties of ContentService that get changed. It seems like ChangeDetection is not working in the ContentSidebarComponent because the properties of ContentService aren't changing there.

By the way: Both services throw errors if there are multiple instances. So this is not the case and not the problem.

How can I trigger ChangeDetection inside the dynamically generated component when a value of a property of an injected service changes?

Thanks in advance.

4
  • Are you sure the problem is change detection? Add a button to log to the console the value you think has changed, and see if it really changed. Commented Aug 3, 2021 at 18:53
  • I added a property to the service which can be changed by a button. The button, its click method are in ContentComponent. The property changes in the service as it does in ContentComponent's template but not in ContentSidebarComponent's template Commented Aug 3, 2021 at 20:22
  • alright ... seems like there 2 instances, constructor is fired twice ... how to avoid that? how can I inject the service? Commented Aug 3, 2021 at 20:33
  • angular.io/guide/… seems like using useExisting instead of useClass is the solution ... but that gives me circular dep on ContentService Commented Aug 3, 2021 at 20:38

1 Answer 1

1

Fixed it passing the service instance into the provider like this

public generateComponent(component: any, service: any, instance: any) {
  const componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);

  const viewContainerRef = viewContainer.viewContainerRef;
  viewContainerRef.clear();

  let componentRef: ComponentRef<any>;
  let injector: Injector|undefined = undefined;

  injector = Injector.create({
    providers: [
      {
        provide: service,
        useValue: instance,
        deps: []
      }
    ]
  })

  componentRef = viewContainerRef.createComponent(
    componentFactory,
    0,
    injector
  );
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.