bikecoders / ngx-sticky

Angular directive that adds sticky position to an HTML element and also applies and remove a custom class when the element is sticky positioned.
https://bikecoders.github.io/ngx-sticky/
10 stars 3 forks source link

Cannot read property 'insertAdjacentElement' of undefined #24

Open allahyar opened 4 years ago

allahyar commented 4 years ago

Angular : 9.0.1 ngx-sticky-directive : 1.2.8

image

dianjuar commented 4 years ago

Hello @allahyar can you provide more context about your problem?

A stackblitz link would bring more clarity

yossely commented 4 years ago

Hi

TL; DR

Pass the triggerOn id value this way [triggerOn]="'text-content'":

  <div ngxSticky [triggerOn]="'text-content'">
    Sticky Title
  </div>
  <div id="text-content">
    Text
  </div>

We found the problem of that bug, it's because Ivy, we have 3 options to solve the error:

  1. Recommended Pass the triggerOn id value this way:
    <div ngxSticky [triggerOn]="'text-content'">
    Sticky Title
    </div>
    <div id="text-content">
    Text
    </div>

Ivy changed something about how we pass parameters. There is an issue open about it

According to Ivy Compatibility guide

Unbound inputs for directives (e.g. name in ) are now set upon creation of the view, before change detection runs (previously, all inputs were set during change detection).

  1. Another option is to pass an HTMLElement as the triggerOn property like this:
    <div ngxSticky [triggerOn]="textContent">
    Sticky Title
    </div>
    <div #textContent>
    Text
    </div>
  2. The No recommended solution is to temporarily turn off Ivy, this can be done by adding the next option to your app's tsconfig.json file:
    {
    "compilerOptions": {...},
    "angularCompilerOptions": {
    "enableIvy": false
    }
    }
yossely commented 4 years ago

We will close this issue after adding this note to the README as part of the documentation and deploy library (so the doc is updated there too).

METACEO commented 4 years ago

Hi @yossely, I found this issue via https://github.com/angular/angular/issues/34227 and I am trying to piece together an ivy directive myself: https://github.com/METACEO/ng-transition

While I believe we're facing the same issue, I'm experimenting with your first recommendation and I'm not having any luck (against my own directive) and our directive's internals look the same: @Input() and set

Does your first recommendation work for you?.. or are you proposing it as a change?

yossely commented 4 years ago

Hi @METACEO, yes, we're facing the same issue and yes, my first recommendation works in my case, passing the string property as [triggerOn]="'text-content'" my directive works as expected.

In my case, I wanted to get an element by id which is indicated by the triggerOn value and the view was not rendered yet, by changing the binging to [triggerOn]="'text-content'" the view was ready and then the element could be found. Do you have the same case?

METACEO commented 4 years ago

by changing the binging to [triggerOn]="'text-content'" the view was ready and then the element could be found. Do you have the same case?

I unfortunately begin to receive a Can't bind to 'ngTransitionEnter' since it isn't a known property of 'div' error when I wrap up my attributes with the [] brackets.

A demo of the error: https://stackblitz.com/edit/angular-ivy-rlsxgb?file=src%2Fapp%2Fapp.component.html

And I look my directive's source and it looks identical to ngx-sticky (in terms of @Input() and set) and if I remove the [] brackets, it will compile but the set never occurs (determined with breakpoints.)

I don't know if this is the same for ngx-sticky but if I hard-lock my consuming project to angular 9.0.0, everything works. The moment I get the latest (angular ^9.1.0) then this issue occurs.

Thank you @yossely for verifying that your first recommendation works, I'll work towards that!

// ngx-sticky
@Input()
set triggerOn(value: string | ElementRef | HTMLElement) {
  this.setHTMLElement('_triggerOn', value);
}

// ng-transition
@Input()
set ngTransitionEnter(ngTransitionEnter: string) {
  this._ngTransitionEnter = ngTransitionEnter.split(' ');
}
METACEO commented 4 years ago

@yossely I believe I've determined that my issue was the conditional template I was rendering with the *ngTransition directive. I've changed the directive to work with the [ngTransition] binding and things are looking much better for the directive and its other attributes, too.

After reading the "Ivy compatibility examples" page, I think the conditional template was interfering with the attributes being set. It wasn't the change I was hoping to find, but it should make due in the meantime. Your first recommendation works just well for me!

Thank you again for the support and replying earlier!

yossely commented 4 years ago

@METACEO you're welcome! Glad to hear that you could solve it too :+1: