Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Table layout #146

Draft
wants to merge 12 commits into
base: master
Choose a base branch
from
Draft

Table layout #146

wants to merge 12 commits into from

Conversation

dhilt
Copy link
Owner

@dhilt dhilt commented Feb 26, 2020

Based on issue #40

dhilt and others added 6 commits December 12, 2019 00:53
by directly creating embedded view from component's template.
Remove intermediate <div ui-scroll> wrapping tag for ui-scroll component
# Conflicts:
#	src/component/processes/render.ts
#	src/ui-scroll.component.ts
#	src/ui-scroll.directive.ts
Comment on lines 81 to 86
constructor(
public changeDetector: ChangeDetectorRef,
public elementRef: ElementRef) { }
public elementRef: ElementRef
) {
setTimeout(() => this.ngOnInit()); // 😢
}
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@markdBC To say I don't like this would be a considerable understatement... ngOnInit must be invoked implicitly, and I have no idea why it became broken. It has something to do with new approach of creating the component on the directive level. The demo we developed on stackblitz has the same issue.

It would be very nice if you could take a look and help with it. For testing in ngx-ui-scroll environment you may use http://localhost:4200/#/test (after npm start), which runs demo/app/samples/test.component.html template. There are multiple issues behind this one, so to see the result is still impossible, but the initialization could be handeled in a proper way

Copy link

@markdBC markdBC Feb 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dhilt The problem is that ngOnInit is called after the first time ngOnChanges is called (https://angular.io/guide/lifecycle-hooks#lifecycle-sequence).

However, while ViewContainerRef.createComponent causes an invocation of ngOnChanges, the same is not true for ComponentRef.create.

You can find the definition of ViewContainerRef.createComponent, at packages/core/src/view/refs.ts:180 of the Angular source code:

  createComponent<C>(
      componentFactory: ComponentFactory<C>, index?: number, injector?: Injector,
      projectableNodes?: any[][], ngModuleRef?: NgModuleRef<any>): ComponentRef<C> {
    const contextInjector = injector || this.parentInjector;
    if (!ngModuleRef && !(componentFactory instanceof ComponentFactoryBoundToModule)) {
      ngModuleRef = contextInjector.get(NgModuleRef);
    }
    const componentRef =
        componentFactory.create(contextInjector, projectableNodes, undefined, ngModuleRef);
    this.insert(componentRef.hostView, index);
    return componentRef;
  }

ViewContainerRef.createComponent calls the ComponentRef.create method, and then calls ViewContainerRef.insert, which among other things causes change detection to occur inside the component.

A solution is to explicitly invoke change detection for the component, via ComponentRef.changeDetectorRef.detectChanges(). This is probably only slightly better than explicitly invoking ngOnInit, but at least we're not calling a lifecycle hook directly.

I've made a PR with this change at #147 and have a StackBlitz demo at https://stackblitz.com/edit/table-implicit-lifecycle-hook-invocation.

@dhilt dhilt mentioned this pull request Feb 26, 2020
componentRef.instance.version = version;
componentRef.instance.parentElement = this.templateRef.elementRef.nativeElement.parentElement;
this.viewContainer.createEmbeddedView(componentRef.instance.uiScrollTemplateRef);
setTimeout(() => componentRef.changeDetectorRef.detectChanges()); // 😢
Copy link
Owner Author

@dhilt dhilt Feb 28, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@markdBC I admire your deep insight of the Angular internal things and very grateful for your explanation regarding ngOnInit. As you can see I had to wrap changes detection into another setTimeout, the problem is that the onInit hook is being triggered (with manual approach) before the initial content of the component is rendered. Do you know, what can be done here? I tried to replace OnInit with AfterViewInit (the latest init hook), but it also runs too early.

The initialization, I need to run on the components first render, includes DOM parsing, in particular, the Scroller tries to find elements needed for virtualization. And immediate initialization (before DOM gets necessary elements during first render) just fails.

Also, calling componentRef.changeDetectorRef.detectChanges() seems equal to calling componentRef.instance.ngOnInit(), but I agree this is better than calling this.ngOnInit() on the component's constructor.

That's what we have now... And it would be great to dig a little dipper and find a way to catch the time of the first render properly. The last thing I want to add is that the demo starts working, not perfect, but something can be seen running localhost:4200/#/test

# Conflicts:
#	src/component/classes/viewport.ts
#	src/component/processes/render.ts
#	src/ui-scroll.component.ts
#	src/ui-scroll.directive.ts
@stale stale bot added the stale label Jul 24, 2020
Repository owner deleted a comment from stale bot Jul 24, 2020
@stale stale bot removed the stale label Jul 24, 2020
@dhilt dhilt added the permanent ignore stale bot label Jul 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
permanent ignore stale bot
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants