Angular Material VirtualScrollViewPort - load data async












2















I find different samples for the VirtualScrollViewPort but with all I have the problem how to use them in real life. The samples load the whole data at once from the server - but since they are too large, I wanna load them individually. My main requirements are:




  1. Search mask - user enters some data

  2. Display progress bar...

  3. Query a Search on the server

  4. If no result is found ==> display a message

  5. If something is found ==> display the first n (=10) items

  6. After the user scrolls down and only e.g. 5 items are left ==> load additionally 10 items


    • continue with 5.

    • if only e.g. 3 are left ==> end the scrolling




I tried already the approach from Specifying data section - but there I fail how to recognize that no data is loaded AND I fail to initiate the view - especially when the user resets the content.



I tried as well with



<cdk-virtual-scroll-viewport itemSize="itemHeight" (scrolledIndexChange)="nextBatch($event,(resultList[resultList.length-1].total) )"
class="scroll-container">
<div *cdkVirtualFor="let search of resultList" class="card-item" >


which works for the first requirements but finally I fail with scrolledIndexChange is fired only on the very first item on the list. I have no clue how to track if user already is displaying already item 6 (which would load additional data). On the API page I do not see any @Output() beside the scrolledIndexChange.



Any hint how to track the events properly?



UPDATE
First problem I figured out was the incorrect syntax of setting the height, i.e. [itemSize]="itemHeight" is the appropriate syntax otherwise it remains always to zero ==> all elements are rendered!










share|improve this question





























    2















    I find different samples for the VirtualScrollViewPort but with all I have the problem how to use them in real life. The samples load the whole data at once from the server - but since they are too large, I wanna load them individually. My main requirements are:




    1. Search mask - user enters some data

    2. Display progress bar...

    3. Query a Search on the server

    4. If no result is found ==> display a message

    5. If something is found ==> display the first n (=10) items

    6. After the user scrolls down and only e.g. 5 items are left ==> load additionally 10 items


      • continue with 5.

      • if only e.g. 3 are left ==> end the scrolling




    I tried already the approach from Specifying data section - but there I fail how to recognize that no data is loaded AND I fail to initiate the view - especially when the user resets the content.



    I tried as well with



    <cdk-virtual-scroll-viewport itemSize="itemHeight" (scrolledIndexChange)="nextBatch($event,(resultList[resultList.length-1].total) )"
    class="scroll-container">
    <div *cdkVirtualFor="let search of resultList" class="card-item" >


    which works for the first requirements but finally I fail with scrolledIndexChange is fired only on the very first item on the list. I have no clue how to track if user already is displaying already item 6 (which would load additional data). On the API page I do not see any @Output() beside the scrolledIndexChange.



    Any hint how to track the events properly?



    UPDATE
    First problem I figured out was the incorrect syntax of setting the height, i.e. [itemSize]="itemHeight" is the appropriate syntax otherwise it remains always to zero ==> all elements are rendered!










    share|improve this question



























      2












      2








      2








      I find different samples for the VirtualScrollViewPort but with all I have the problem how to use them in real life. The samples load the whole data at once from the server - but since they are too large, I wanna load them individually. My main requirements are:




      1. Search mask - user enters some data

      2. Display progress bar...

      3. Query a Search on the server

      4. If no result is found ==> display a message

      5. If something is found ==> display the first n (=10) items

      6. After the user scrolls down and only e.g. 5 items are left ==> load additionally 10 items


        • continue with 5.

        • if only e.g. 3 are left ==> end the scrolling




      I tried already the approach from Specifying data section - but there I fail how to recognize that no data is loaded AND I fail to initiate the view - especially when the user resets the content.



      I tried as well with



      <cdk-virtual-scroll-viewport itemSize="itemHeight" (scrolledIndexChange)="nextBatch($event,(resultList[resultList.length-1].total) )"
      class="scroll-container">
      <div *cdkVirtualFor="let search of resultList" class="card-item" >


      which works for the first requirements but finally I fail with scrolledIndexChange is fired only on the very first item on the list. I have no clue how to track if user already is displaying already item 6 (which would load additional data). On the API page I do not see any @Output() beside the scrolledIndexChange.



      Any hint how to track the events properly?



      UPDATE
      First problem I figured out was the incorrect syntax of setting the height, i.e. [itemSize]="itemHeight" is the appropriate syntax otherwise it remains always to zero ==> all elements are rendered!










      share|improve this question
















      I find different samples for the VirtualScrollViewPort but with all I have the problem how to use them in real life. The samples load the whole data at once from the server - but since they are too large, I wanna load them individually. My main requirements are:




      1. Search mask - user enters some data

      2. Display progress bar...

      3. Query a Search on the server

      4. If no result is found ==> display a message

      5. If something is found ==> display the first n (=10) items

      6. After the user scrolls down and only e.g. 5 items are left ==> load additionally 10 items


        • continue with 5.

        • if only e.g. 3 are left ==> end the scrolling




      I tried already the approach from Specifying data section - but there I fail how to recognize that no data is loaded AND I fail to initiate the view - especially when the user resets the content.



      I tried as well with



      <cdk-virtual-scroll-viewport itemSize="itemHeight" (scrolledIndexChange)="nextBatch($event,(resultList[resultList.length-1].total) )"
      class="scroll-container">
      <div *cdkVirtualFor="let search of resultList" class="card-item" >


      which works for the first requirements but finally I fail with scrolledIndexChange is fired only on the very first item on the list. I have no clue how to track if user already is displaying already item 6 (which would load additional data). On the API page I do not see any @Output() beside the scrolledIndexChange.



      Any hint how to track the events properly?



      UPDATE
      First problem I figured out was the incorrect syntax of setting the height, i.e. [itemSize]="itemHeight" is the appropriate syntax otherwise it remains always to zero ==> all elements are rendered!







      angular angular-material angular7






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Jan 3 at 10:37







      LeO

















      asked Jan 2 at 16:28









      LeOLeO

      688932




      688932
























          1 Answer
          1






          active

          oldest

          votes


















          0














          After some work my final solution looks like:



          <ng-container *ngIf="lstSearchResults|async as resultList; else searching">
          <cdk-virtual-scroll-viewport [itemSize]="itemHeight" (scrolledIndexChange)="nextBatch()"
          class="scroll-container">
          <div *cdkVirtualFor="let search of resultList" class="card-item" >


          where it is noteworthy that my list is an async list, named lstSearchResults and in the the ts code I have:



            // for proper height and caching... (in pixels)
          itemHeight = 174;

          search(searchConfig:SearchOptions):void {
          ....
          this.lstSearchResults = new BehaviorSubject<SearchResult>(null);
          // call the REST service
          this.searchService.doSearch(searchConfig).subscribe(foundEntry => {
          if (!this.resultList) {
          // first list - nothing found up till now
          this.resultList = foundEntry;
          } else {
          if (!this.resultList[this.resultList.length - 1]) {
          //remove the marker (which was added below/previously)
          this.resultList.pop();
          }
          foundEntry.map(item => this.resultList.push(item));
          }
          if (this.resultList[0] && this.resultList[0].total > this.resultList.length + 1) {
          //some more elements could be fetched from the server ==> add a dummy entry for rendering
          this.resultList.push(undefined);
          }
          // notify the search list to be updated
          this.lstSearchResults.next(this.resultList);


          and for the scrolling I have the following code:



            nextBatch(): void {
          if (this.theEnd) {
          return;
          }

          if (this.resultList[0]) {
          // something was found
          if (this.viewport.getRenderedRange().end === this.viewport.getDataLength()) {
          // since we scrolled to the very end of the rendered display
          // ==> check if further search is required (and do so...)
          const searchTotal = this.resultList[0].total;
          this.mySearchConfig.posOffset += this.mySearchConfig.noOfElements;
          // some basic check if the total counter exceeds the current offset
          // i.e. no further search required
          if (this.mySearchConfig.posOffset <= searchTotal) {
          this.search(this.mySearchConfig, true);
          } else {
          this.theEnd = true;
          }
          }
          } else {
          // nothing found ==> mark the end
          this.theEnd = true;
          }
          }





          share|improve this answer
























            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            autoActivateHeartbeat: false,
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54009818%2fangular-material-virtualscrollviewport-load-data-async%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes









            0














            After some work my final solution looks like:



            <ng-container *ngIf="lstSearchResults|async as resultList; else searching">
            <cdk-virtual-scroll-viewport [itemSize]="itemHeight" (scrolledIndexChange)="nextBatch()"
            class="scroll-container">
            <div *cdkVirtualFor="let search of resultList" class="card-item" >


            where it is noteworthy that my list is an async list, named lstSearchResults and in the the ts code I have:



              // for proper height and caching... (in pixels)
            itemHeight = 174;

            search(searchConfig:SearchOptions):void {
            ....
            this.lstSearchResults = new BehaviorSubject<SearchResult>(null);
            // call the REST service
            this.searchService.doSearch(searchConfig).subscribe(foundEntry => {
            if (!this.resultList) {
            // first list - nothing found up till now
            this.resultList = foundEntry;
            } else {
            if (!this.resultList[this.resultList.length - 1]) {
            //remove the marker (which was added below/previously)
            this.resultList.pop();
            }
            foundEntry.map(item => this.resultList.push(item));
            }
            if (this.resultList[0] && this.resultList[0].total > this.resultList.length + 1) {
            //some more elements could be fetched from the server ==> add a dummy entry for rendering
            this.resultList.push(undefined);
            }
            // notify the search list to be updated
            this.lstSearchResults.next(this.resultList);


            and for the scrolling I have the following code:



              nextBatch(): void {
            if (this.theEnd) {
            return;
            }

            if (this.resultList[0]) {
            // something was found
            if (this.viewport.getRenderedRange().end === this.viewport.getDataLength()) {
            // since we scrolled to the very end of the rendered display
            // ==> check if further search is required (and do so...)
            const searchTotal = this.resultList[0].total;
            this.mySearchConfig.posOffset += this.mySearchConfig.noOfElements;
            // some basic check if the total counter exceeds the current offset
            // i.e. no further search required
            if (this.mySearchConfig.posOffset <= searchTotal) {
            this.search(this.mySearchConfig, true);
            } else {
            this.theEnd = true;
            }
            }
            } else {
            // nothing found ==> mark the end
            this.theEnd = true;
            }
            }





            share|improve this answer




























              0














              After some work my final solution looks like:



              <ng-container *ngIf="lstSearchResults|async as resultList; else searching">
              <cdk-virtual-scroll-viewport [itemSize]="itemHeight" (scrolledIndexChange)="nextBatch()"
              class="scroll-container">
              <div *cdkVirtualFor="let search of resultList" class="card-item" >


              where it is noteworthy that my list is an async list, named lstSearchResults and in the the ts code I have:



                // for proper height and caching... (in pixels)
              itemHeight = 174;

              search(searchConfig:SearchOptions):void {
              ....
              this.lstSearchResults = new BehaviorSubject<SearchResult>(null);
              // call the REST service
              this.searchService.doSearch(searchConfig).subscribe(foundEntry => {
              if (!this.resultList) {
              // first list - nothing found up till now
              this.resultList = foundEntry;
              } else {
              if (!this.resultList[this.resultList.length - 1]) {
              //remove the marker (which was added below/previously)
              this.resultList.pop();
              }
              foundEntry.map(item => this.resultList.push(item));
              }
              if (this.resultList[0] && this.resultList[0].total > this.resultList.length + 1) {
              //some more elements could be fetched from the server ==> add a dummy entry for rendering
              this.resultList.push(undefined);
              }
              // notify the search list to be updated
              this.lstSearchResults.next(this.resultList);


              and for the scrolling I have the following code:



                nextBatch(): void {
              if (this.theEnd) {
              return;
              }

              if (this.resultList[0]) {
              // something was found
              if (this.viewport.getRenderedRange().end === this.viewport.getDataLength()) {
              // since we scrolled to the very end of the rendered display
              // ==> check if further search is required (and do so...)
              const searchTotal = this.resultList[0].total;
              this.mySearchConfig.posOffset += this.mySearchConfig.noOfElements;
              // some basic check if the total counter exceeds the current offset
              // i.e. no further search required
              if (this.mySearchConfig.posOffset <= searchTotal) {
              this.search(this.mySearchConfig, true);
              } else {
              this.theEnd = true;
              }
              }
              } else {
              // nothing found ==> mark the end
              this.theEnd = true;
              }
              }





              share|improve this answer


























                0












                0








                0







                After some work my final solution looks like:



                <ng-container *ngIf="lstSearchResults|async as resultList; else searching">
                <cdk-virtual-scroll-viewport [itemSize]="itemHeight" (scrolledIndexChange)="nextBatch()"
                class="scroll-container">
                <div *cdkVirtualFor="let search of resultList" class="card-item" >


                where it is noteworthy that my list is an async list, named lstSearchResults and in the the ts code I have:



                  // for proper height and caching... (in pixels)
                itemHeight = 174;

                search(searchConfig:SearchOptions):void {
                ....
                this.lstSearchResults = new BehaviorSubject<SearchResult>(null);
                // call the REST service
                this.searchService.doSearch(searchConfig).subscribe(foundEntry => {
                if (!this.resultList) {
                // first list - nothing found up till now
                this.resultList = foundEntry;
                } else {
                if (!this.resultList[this.resultList.length - 1]) {
                //remove the marker (which was added below/previously)
                this.resultList.pop();
                }
                foundEntry.map(item => this.resultList.push(item));
                }
                if (this.resultList[0] && this.resultList[0].total > this.resultList.length + 1) {
                //some more elements could be fetched from the server ==> add a dummy entry for rendering
                this.resultList.push(undefined);
                }
                // notify the search list to be updated
                this.lstSearchResults.next(this.resultList);


                and for the scrolling I have the following code:



                  nextBatch(): void {
                if (this.theEnd) {
                return;
                }

                if (this.resultList[0]) {
                // something was found
                if (this.viewport.getRenderedRange().end === this.viewport.getDataLength()) {
                // since we scrolled to the very end of the rendered display
                // ==> check if further search is required (and do so...)
                const searchTotal = this.resultList[0].total;
                this.mySearchConfig.posOffset += this.mySearchConfig.noOfElements;
                // some basic check if the total counter exceeds the current offset
                // i.e. no further search required
                if (this.mySearchConfig.posOffset <= searchTotal) {
                this.search(this.mySearchConfig, true);
                } else {
                this.theEnd = true;
                }
                }
                } else {
                // nothing found ==> mark the end
                this.theEnd = true;
                }
                }





                share|improve this answer













                After some work my final solution looks like:



                <ng-container *ngIf="lstSearchResults|async as resultList; else searching">
                <cdk-virtual-scroll-viewport [itemSize]="itemHeight" (scrolledIndexChange)="nextBatch()"
                class="scroll-container">
                <div *cdkVirtualFor="let search of resultList" class="card-item" >


                where it is noteworthy that my list is an async list, named lstSearchResults and in the the ts code I have:



                  // for proper height and caching... (in pixels)
                itemHeight = 174;

                search(searchConfig:SearchOptions):void {
                ....
                this.lstSearchResults = new BehaviorSubject<SearchResult>(null);
                // call the REST service
                this.searchService.doSearch(searchConfig).subscribe(foundEntry => {
                if (!this.resultList) {
                // first list - nothing found up till now
                this.resultList = foundEntry;
                } else {
                if (!this.resultList[this.resultList.length - 1]) {
                //remove the marker (which was added below/previously)
                this.resultList.pop();
                }
                foundEntry.map(item => this.resultList.push(item));
                }
                if (this.resultList[0] && this.resultList[0].total > this.resultList.length + 1) {
                //some more elements could be fetched from the server ==> add a dummy entry for rendering
                this.resultList.push(undefined);
                }
                // notify the search list to be updated
                this.lstSearchResults.next(this.resultList);


                and for the scrolling I have the following code:



                  nextBatch(): void {
                if (this.theEnd) {
                return;
                }

                if (this.resultList[0]) {
                // something was found
                if (this.viewport.getRenderedRange().end === this.viewport.getDataLength()) {
                // since we scrolled to the very end of the rendered display
                // ==> check if further search is required (and do so...)
                const searchTotal = this.resultList[0].total;
                this.mySearchConfig.posOffset += this.mySearchConfig.noOfElements;
                // some basic check if the total counter exceeds the current offset
                // i.e. no further search required
                if (this.mySearchConfig.posOffset <= searchTotal) {
                this.search(this.mySearchConfig, true);
                } else {
                this.theEnd = true;
                }
                }
                } else {
                // nothing found ==> mark the end
                this.theEnd = true;
                }
                }






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Jan 8 at 7:41









                LeOLeO

                688932




                688932
































                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54009818%2fangular-material-virtualscrollviewport-load-data-async%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    MongoDB - Not Authorized To Execute Command

                    How to fix TextFormField cause rebuild widget in Flutter

                    in spring boot 2.1 many test slices are not allowed anymore due to multiple @BootstrapWith