Topic: Accordion not opening firstItem after API call

Declan Ward priority asked 1 year ago


Expected behavior

First item opens

Actual behavior

Does not open after data retrieved from API call.However, if test data loaded locally, the first item does open.

I suspect a timing issue or am I missing something simple? Why would one work and not the other?

Any help appreciated.

Resources (screenshots, code snippets etc.)

enter image description here

ngOnInit() {
    // Load data locally
    this.addDocTypes();

    // Load data from API
    this.refreshDocuments();
}

ngAfterViewInit(){
    this.firstItem.show();   

     // Needed this to prevent error
     this.cdr.detectChanges();
}

Loading data locally:

  addDocTypes(){
    this.localDocTypes.push({ DocumentCount:2, Description: 'Payslip', NumberNotViewed:0, 
      Documents:[
        {
          DocCreated:  '2020-02-10T10:11:27',
          DocFileName: 'Payslip-Period__5.pdf',
          DocId: '2864453',
          DocLength: '45883',
          DocTypeDescr:  'Payslip',
          DocURL:  'https://someserver.com/docserver.ashx?file=00028644535',
          DocViewed:  '11/9/2023 7:55:47 PM'
        },
        {
          DocCreated:  '2019-07-17T10:17:35',
          DocFileName: 'Payslip-Period__6.pdf',
          DocId: '2516617',
          DocLength: '45883',
          DocTypeDescr:  'Payslip',
          DocURL:  'https://someserver.com/docserver.ashx?file=00025166170',
          DocViewed:  '3/8/2021 5:29:52 PM'
        }
      ]
    });

    this.localDocTypes.push({ DocumentCount: 2, Description: 'P60', NumberNotViewed: 0, 
      Documents:[
        {
          DocCreated:  '2020-03-27T12:43:54',
          DocFileName: 'P60-2016.pdf',
          DocId: '2965144',
          DocLength: '126317',
          DocTypeDescr:  'P60',
          DocURL:  'https://someserver.com/docserver.ashx?file=00029651',
          DocViewed:  '11/10/2023 2:58:00 PM'
        },
        {
          DocCreated:  '2019-04-05T10:06:22',
          DocFileName: 'P60-2017.pdf',
          DocId: '2323834',
          DocLength: '126317',
          DocTypeDescr:  'P60',
          DocURL:  'https://someserver.com/docserver.ashx?file=00023238301',
          DocViewed:  '11/9/2023 3:18:46 PM'
        }
      ]
    });
  }

Loading data from API

this.docGuestService.getUserDocuments()
  .subscribe( 
    {
      next: (response) => {

        // Normally set docTypes directly from API
        this.docTypes = response;


        // Trying to build object with data from API
        // Just in case something is different!
        // this.docTypes = [];

        // response.forEach(element => {

        // // Clear list of UserDocuments first  
        // this.userDocuments = [];

        // // Add documents
        // element.Documents.forEach(doc =>{

        //   this.userDocuments.push({
        //     DocCreated:  doc.DocCreated,
        //     DocFileName: doc.DocFileName,
        //     DocId: doc.DocId,
        //     DocLength: doc.DocLength,
        //     DocTypeDescr:  doc.DocTypeDescr,
        //     DocURL:  doc.DocURL,
        //     DocViewed:  doc.DocViewed
        //   })

        // })
        //   // Add complete item & documents
        //   this.docTypes.push({ 
        //     DocumentCount: element.DocumentCount, 
        //     Description: element.Description, 
        //     NumberNotViewed: element.NumberNotViewed, 
        //     Documents: this.userDocuments                
        //   });
        // });

      },
      error:(e) => {
        this.IsError = true;
                  this.alertService.error(e.error, {
          autoClose: false,
          keepAfterRouteChange: false
        });

      },
      complete: () =>{
        this.loading = false;  

      }
    }

Service to get data:

  getUserDocuments(): Observable<DocumentType[]> {
    return this.http.get<DocumentType[]>(this._urlBase + 'DocViewer/g');
  }

Interface

    DocumentType interface

    export interface DocumentType{

    // Description of the current document type
    Description: string;

    // Number of documents for the document type (description)
    DocumentCount: number;

    // Number of documents NotViewed for the document type (description)
    NumberNotViewed: number;

    // User Documents for the above document Type (Description)
    Documents: BaseDocument[];
}

HTML - identical for each accordion except

API data

*ngFor="let docType of docTypes"

Locally loaded data

    *ngFor="let docType of localDocTypes"

Defined

      // Interfaces
  // From API
  docTypes: DocumentType[] = [];
  userDocuments: UserDocument[] = [];

  // Generated locally
  localDocTypes:DocumentType[] = [];

Actual HTML

   <mdb-accordion 
  [flush]="true" 
  [multiple]="false">
  <mdb-accordion-item  
    [collapsed]="true" 
    *ngFor="let docType of localDocTypes"

    #firstItem

    >
    <ng-template mdbAccordionItemHeader>
      <div> 
        <fa-icon class="icon" [icon]="faFilePdf"></fa-icon>
          {{docType.Description}}
          {{docType.DocumentCount}} ({{docType.NumberNotViewed}}) 
      </div>
    </ng-template>

    <ng-template mdbAccordionItemBody>

      <div class="datatable">

        <table
          class="table datatable-table "
          mdbTable
          #table="mdbTable"
          [dataSource]="docType.Documents"
          striped="true"
          sm="true">
          <thead class="datatable-header">
            <tr>
              <div class="row">                    
                <div class="col">File Name</div>
                <div class="col" style="text-align:right;">Size</div>
                <div class="col" style="text-align:right;">Date</div>
              </div>

            </tr>
          </thead>

          <tbody class="datatable-body">
            <tr *ngFor="let doc of table.data" scope="row"  >
              <td>
                <a  href="{{doc.DocURL}}" download >
                  <div class="row">

                    <div class="col">
                        <span class="viewed" *ngIf="doc.DocViewed !=''">Viewed</span>
                        <span class="notviewed" *ngIf="doc.DocViewed ===''">Not Viewed</span>
                    </div>   

                    <div class="col" style="text-align:right;">
                      {{doc.DocLength}}
                    </div>

                    <div class="col" style="text-align:right;">      
                        {{ doc.DocCreated | date:'dd MMM yyyy' }}
                    </div>                          

                  </div>

                  <div class="row">
                    <div class="col wraptext">{{doc.DocFileName}}</div>
                  </div>
                </a>
              </td>
            </tr>
          </tbody> 
        </table>

      </div>        

    </ng-template>
  </mdb-accordion-item>
</mdb-accordion>

Rafał Seifert free answered 1 year ago


You are rendering accordion items through *ngFor directive. At the beginning there is no data so items will not render. Therefore you will not be able to open them in ngAfterViewInit(), you should also see an error in console that items are not defined. To fix this issue I would suggest to add opening logic in callback function where you receive data from API call. It would look like this in your example. You should also wrap it in setTimeout as the items won't be rendered immediately after updating local data.

this.docGuestService.getUserDocuments()
  .subscribe( 
    {
      next: (response) => {

        // Normally set docTypes directly from API
        this.docTypes = response;
        setTimeout(() => {
        this.firstItem.show();
        }, 0);

Declan Ward priority commented 1 year ago

Hi Rafal,

Yes you are correct, there was an error stating firstItem undefined.

Your solution above is perfect, thank you.

Regards, Declan



Please insert min. 20 characters.

FREE CONSULTATION

Hire our experts to build a dedicated project. We'll analyze your business requirements, for free.

Status

Resolved

Specification of the issue

  • ForumUser: Priority
  • Premium support: Yes
  • Technology: MDB Angular
  • MDB Version: MDB5 5.1.0
  • Device: All
  • Browser: All
  • OS: Windows
  • Provided sample code: No
  • Provided link: No