Geek
Geek

Reputation: 3329

typescript scroll position

In my angular UI code, I have a component class that calls a like below

app.component.html

//...
<div class="banner">
    <p-dialog [(visible)]="displayCOI" styleClass="coiDialog" [contentStyle]="{'overflow-y': 'hidden'}" [modal]="true" [style]="{width: '75vw'}" [baseZIndex]="10000" [showHeader]="false"
        [draggable]="false" [resizable]="false">  
        <coi (notify)="onCoIAccept($event)"></coi>
    </p-dialog>
</div>

...///

coi.component.html looks like below

<div>
<div class="row" style="padding: 10px 0px">
    <div class="col-sm-4">
    <p align="center"><b>Instructions</b></p>                        
    <br>...//
    </div>
    <div #scrollDiv id="scrollDiv" class="col-sm-6" style="height:350px; overflow-y: scroll;" (scroll)="onScroll($event)">
    <p-table #dt [columns]="cols" [scrollable]="true" [value]="usersLi" [(selection)]="selectedUsersLi"  dataKey="id">
    //....
    ..///
    </p-table>
    </div>
    <div class="col-sm-2">
    <div align="center">
        <button pButton type="button" label="Accept" [disabled]="disableAccept" (click)="close()" class="ui-button-rounded"></button>&nbsp;
        </a>
    </div>
</dv>
</div>

coi.component.ts code is as below:

export class coiComponent  {
  @ViewChild("scrollDiv") scrollDiv: ElementRef;
  disableAccept: boolean = false;
  
  ngOnInit():void { 
    this.keys = Object.keys(this.propertyObj); 
    this._utilService.convertKeysToHeader(this.keys,this.cols);
    this.disableAccept = true;    
    this.loadRecords();
  }
  
  
  onScroll(event: any) { 
    // visible height + pixel scrolled >= total height 
    if (event.target.offsetHeight + event.target.scrollTop >= event.target.scrollHeight) {
        this.disableAccept = false;
        console.log("End");
    }
  }
  
   ngOnChanges(changes: SimpleChanges){
    console.log("ngOnChanges" , changes);
    for ( const propName in changes){
        let change = changes[propName];
        if ( propName == 'coi'){
            // console.log('CHANGED...DO HERE');
            console.log(this.scrollDiv.nativeElement.offsetHeight);
            console.log(this.scrollDiv.nativeElement.scrollHeight); 
        }
    
    }
    
    }
}

As you can see the modal is divided into 3 DIV. 1. instrucations, 2: table, 3. Accept button The modal by itself has a fixed height and scroll hidden. The div with table has a fixed height and overflow scroll and it works perfectly. Now the table can be with 30-50 records so vertical scrolling is enabled. I want the accept button on the 3rd div to be enabled only when the user had scrolled the table and has seen all the records. So the function (scroll)="onScroll($event)" enables only when the scroll is scrolled completely and it works perfectly.

my question is Some users may see less than 5-10 records which means scroll wouldn't be enabled for those users and accept also need to be enabled for them. Any suggestion on how to do this, please? I tried adding an id for the div tag called "scrollDiv" and #scrollDiv and passing this as an ElementRef and on ngOnChange trying to get the offsetHeight and scrollHeight but I get value '0' on all the cases.` Can someone help me with this?

I have updated my question. Please give some suggestions. Thank you.

Upvotes: 2

Views: 7146

Answers (1)

Francesco Lisandro
Francesco Lisandro

Reputation: 720

I'll try to give you a running idea, then you can understand and apply it to your case. You can check at this link.

Explanation of the example

In the component you have 4 important things to consider:

  • isActionDisabled a variable that says if your action should be disabled or not
  • @ViewChild('containerElement') containerElement a refer to the scrollable container of the table
  • onScrollContainer a method that's executed when you scroll the containerElement
  • disableByScroll a method that changes the value of isActionDisabled according to the position of the scrollbar of the containerElement. If it's on bottom isActionDisabled is false otherwise is true.

The most important method is disableByScroll:

disableByScroll(): void {
  if (this.containerElement) {
    const element = this.containerElement.nativeElement;
    this.isActionDisabled = !(
      element.scrollTop ===
      element.scrollHeight - element.clientHeight
    );
  } else {
    this.isActionDisabled = true;
  }
}

Please read this article to understand what I did. disableByScroll is called each time a scroll event is called on containerElement

onScrollContainer(): void {
  this.disableByScroll();
}

and after view init

ngAfterViewInit(): void {
  this.disableByScroll();
  this.cdr.detectChanges();
}

That is useful if you have a number of items that do not activate the scrollbar. Please, read this guide to understand the lifecycle events of an Angular application. As you can see I called a method detectChanges of the ChangeDetectorRef. Reading that guide you'll understand why.

About the template, it's pretty simple and you can figure it out.

Upvotes: 2

Related Questions