NgbTypeahead component doesn't scroll inside a scrollable component

后端 未结 4 1298
温柔的废话
温柔的废话 2021-01-25 03:11

I am using NgbTypeahead component of ng-bootstrap. My problem is, when I put the typeahead component inside a scrollable component and make a scroll down, the position of dropdo

相关标签:
4条回答
  • 2021-01-25 03:45

    To add a vertical scroll bar to typeahead results, you can use something this:

    ngb-typeahead-window.dropdown-menu {
        max-height: 500px !important;
        overflow-y: auto;
    }
    
    0 讨论(0)
  • 2021-01-25 04:03

    As NgbTypeahead does not have support with scroll, we need to handle from component. Use showDropdownEle function on keydown of Input.

    private isElementInViewport(el, inputElem) {
    const rect = el.getBoundingClientRect();
    const rectElem = inputElem.getBoundingClientRect();
    console.log(rectElem);
    return (
      rect.top >= rectElem.bottom &&
      rect.left >= 0 &&
      rect.bottom <= (rectElem.bottom + rect.offsetHeight) &&
      rect.right <= (window.innerWidth || document.documentElement.clientWidth)
      );
    }
    
    public showDropdownEle(event) {
    if (event.keyCode === 38 || event.keyCode === 40) {
      if (event.target.nextElementSibling && event.target.nextElementSibling.nodeName === 'NGB-TYPEAHEAD-WINDOW') {
        let activeDropdownEle = (event.keyCode === 40) ? event.target.nextElementSibling.querySelector('.active').nextElementSibling : event.target.nextElementSibling.querySelector('.active').previousElementSibling;
        if (!activeDropdownEle) {
          const allDropdownElems = event.target.nextElementSibling.querySelectorAll('.dropdown-item');
          activeDropdownEle = (event.keyCode === 38) ? allDropdownElems[allDropdownElems.length - 1] : allDropdownElems[0];
        }
        if (!this.isElementInViewport(activeDropdownEle, event.target) && event.keyCode === 40) {
          activeDropdownEle.scrollIntoView(false);
        }
        if (!this.isElementInViewport(activeDropdownEle, event.target) && event.keyCode === 38) {
          activeDropdownEle.scrollIntoView(true);
        }
      }
    }
    }
    
    0 讨论(0)
  • 2021-01-25 04:07

    typeahead-scrollable.html file

    <input id="typeahead-scrollable" type="text" class="form-control" (keydown)="typeaheadKeydown($event)" #typeaheadInstance="ngbTypeahead" [(ngModel)]="model" [ngbTypeahead]="search" [resultFormatter]="formatter" 
    

    typeahead-scrollable.ts file

        @ViewChild('typeaheadInstance')
        private typeaheadInstance: NgbTypeahead;
    
        typeaheadKeydown($event: KeyboardEvent) {
          if (this.typeaheadInstance.isPopupOpen()) {
            setTimeout(() => {
              const popup = document.getElementById(this.typeaheadInstance.popupId);
              const activeElements = popup.getElementsByClassName('active');
              if (activeElements.length === 1) {
                // activeElements[0].scrollIntoView();
                const elem = (activeElements[0] as any);
                if (typeof elem.scrollIntoViewIfNeeded === 'function') {
                  // non standard function, but works (in chrome)...
                  elem.scrollIntoViewIfNeeded();
                } else {
                  //do custom scroll calculation or use jQuery Plugin or ...
                  this.scrollIntoViewIfNeededPolyfill(elem as HTMLElement);
                }
              }
            });
          }
        }
    
        private scrollIntoViewIfNeededPolyfill(elem: HTMLElement, centerIfNeeded = true) {
          var parent = elem.parentElement,
            parentComputedStyle = window.getComputedStyle(parent, null),
            parentBorderTopWidth = parseInt(parentComputedStyle.getPropertyValue('border-top-width')),
            parentBorderLeftWidth = parseInt(parentComputedStyle.getPropertyValue('border-left-width')),
            overTop = elem.offsetTop - parent.offsetTop < parent.scrollTop,
            overBottom = (elem.offsetTop - parent.offsetTop + elem.clientHeight - parentBorderTopWidth) > (parent.scrollTop + parent.clientHeight),
            overLeft = elem.offsetLeft - parent.offsetLeft < parent.scrollLeft,
            overRight = (elem.offsetLeft - parent.offsetLeft + elem.clientWidth - parentBorderLeftWidth) > (parent.scrollLeft + parent.clientWidth),
            alignWithTop = overTop && !overBottom;
    
          if ((overTop || overBottom) && centerIfNeeded) {
            parent.scrollTop = elem.offsetTop - parent.offsetTop - parent.clientHeight / 2 - parentBorderTopWidth + elem.clientHeight / 2;
          }
    
          if ((overLeft || overRight) && centerIfNeeded) {
            parent.scrollLeft = elem.offsetLeft - parent.offsetLeft - parent.clientWidth / 2 - parentBorderLeftWidth + elem.clientWidth / 2;
          }
    
          if ((overTop || overBottom || overLeft || overRight) && !centerIfNeeded) {
            elem.scrollIntoView(alignWithTop);
          }
        }
    

    Working example:

    https://stackblitz.com/edit/angular-utd9ii?file=app%2Ftypeahead-scrollable.ts

    0 讨论(0)
  • 2021-01-25 04:09

    Place the following code in your styles.css.

    We can place the following code in any of the following files

    • Style.css file
    • index.html style tag
    ngb-typeahead-window {
      max-height: 200px;
      overflow-y: auto;
      overflow-x: hidden;
    }
    

    Working code stackblitz link: https://stackblitz.com/edit/angular-qpzsfv

    0 讨论(0)
提交回复
热议问题