---
title: Retrieve Uploaded Files for Preview Using File Names
product: Form Library
description: Learn how to upload files to a server, store their names in the survey results, and enable file previews. View a free demo for JavaScript to learn more.
framework: Angular
source: https://surveyjs.io/form-library/examples/store-file-names-in-survey-results/angular
index: https://surveyjs.io/form-library/examples/overview.md
---

# Retrieve Uploaded Files for Preview Using File Names (Angular)

When respondents attach a file to a survey, this file can be uploaded to a server or stored directly within a JSON object with survey results. The [File Upload](https://surveyjs.io/form-library/examples/file-upload/) demo describes both approaches and shows how to upload a file and store only its URL in survey results. However, if you store file identifiers different from URLs (for instance, file names), file previews are unavailable. This demo explains how to enable file previews when survey results store only file names.

> In this demo, files are uploaded to SurveyJS servers from where they are then deleted after a predefined period of time. We strongly encourage you to use your own servers for file uploads when you use SurveyJS to collect sensitive respondent data in your application.

## Upload Files to a Server

The steps to upload a file to a server are the same as for the File Upload demo, except that you should save file names instead of URLs on step 2:

1. Disable the [`storeDataAsText`](https://surveyjs.io/form-library/documentation/api-reference/file-model#storeDataAsText) property for the File Upload question.
2. Use `SurveyModel`'s [`onUploadFiles`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onUploadFiles) event to upload files and save file names in survey results.         
Within the event handler, call the `options.callback` function when file upload ends. Pass an array of successfully uploaded files as the first argument. As the second argument, you can pass an array of error messages if file upload failed.
3. Enable the File Upload question's [`waitForUpload`](https://surveyjs.io/form-library/documentation/api-reference/file-model#waitForUpload) property to ensure that users won't complete the survey until files are uploaded.

## Enable File Previews

When survey results store file names, a File Upload question cannot retrieve the files to display their previews. To enable the previews in this case, implement `SurveyModel`'s [`onDownloadFile`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onDownloadFile) event handler. Within this handler, you need to fetch the required file from the server, encode it to a Base64 string, and pass this string as the second argument to the `options.callback` method. This demo uses the <a href="https://developer.mozilla.org/ru/docs/Web/API/FileReader" target="_blank">FileReader API</a> to encode files.

## Remove Files from a Server

Users can click an individual file's Remove button to delete this file or click the Clear button to delete all uploaded files. Handle `SurveyModel`'s [`onClearFiles`](https://surveyjs.io/form-library/documentation/api-reference/survey-data-model#onClearFiles) event to delete the files from a server storage.

Within an `onClearFiles` event handler, you can identify the file to delete using the `options.fileName` parameter. Send a request to your server to delete the specified file. If `options.fileName` contains `null`, it means that the user has clicked the Clear button to delete all uploaded files. In this case, you should send a request to delete files listed in the `options.value` array.

Once you receive a response from the server, call the `options.callback` method. Pass `"success"` or `"error"` to indicate the operation status. As the second argument, you can pass deleted files' data (`options.value`) if file deletion was successful or an error message if file deletion failed.

## Files

### `src/app/components/json.ts`

```ts
export const json = {
  "elements": [
    {
      "type": "file",
      "title": "Please upload your photo",
      "name": "photo",
      "acceptedTypes": "image/*",
      "storeDataAsText": false,
      "waitForUpload": true,
      "maxSize": 512000
    }
  ]
};
```

### `src/app/components/survey.component.css`

```css
/* You can add your custom CSS here. */
```

### `src/app/components/survey.component.html`

```html
<survey [model]="model" style="position: absolute; top: 0; left: 0; right: 0; bottom: 0; height:100%"></survey>
```

### `src/app/components/survey.component.ts`

```ts
import { Component, OnInit } from "@angular/core";
import { Model } from "survey-core";
import { json } from "./json";
import "./survey.component.css";
import "survey-core/survey-core.min.css";

@Component({
    // tslint:disable-next-line:component-selector
    selector: "component-survey",
    templateUrl: "./survey.component.html",
    styleUrls: ["./survey.component.css"]
})
export class SurveyComponent implements OnInit {
    model: Model;
    ngOnInit() {
        const survey = new Model(json);
        survey.onUploadFiles.add((_, options) => {
            const formData = new FormData();
            options.files.forEach((file) => {
                formData.append(file.name, file);
            });
        
            fetch("https://api.surveyjs.io/private/Surveys/uploadTempFiles", {
                method: "POST",
                body: formData
            })
                .then((response) => response.json())
                .then((data) => {
                    options.callback(
                        options.files.map((file) => {
                            return {
                                file: file,
                                content: data[file.name]
                            };
                        })
                    );
                })
                .catch((error) => {
                    console.error("Error: ", error);
                    options.callback([], [ "An error occurred during file upload." ]);
                });
        });
        
        survey.onDownloadFile.add((_, options) => {
            fetch("https://api.surveyjs.io/private/Surveys/getTempFile?name=" + options.content)
                .then((response) => response.blob())
                .then((blob) => {
                    const file = new File([blob], options.fileValue.name, {
                        type: options.fileValue.type
                    });
                    const reader = new FileReader();
                    reader.onload = (e) => {
                        options.callback("success", e.target.result);
                    };
                    reader.readAsDataURL(file);
                })
                .catch((error) => {
                    console.error("Error: ", error);
                    options.callback("error");
                });
        });
        async function deleteFile(fileURL) {
            try {
                const apiUrl = `https://api.surveyjs.io/private/Surveys/deleteTempFile?name=${encodeURIComponent(fileURL)}`;
                const response = await fetch(apiUrl, { method: "DELETE" });
        
                if (response.status === 200) {
                    console.log(`File ${fileURL} was deleted successfully`);
                    return "success";
                } else {
                    console.error(`Failed to delete file: ${fileURL}`);
                    return "error";
                }
            } catch (error) {
                console.error("Error while deleting file: ", error);
                return "error";
            }
        }
        
        survey.onClearFiles.add(async (_, options) => {
            if (!options.value || options.value.length === 0) {
                return options.callback("success");
            }
        
            const filesToDelete = options.fileName
                ? options.value.filter((item) => item.name === options.fileName)
                : options.value;
        
            if (filesToDelete.length === 0) {
                console.error(`File with name ${options.fileName} is not found`);
                return options.callback("error");
            }
        
            const results = await Promise.all(
                filesToDelete.map((file) => deleteFile(file.content))
            );
        
            if (results.every((res) => res === "success")) {
                options.callback("success");
            } else {
                options.callback("error");
            }
        });
        survey.onComplete.add((sender, options) => {
            console.log(JSON.stringify(sender.data, null, 3));
        });
        this.model = survey;
    }
}
```

### `src/app/components/theme.ts`

```ts
export const themeJson = {};
```

### `src/app/app.component.css`

```css

```

### `src/app/app.component.html`

```html
<component-survey></component-survey>
```

### `src/app/app.component.ts`

```ts
import { Component } from "@angular/core";

@Component({
    selector: "app-root",
    templateUrl: "./app.component.html",
    styleUrls: ["./app.component.css"]
})
export class AppComponent {
    title = "CodeSandbox";
}
```

### `src/app/app.module.ts`

```ts
import { BrowserModule } from "@angular/platform-browser";
import { NgModule } from "@angular/core";

import { AppComponent } from "./app.component";
import { SurveyModule } from "survey-angular-ui";
import { SurveyComponent } from "./components/survey.component";

@NgModule({
    declarations: [AppComponent, SurveyComponent],
    imports: [BrowserModule, SurveyModule],
    providers: [],
    bootstrap: [AppComponent]
})
export class AppModule { }
```

### `src/environments/environment.prod.ts`

```ts
export const environment = {
    production: true
};
```

### `src/environments/environment.ts`

```ts
// The file contents for the current environment will overwrite these during build.
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
// The list of which env maps to which file can be found in `.angular-cli.json`.

export const environment = {
    production: false
};
```

### `src/index.html`

```html
<app-root></app-root>
```

### `src/main.ts`

```ts
import { enableProdMode } from "@angular/core";
import { platformBrowserDynamic } from "@angular/platform-browser-dynamic";

import { AppModule } from "./app/app.module";
import { environment } from "./environments/environment";

if (environment.production) {
    enableProdMode();
}

platformBrowserDynamic()
    .bootstrapModule(AppModule)
    .catch(err => console.log(err));
```

### `src/polyfills.ts`

```ts
/**
 * This file includes polyfills needed by Angular and is loaded before the app.
 * You can add your own extra polyfills to this file.
 *
 * This file is divided into 2 sections:
 *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
 *   2. Application imports. Files imported after ZoneJS that should be loaded before your main
 *      file.
 *
 * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
 * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
 * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
 *
 * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
 */

/***************************************************************************************************
 * BROWSER POLYFILLS
 */

/** IE9, IE10 and IE11 requires all of the following polyfills. **/
// import 'core-js/es6/symbol';
// import 'core-js/es6/object';
// import 'core-js/es6/function';
// import 'core-js/es6/parse-int';
// import 'core-js/es6/parse-float';
// import 'core-js/es6/number';
// import 'core-js/es6/math';
// import 'core-js/es6/string';
// import 'core-js/es6/date';
// import 'core-js/es6/array';
// import 'core-js/es6/regexp';
// import 'core-js/es6/map';
// import 'core-js/es6/weak-map';
// import 'core-js/es6/set';

/** IE10 and IE11 requires the following for NgClass support on SVG elements */
// import 'classlist.js';  // Run `npm install classlist.js`.

/** IE10 and IE11 requires the following for the Reflect API. */
// import 'core-js/es6/reflect';

/** Evergreen browsers require these. **/
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
import "core-js/proposals/reflect-metadata";

/**
 * Required to support Web Animations `@angular/platform-browser/animations`.
 * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
 **/
// import 'web-animations-js';  // Run `npm install web-animations-js`.

/***************************************************************************************************
 * Zone JS is required by default for Angular itself.
 */
import "zone.js/dist/zone"; // Included with Angular CLI.

/***************************************************************************************************
 * APPLICATION IMPORTS
 */
```

### `src/styles.css`

```css
/* You can add your custom CSS here. */
```

### `src/typings.d.ts`

```ts
/* SystemJS module definition */
declare var module: NodeModule;
interface NodeModule {
    id: string;
}
```

### `.angular-cli.json`

```json
{
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [ "assets", "favicon.ico" ],
      "index": "index.html",
      "main": "main.ts",
      "polyfills": "polyfills.ts",
      "prefix": "app",
      "styles": [ "styles.css" ],
      "scripts": [ ],
      "environmentSource": "environments/environment.ts",
      "environments": {
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
  ]
}
```

### `_tsconfig.json`

```json
{
  "compileOnSave": false,
  "compilerOptions": {
    "baseUrl": "./",
    "outDir": "./dist/out-tsc",
    "sourceMap": true,
    "declaration": false,
    "allowSyntheticDefaultImports": true,
    "downlevelIteration": true,
    "experimentalDecorators": true,
    "moduleResolution": "node",
    "importHelpers": true,
    "resolveJsonModule": true,
    "target": "es2015",
    "module": "es2020",
    "lib": [
      "es2018",
      "dom"
    ]
  }
}
```

### `package.json`

```json
{
  "name": "surveyjs-angular",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build --prod",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "14.1.1",
    "@angular/cdk": "14.1.1",
    "@angular/common": "14.1.1",
    "@angular/compiler": "14.1.1",
    "@angular/core": "14.1.1",
    "@angular/forms": "14.1.1",
    "@angular/platform-browser": "14.1.1",
    "@angular/platform-browser-dynamic": "14.1.1",
    "@angular/router": "14.1.1",
    "core-js": "3.6.4",
    "rxjs": "6.5.4",
    "survey-core": "latest",
    "survey-angular-ui": "latest",
    "tslib": "1.13.0",
    "zone.js": "0.11.7"
  },
  "devDependencies": {
    "@angular/cli": "1.6.6",
    "@angular/compiler-cli": "^5.2.0",
    "@angular/language-service": "^5.2.0",
    "@types/core-js": "0.9.46",
    "@types/jasmine": "~2.8.3",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "~6.0.60",
    "codelyzer": "^4.0.1",
    "jasmine-core": "~2.8.0",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~2.0.0",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.1.2",
    "ts-node": "~4.1.0",
    "tslint": "~5.9.1",
    "typescript": "3.9.7"
  },
  "keywords": [ "angular", "surveyjs" ],
  "description": "SurveyJS-Angular example project"
}
```

## Other Frameworks

- [React](https://surveyjs.io/form-library/examples/store-file-names-in-survey-results/reactjs.md)
- [Vue 3](https://surveyjs.io/form-library/examples/store-file-names-in-survey-results/vue3js.md)
- [jQuery](https://surveyjs.io/form-library/examples/store-file-names-in-survey-results/jquery.md)
- [Vanilla JS](https://surveyjs.io/form-library/examples/store-file-names-in-survey-results/vanillajs.md)
