I have a link for a that is supposed to open an file attachment but when I click on the link nothing happens. I'm calling called fetchdocument to get each document for viewing. When I inspect the link I don't see an actual url path just the file name. html <div *ngIf="!isLoadingDocuments && !tableDataSource?.data.length" class="text-center empty-card-height"> <p class="mb-0">No vendor documents on file</p> </div> <div [class.hidden]="isLoadingDocuments || !tableDataSource?.data.length"> <div *ngIf="tableDataSource?.data.length" class="card-header p-3"> <lf-material-search (updated)="tableDataSource.filter = $event;"></lf-material- search> </div> <div class="add-scroller table-responsive"> <mat-table [dataSource]="tableDataSource" matSort matSortActive="filename" matSortDirection="asc" matSortDisableClear="true" > <!-- filename --> <ng-container matColumnDef="name"> <mat-header-cell *matHeaderCellDef mat-sort-header>Filename</mat-header- cell> <mat-cell *matCellDef="let document"> <a (click)="fetchVendorDocument(document, true);"> {{document.name}} </a> </mat-cell> </ng-container> <!-- uploader --> <ng-container matColumnDef="uploader"> <mat-header-cell *matHeaderCellDef class="add-min-width">Uploader</mat- header-cell> <mat-cell *matCellDef="let document" class="add-min-width"> <span *ngIf="document.user.memberships && document.user.memberships.length > 0 && document.user.memberships[0].profile" >{{document.user.memberships[0].profile.givenNames}} {{document.user.memberships[0].profile.familyName}}</span> <span *ngIf="!document.user.memberships || document.user.memberships.length === 0 && document.user.profile"> {{document.user.profile.givenNames}} {{document.user.profile.familyName}}</span> </mat-cell> </ng-container> <!-- upload date --> <ng-container matColumnDef="createdAt"> <mat-header-cell class="add-min-width" *matHeaderCellDef mat-sort- header>Uploaded time </mat-header-cell> <mat-cell class="add-min-width" *matCellDef="let document"> {{document.createdAt | legfiDate:'MM/DD/YYYY h:mm a'}} </mat-cell> </ng-container> <!-- filesize --> <ng-container matColumnDef="filesize"> <mat-header-cell class="narrower" *matHeaderCellDef mat-sort-header>File size </mat-header-cell> <mat-cell class="narrower" *matCellDef="let document"> {{document.filesize | legfiFilesize}} </mat-cell> </ng-container> <!-- actions --> <ng-container matColumnDef="actions"> <mat-header-cell class="d-flex justify-content-end" *matHeaderCellDef> Actions </mat-header-cell> <mat-cell *matCellDef="let document" class="d-flex justify-content-end"> <div class="text-right"> <button class="btn btn-link" [matMenuTriggerFor]="columnsMenu" [attr.aria-label]="'actions'"> <i class="custom-more"></i> </button> <mat-menu #columnsMenu="matMenu" class="pb-0"> <ng-container *ngIf="document.model !== 'payable'"> <button mat-menu-item (click)="fetchVendorDocument(document)"> {{ 'Upload Document' }} </button> <button mat-menu-item *ngIf="hasWriteAccess" (click)="startDocumentRename(document);"> {{ 'Edit Document' }} </button> <button mat-menu-item *ngIf="hasWriteAccess" (click)="startDeleteVendorDocument(document);"> {{ 'Delete' }} </button> </ng-container> </mat-menu> </div> </mat-cell> </ng-container> <!-- template items --> <mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></mat- header-row> <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row> </mat-table> </div> </div> <div *ngIf="hasWriteAccess" class="card-footer text-right"> <button (click)="showDocumentUploaderDialog()" class="btn btn-outline-secondary"> <i class="fa fa-paperclip"></i> Upload document </button> </div> typescript @UntilDestroy() @Component({ selector: 'app-vendor-documents', templateUrl: './vendor-documents.component.html', }) export class VendorDocumentsComponent implements OnInit { vendorId: number = 0; vendor: Vendor; /** docs table **/ displayedColumns: string[] = [ 'name', 'createdAt', 'uploader', 'filesize', 'actions', ]; tableDataSource: MatTableDataSource<VendorDocument> = null; searchValue = ''; @ViewChild(MatSort) sort: MatSort; /** state */ jwt: JwtLegFiClaims; isLoadingDocuments: boolean = true; hasWriteAccess: boolean = false; hasReadAccess: boolean = false; constructor( private _billPayVendorService: VendorService, private _growler: GrowlerService, private _matDialogService: MatDialog, private _activatedRoute: ActivatedRoute, ) { } ngOnInit(): void { this.jwt = LegFiJwtService.read(); this.hasReadAccess = LegFiJwtService.doesUserHaveModulePermission( 'billpay', false, ); this.hasWriteAccess = LegFiJwtService.doesUserHaveModulePermission( 'billpay', true, ); this.vendorId = +extractRoute(this._activatedRoute, VendorDetailsComponent).snapshot.parent.params['id']; if (this.hasReadAccess) { this.getVendorInformation(); this.getVendorDocuments(); } else { this.isLoadingDocuments = false; } } getVendorInformation(): void { this.isLoadingDocuments = true; this._billPayVendorService .getOrgVendorDetails(null, this.vendorId) .pipe(untilDestroyed(this)) .subscribe( { next: (billPayVendor: Vendor) => { this.vendor = billPayVendor; this.isLoadingDocuments = false; }, error: () => { this._growler.oops( 'There was a problem loading this vendor.', ); }, }, ); } /** Prompt for confirmation before deleting vendor doc */ startDeleteVendorDocument(document: VendorDocument): void { this._matDialogService.open(ConfirmActionDialogComponent, { width: MatDialogSizes.SM, data: <ConfirmActionDialogInput>{ content: `Are you sure you want to delete this vendor document, ${document.name}?`, confirmButton: 'Yes, delete', }, }).afterClosed().subscribe((result: GenericDialogResult) => { if (result?.success) { this._deleteVendorDocument(document); } }); } /** Show modal for option to rename a vendor document */ startDocumentRename(document: VendorDocument): void { const data: ConfirmWithInputDialogInput = { title: 'Edit Document Name', btnContent: 'Rename', label: 'New Document Name', inputRequired: true, }; this._matDialogService.open(ConfirmWithInputDialogComponent, { width: MatDialogSizes.SM, data: data, }).afterClosed().subscribe((result: ConfirmWithInputDialogResult) => { if (result?.success) { this._billPayVendorService .renameOrgVendorDocument(null, document.vendorId, document.id, result?.value) .subscribe( () => { this._growler.success('Success', 'Document renamed successfully.'); this.getVendorDocuments(); }, () => { this._growler.oops('There was a problem updating your vendor\'s document.'); }, ); } }); } /** Get one vendor document for viewing */ fetchVendorDocument(document, inline = false): void { this._billPayVendorService .getOrgVendorDocumentLink( null, document.vendorId, document.id, inline, ) .pipe(untilDestroyed(this)) .subscribe((res: any) => { window.open(res.url); }); } /** Get list of vendor docs */ getVendorDocuments(): void { this.isLoadingDocuments = true; this._billPayVendorService .getOrgVendorDocuments(null, this.vendorId) .pipe(untilDestroyed(this)) .subscribe( { next: (vendorDocuments: VendorDocument[]) => { this.tableDataSource = new MatTableDataSource<VendorDocument>(vendorDocuments); this.tableDataSource.sort = this.sort; this.isLoadingDocuments = false; }, error: () => { this._growler.oops( 'There was a problem getting your vendor\'s document list.', ); }, }, ); } /** They clicked to upload files */ showDocumentUploaderDialog() { this._matDialogService.open(MultiDocumentUploaderDialogComponent, { width: MatDialogSizes.MD, data: <MultiDocumentUploaderDialogInput>{ type: 'vendor', vendor: this.vendor, }, }).afterClosed().subscribe( (result: GenericDialogResult) => { if (result?.success) { this.getVendorDocuments(); } }, ); } private _deleteVendorDocument(document: VendorDocument) { this._billPayVendorService .deleteOrgVendorDocument(null, document.vendorId, document.id) .subscribe( { next: () => { this._growler.success('Success', 'Vendor document deleted', ); this.getVendorDocuments(); }, error: () => { this._growler.oops('There was a problem deleting your vendor\'s document.', ); }, }, ); } } I'm trying to see if anyone has any ideas on what I need to fix this issue. I would appreciate any input on this. Continue reading...