{"id":13808567,"url":"https://github.com/jwelker110/file-input-accessor","last_synced_at":"2025-07-30T19:33:58.911Z","repository":{"id":26401326,"uuid":"106945485","full_name":"jwelker110/file-input-accessor","owner":"jwelker110","description":"Angular directive that provides file input functionality in Angular forms.","archived":false,"fork":false,"pushed_at":"2025-01-24T17:16:14.000Z","size":4657,"stargazers_count":29,"open_issues_count":13,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-06-16T12:12:28.814Z","etag":null,"topics":["accessor","accessor-inputs","angular","angular-forms","angular4","angular5","angular6","control","file","form","input","reactive","template"],"latest_commit_sha":null,"homepage":"https://jwelker110.github.io/file-input-accessor/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jwelker110.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-10-14T16:50:31.000Z","updated_at":"2025-01-24T17:16:19.000Z","dependencies_parsed_at":"2025-04-09T21:19:25.940Z","dependency_job_id":"2526b53d-2277-4928-a1cb-b4cfbb81424c","html_url":"https://github.com/jwelker110/file-input-accessor","commit_stats":{"total_commits":63,"total_committers":2,"mean_commits":31.5,"dds":"0.015873015873015928","last_synced_commit":"980f167a6bb2f2fe73c0328f1354633e433ea013"},"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/jwelker110/file-input-accessor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwelker110%2Ffile-input-accessor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwelker110%2Ffile-input-accessor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwelker110%2Ffile-input-accessor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwelker110%2Ffile-input-accessor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jwelker110","download_url":"https://codeload.github.com/jwelker110/file-input-accessor/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jwelker110%2Ffile-input-accessor/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265727240,"owners_count":23818386,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["accessor","accessor-inputs","angular","angular-forms","angular4","angular5","angular6","control","file","form","input","reactive","template"],"created_at":"2024-08-04T01:01:46.369Z","updated_at":"2025-07-30T19:33:58.841Z","avatar_url":"https://github.com/jwelker110.png","language":"TypeScript","funding_links":[],"categories":["Third Party Components"],"sub_categories":["Form Controls"],"readme":"Looking for the [changelog](https://github.com/jwelker110/file-input-accessor/blob/master/CHANGELOG.md)?\n\n#### (Versions of this package \u003c 2.0.1) If you see an error about an unknown token `{` with some imports.\n\nThis isn't compatible with Angular Universal (Server side rendering) yet. I'll fix this in a future release. Until then, if you need to server-side render this package, please refer to the instructions [here](https://github.com/SebastianM/angular-google-maps/issues/1052#issuecomment-331150772). Summarized below:\n\n- npm i --save-dev babel-cli babel-preset-es2015\n- create a .babelrc file in the project's root directory with the following contents:\n    ```json \n    {\n        \"presets\": [\"es2015\"]\n    }\n    ```\n- Add a script to your package.json:\n    ```json\n    \"compile:file-input-accessor\": \"babel node_modules/file-input-accessor -d node_modules/file-input-accessor --presets es2015\"\n    ```\n- Add a postinstall script to your package.json scripts section:\n    ```json\n    \"postinstall\": \"compile:file-input-accessor\"\n    ```\n\n# FileInputAccessor\n\nAdds Reactive and Template behavior you're used to using with Angular Forms, but for `\u003cinput type=\"file\"\u003e`. Check out the [demo](https://jwelker110.github.io/file-input-accessor/) to see it in action. \n\nSample code for sending the files from Angular to your backend is [further down](#uploading-the-files) this page. \n\nProvides [NG_VALUE_ACCESSOR](https://angular.io/api/forms/NG_VALUE_ACCESSOR) implementing the [ControlValueAccessor](https://angular.io/api/forms/ControlValueAccessor)\ninterface. For more info, refer to [this stack overflow answer](https://stackoverflow.com/questions/41889384/angular2-validation-for-input-type-file-wont-trigger-when-changing-the-fi/41938495#41938495)\nlinked on [this issue](https://github.com/angular/angular/issues/7341).\n\n- [Which version should I use?](#which-version-should-i-use)\n- [Installation](#installation)\n- [Using in your form](#using-in-your-form)\n- [Validation](#validation)\n- [Accessor Inputs](#accessor-inputs)\n- [ICustomFile](#icustomfile)\n\n## Which version should I use?\n\n**Version 1.x.x uses [Rxjs](https://github.com/ReactiveX/rxjs/blob/master/CHANGELOG.md) v5.5.x.** Rxjs v6 underwent some changes that include adjustments to the way operators are imported along with other [breaking changes](https://github.com/ReactiveX/rxjs/blob/master/CHANGELOG.md#600-alpha1-2018-01-12). \n\n**Version 2.x.x uses Rxjs v6.** If you're interested in updating your projects, [a package](https://www.npmjs.com/package/rxjs-compat) has been created for that very purpose by the Rxjs team.\n\nAs a general rule:\n\n- For Angular 4 and 5, use version 1.x.x.\n- For Angular 6 use version 2.x.x.\n- Angular 7 and above aligns with the Angular version, so for Angular 7, use 7.x.x, Angular 8, use 8.x.x, etc..\n\n#### RxJS\n\nRxJS [docs](https://beta-rxjsdocs.firebaseapp.com/) (beta as of 2018/05/05). [Another](https://www.learnrxjs.io/learn-rxjs/operators) very helpful resource to familiarize yourself with Rxjs by providing a list of commonly used operators with examples.\n\n## Using with your forms\n\n1. Install package from npm \n   \n   ```npm i file-input-accessor```\n\n2. Import the FileInputAccessorModule.\n    \n   ```typescript\n    import {BrowserModule} from '@angular/platform-browser';\n    import {FileInputAccessorModule} from \"file-input-accessor\";\n\n    @NgModule({\n        declarations: [\n            AppComponent\n        ],\n        imports: [\n            BrowserModule,\n            FileInputAccessorModule\n        ],\n        providers: [],\n        bootstrap: [AppComponent]\n    })\n    export class AppModule {}\n   ```\n\n3. That's it. You can use FormControl and NgModel with your file input.\n\n   ```angular2html\n    \u003c!--file-upload.component.html--\u003e\n\n    \u003cform\u003e\n      \u003c!--Reactive form control--\u003e\n      \u003cinput type=\"file\" multiple [formControl]=\"fileControl\"\u003e\n    \u003c/form\u003e\n\n    \u003cform\u003e\n      \u003c!--Template form control, using model changes to trigger upload--\u003e\n      \u003cinput type=\"file\" multiple name=\"templateFileUploadControl\" [ngModel]=\"modelChangesFiles\" (ngModelChange)=\"onFileInputChange($event)\"\u003e\n    \u003c/form\u003e\n\n    \u003cform\u003e\n      \u003c!--Template form control, upload is manually triggered--\u003e\n      \u003cinput type=\"file\" multiple [(ngModel)]=\"manualChangesFiles\" name=\"templateFileUploadControl2\"\u003e\n      \u003cbutton type=\"button\" (click)=\"submitFiles()\"\u003eClick to upload\u003c/button\u003e\n    \u003c/form\u003e\n   ```\n\n## Uploading the files\n1. Import the [HttpClientModule](https://angular.io/api/common/http/HttpClientModule) if it isn't already.\n\n   ```typescript\n    @NgModule({\n        declarations: [\n            AppComponent,\n            FileUploadComponent\n        ],\n        imports: [\n            BrowserModule,\n            RouterModule.forRoot(ROUTES),\n            HttpClientModule,\n            FileInputAccessorModule\n        ],\n        providers: [],\n        bootstrap: [AppComponent]\n    })\n    export class AppModule {\n    }\n   ```\n\n2. When you're ready to upload your files, append them to your [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) and use [HttpClient](https://angular.io/api/common/http/HttpClient) to call your file upload endpoint.\n\n   ```typescript\n    @Component({\n        selector: 'app-file-upload',\n        templateUrl: './file-upload.component.html',\n        styleUrls: ['./file-upload.component.css']\n    })\n    export class FileUploadComponent implements OnInit {\n\n        fileControl = new FormControl();\n\n        modelChangesFiles: ICustomFile[] = [];\n        manualChangesFiles: ICustomFile[] = [];\n\n        constructor(private _http: HttpClient) {\n        }\n\n        /**\n         * Subscribe to the valueChanges Observable on the reactive FormControl.\n         */\n        ngOnInit() {\n            this.fileControl.valueChanges\n                .pipe(mergeMap(files =\u003e this.uploadFiles(files)))\n                .subscribe(() =\u003e this.fileControl.setValue([]));\n        }\n\n        /**\n         * (ngModelChange) event handler\n         *\n         * @param {ICustomFile[]} event\n         */\n        onFileInputChange(event: ICustomFile[]) {\n            this.uploadFiles(event)\n                .subscribe(() =\u003e (this.modelChangesFiles = []));\n        }\n\n        /**\n         * Upload button's (click) event handler\n         */\n        submitFiles() {\n            this.uploadFiles(this.manualChangesFiles)\n                .subscribe(() =\u003e (this.manualChangesFiles = []));\n        }\n\n        /**\n         * Appends the provided files to FormData and returns an Observable that will pass the FormData\n         * to the api when subscribed.\n         *\n         * @param {ICustomFile[]} files\n         * @returns {Observable\u003cObject\u003e}\n         */\n        private uploadFiles(files: ICustomFile[]): Observable\u003cObject\u003e {\n            if (!files || files.length === 0) {\n                return EMPTY;\n            }\n\n            const data = new FormData();\n\n            for (const file of files) {\n                data.append('file', file.slice(), file.name);\n            }\n            return this._http.post('/api/files', data);\n        }\n    }\n   ```\n\n## Validation\nAn async validator is included and only runs if sync validation passes and values are provided to the accessor inputs. The following errors may be set `true` on the control if at least one file fails validation:\n\n* fileSize - File size is too large.\n* fileType - File **type** failed to match.\n* fileExt - File **extension** failed to match.\n* The image validation requires `withMeta` set to `true`.\n    * imageWidth - Image does not meet width requirement.\n    * imageHeight - Image does not meet height requirement.\n    * (\u003e= 8.1.0) maxHeight - Image is too tall.\n    * (\u003e= 8.1.0) maxWidth - Image is too wide.\n    * (\u003e= 8.1.0) minHeight - Image is not tall enough.\n    * (\u003e= 8.1.0) minWidth - Image is not wide enough\n\n## Accessor Inputs\n\nAll inputs are optional.\n\n* `[allowedExt]` - Used to validate each file's **extension**. Accepts the following:\n    - A [RegExp](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp) instance.\n    - A String that will be used to create a new RegExp.\n    - An array of strings that will be joined into a single capture group and used to create a new RegExp.\n* `[allowedTypes]` - Accepts the same as allowedExt but will be used to validate the file's **type**.\n* `[size]` - Used to verify each file's size (bytes) is \u003c= the provided value.\n* `[withMeta]` - If `true`, each file will receive additional properties adhering to the ICustomFile interface. If you plan to validate maxHeight and maxWidth, `true` **is required**.\n* `[maxHeight]` - The largest acceptable height, in pixels, for image files.\n* `[maxWidth]` - The largest acceptable width, in pixels, for image files.\n* `[minHeight]` - The smallest acceptable height, in pixels, for image files.\n* `[minWidth]` - The smallest acceptable width, in pixels, for image files.\n\n## ICustomFile\n\nAn interface implemented by the Files added to the control. All properties are \noptional and only present if `withMeta` input is set to `true`.\n\n* If the file's **type** is image:\n    - `imgSrc` - Contains a data: URL representing the file data.\n    - `imgHeight` - The height of the image, in pixels.\n    - `imgWidth` - The width of the image, in pixels.\n    - `isImg` - `true`.\n* If the file's **type** is text:\n    - `textContent` - The text content of the file.\n* Each file contains an `errors` property that contains an errors\nobject. The following errors will be set `true` if the file has \nfailed that validation check.\n    - fileSize - File size is too large.\n    - fileType - File **type** failed to match.\n    - fileExt - File **extension** failed to match.\n    - imageWidth - Image does not meet width requirement.\n    - imageHeight - Image does not meet height requirement.\n    - (\u003e= 8.1.0) maxHeight - Image is too tall.\n    - (\u003e= 8.1.0) maxWidth - Image is too wide.\n    - (\u003e= 8.1.0) minHeight - Image is not tall enough.\n    - (\u003e= 8.1.0) minWidth - Image is not wide enough.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjwelker110%2Ffile-input-accessor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjwelker110%2Ffile-input-accessor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjwelker110%2Ffile-input-accessor/lists"}