2

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.

1 Answer 1

2

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.

Sign up to request clarification or add additional context in comments.

5 Comments

thank you . can you please see my updated code and edits please?
I just edited it. I've created a playground for you so you can apply it to your code. What I did is to consider if the scrollbar thumb is at the bottom and you can know it checking if scrollTop = scrollHeight - clientHeight. You can do the same check to enable or disable the button if no scrollbar is present. In that case scrollTop is 0 and scrollHeight is equal clientHeight (so 0). Anyway, I added some links so you can understand it better.
@ Francesco Lisandro thank you. But when i get the clientHeight, scrollHeight, offsetHeight it all says 200 on page load. Do you know why?
It's a problem not related to it. Probably it's a syntax problem.
this.cdr.detectChanges(); made the difference thank you. @Francesco Lisandro

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.