9.3 KiB
File Upload Component
The file upload component in /src/app/shared/file-upload allows for files to be uploaded to Azure Blob Storage for a given loan. Once the loan is created in ACTion it will upload the files to ACTion and show up in Attachments. An example of the component shown here:
Enabling Employment Income/Other Income file uploads for a loan
Set showProofOfIncomeUploadForm value for the loan to true in src\app\shared\loan-type.ts
Adding the upload component to a form (see end of document for an example implementation)
- Update interface by adding two variables:
filesandisUploading, example insrc\app\loan-wizard\field-groups\personal\personal-information.ts - Add new values to form group in
src\app\loan-wizard\field-groups\common-groups.ts, seePERSONAL_INFOin this file for an example - Add the HTML to the form, example below and in
src\app\loan-wizard\field-groups\personal\personal-info-form.component.html - Update TS by adding variables needed, example below and in
src\app\loan-wizard\field-groups\personal\personal-info-form.component.ts - Update
src\assets\i18n\en.jsonto have verbiage for uploading document - Update
src\app\shared\loan-type.tsto setbeforeYouBeginKeyvalue on a given loan to the corresponding key inen.jsonto enable the checklist - Update the summary component to show files if they're present, example in
src\app\loan-wizard\wizards\common\summary\personal-summary.component.html
Inputs
loanIdrequired- The CosmosDB loan ID that uploaded files will be associated with
sectionoptional- The section that the form is in, e.g. Collateral.
- If left blank, the description in ACTion will not include this.
sectionIdrequired- The sectionId is used to be more specific, when there are multiple upload components in a single form.
- An example would be the Income section that shows up to 3 upload components for any borrower on the loan, for which the
sectionIdis set toPrimary Borrower-#, where#would be which income section it is associated with, 1, 2, or 3.
descriptionrequired- Description that is used to set the attachment type in ACTion
- This text will be displayed in the component after "Upload"
- This text can be overridden by passing a value in for the
labelinput
labeloptional- This text will be displayed in the component after "Upload"
- This was added in after the verbiage requirements needed something more custom in certain areas to show something like
Upload a copy of first mortgage balance statementinstead ofUpload Copy of first mortgage balance statement. - If
labelis not provided,descriptionwill be shown.
removeAllFilesSubjectoptional- This input is used by passing in a
Subject<boolean>and then triggered by calling the.next()function on the subject, which will remove all files and emit when completed. - It is meant to be used along with the
removedAllFilesoutput to notify the parent component that the files have been removed and the form can be updated.
- This input is used by passing in a
Outputs
sendFilesrequired- Used to capture when files change and need to be updated on the parent component.
uploadingFilesrequired- Used for form validation so that the Next button cannot be pressed while a file is being uploaded or deleted.
removedAllFilesoptional- Used when a form is closed/not needed and the files that were uploaded need to be deleted.
- Once
removedAllFilesSubjectis called and completed, this output is emitted so that the form can be updated as needed.
Notes
- When the component loads, it creates two requests for the API: one for the files associated with the
loanIdand the other for the settings, which controls the file size and types. - The
<lw-file-upload>component should be surround with adivthat controls the width and visibility, e.g.:
<div *ngIf="showUploadForm" class="form-group col-lg-5 col-md-6 col-sm-12">
ACTion
Files that are uploaded into ACTion will be given a type: Attachment, Proof of Income, or Title. This is done by using the description input and mapping it to a type on the backend API defined in appsettings.json. If a description is mistyped or not found in appsettings.json, it will default to Attachment.
The description within action is created with the inputs: section, sectionId, and description.
If section is null or blank, it is not used as shown in the code and screenshot below.
// Code segment from LoanWizardAPI/CRIF.ACTion/Files/AddAppFilesSection.cs
$"{file.Section} - {file.SectionId}: {file.Description}"
$"{file.SectionId}: {file.Description}"
Example Implementation
HTML
<div *ngIf="showUploadForm" class="form-group col-lg-5 col-md-6 col-sm-12">
<lw-file-upload
[loanId]="loanId"
section=""
sectionId="Personal Information"
description="Proof of being a student"
label="proof that you are a student"
[removeAllFilesSubject]="removeAllFilesSubject"
(sendFiles)="handleFiles($event)"
(uploadingFiles)="handleUploadingFiles($event)"
(removedAllFiles)="handleRemovedAllFiles($event)">
</lw-file-upload>
</div>
TypeScript
@Input()
public group: FormGroup;
public loanId: string;
public showUploadForm: boolean;
public removeAllFilesSubject: Subject<boolean>;
constructor(private collateralInfoService: CollateralInfoFormService) {
this.loanId = collateralInfoService.getLoanId(); // not real, just an example
this.showUploadForm = true;
this.removeAllFilesSubject = new Subject<boolean>();
}
// Somewhat of a contrived example, but essentially when the form is supposed to be deleted, the .next() should be called.
// Once files are removed, the removedAllFiles output of the component will emit and call the function to complete removing the form handleRemovedAllFiles (below)
public closeForm() {
this.removeAllFilesSubject.next();
}
// Sets the files value of the group, called when component is initialized and when all files have been removed.
public handleFiles(files: any[]): void {
this.group.patchValue({ 'files': files });
}
// Sets a boolean to true/false for form validation so that Next is disabled
public handleUploadingFiles(isUploading: boolean): void {
this.group.patchValue({ 'isUploading': isUploading });
}
public handleRemovedAllFiles(removedAllFiles: boolean): void {
if(removedAllFiles) {
// Code to clear/delete form here...
}
}
Interface
This is the interface that the files variable should be added to. If it is in the Personal Info section, it would be added to src\app\loan-wizard\field-groups\personal\personal-information.ts
{
...
// not all variables shown
files?: any[];
isUploading?: boolean;
...
}
src\app\loan-wizard\field-groups\common-groups.ts
This file is where the form group for the page is generated. It will also need to have both variables added to the correct section so they can be used with the validators.
{
...
// not all variables shown
{
field: 'files',
validation: [WizardValidators.FileValidator]
},
{
field: 'isUploading',
validation: [WizardValidators.MustBeFalse]
}
...
}
src\assets\i18n\en.json
{
...
// not all variables shown
"BEFOREYOUBEGIN": {
"EXAMPLE": {
"INTRO": "Before you begin the process, you should have the following documents:",
"HEADINGS": [
{
"HEADING": "Documents to Upload",
"VALUES": [
"Proof of income (i.e. most recent payroll check stub, 1040s for self-employed borrowers, bank statement).",
"Proof that you are a student (i.e. Student ID from current school year or current enrollment documentation such as a class schedule)."
]
}
]
},
...
}
}
src\app\shared\loan-type.ts
Add needed keys for checklist component, coming from en.json (see above)
{
...
// not all variables shown
beforeYouBeginKey: 'BEFOREYOUBEGIN.EXAMPLE', // Should be added/updated whenever the upload form is added
showProofOfIncomeUploadForm: true // Set to true if the proof of income file uploads should show, be sure to update en.json!
...
}
Summary component
Add divs to display files. The description can be pulled from the first file, as shown (it is done with income files as there are multiple sections and borrowers), or the description can be hard coded. The files array is passed into the uploadedFiles pipe which parses them into a comma-separated list. The pipe is located at src\app\shared\pipes\uploaded-files.pipe.ts
<div class="row summary-card" *ngIf="personalInformation">
<!-- full code of component not shown -->
<div *ngIf="personalInformation?.files?.length > 0" class="col-md-4 col-sm-12 summary-card-field-title">{{personalInformation.files[0].description}} document(s)</div>
<div *ngIf="personalInformation?.files?.length > 0" class="col-md-8 col-sm-12">{{personalInformation.files | uploadedFiles}}</div>
</div>

