Uploading files in Angular 5 with additional properties of other objects

I am facing a challenge with uploading a file as part of a property to an object within a form. Most documentations I have come across only focus on services that handle standalone files. In my case, I have a form with various text inputs and date pickers, along with a file upload field. So, how can this scenario be handled effectively?

<mat-form-field>
    <input matInput placeholder="Start date" name="startdate">
    <mat-datepicker-toggle matSuffix [for]="SDpicker"></mat-datepicker-toggle>
    <mat-datepicker #SDpicker ngDefaultControl (selectedChanged)="onStartDateChange($event)"></mat-datepicker>
  </mat-form-field>
  <mat-form-field>
    <input matInput placeholder="End date" name="enddate">
    <mat-datepicker-toggle matSuffix [for]="EDpicker"></mat-datepicker-toggle>
    <mat-datepicker #EDpicker ></mat-datepicker>
  </mat-form-field>
  <mat-form-field>
    <input matInput placeholder="No. of days" name="noofdays">
  </mat-form-field>
  <label for="uploadAttachment" class="upload-file">
    <mat-icon>cloud_upload</mat-icon>
  </label>
  <input type="file" id="leaveapplication.attachment" class="hidden-input" (change)="onFileChange($event)" accept="image/jpeg, .jpeg, image/png, .png, image/pjpeg, .jpg, application/pdf" #fileInput>
  <button mat-button (click)="clearFile()">clear file</button>

Here is the service:

import { Http } from '@angular/http';
import { Injectable } from '@angular/core';
import 'rxjs/add/operator/map';
@Injectable()
export class LeaveapplicationService {

  constructor(private http: Http) { }
  getLeaveApplications() {
    return this.http.get('api/LeaveApplications/Get').map(res => res.json());
  }

  create(leaveapplication) {
    return this.http.post('/api/LeaveApplications', leaveapplication).map(res => res.json());
  }

}

The API being used is Core 2 Web API.

To handle the file in the component, a method like this can be implemented:

 onFileChange(event) {
    let reader = new FileReader();
    if (event.target.files && event.target.files.length > 0) {
      let file = event.target.files[0];
      reader.readAsDataURL(file);
      reader.onload = () => {
        this.form.get('leaveapplication.attachment').setValue({
          filename: file.name,
          filetype: file.type,
          value: reader.result.split(',')[1]
        })
      };
    }
  }

However, binding the attached file to the property of the leaveapplication obj in order to pass it through to the API as a whole remains a question.

Answer №1

To successfully upload a file using a multipart request, you will need to utilize formData.

public uploadFile(leaveApplication, file: File): Observable<any> {
    let formData: FormData = new FormData();
    formData.append('data', JSON.stringify(leaveApplication));
    formData.append('file', file, file.name);
    return this.http.post('/api/LeaveApplications', formData)
        .map(response => {return response.json()});
}

By using this approach, the attachment is no longer considered as an attribute of the 'leaveApplication' object.

If you still prefer to have the attachment as an attribute, you can explore encoding it in base64 format.

Answer №2

In order to utilize the API, you must upload the file as formData into your object. Here is an example of how to achieve this:

onFileSelection(event) {
    let reader = new FileReader();
    if (event.target.files && event.target.files.length > 0) {
      let selectedFile = event.target.files[0];
      const data= new Blob([selectedFile], { type: "application/text" });
      const formData = new FormData();
      formData.append("uploadedFile", jsonData);
      };
    }
  }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Running out of memory due to inefficient mark-compacting processes nearing the heap limit in Angular 8 allocation

A significant portion of the modules are built, with only one active in progress. The process is located at ...\src\index.js??extracted!D:\Clients\app\node_modules\sass-loader\lib\loader.js??ref--15-3!D:\src&bso ...

The navigation underline stays in place even after being clicked, and also appears below

Take a look at this js fiddle I've managed to create the underline effect on the navigation links when the user hovers over them. However, the underline only stays visible until the user clicks elsewhere on the screen. How can I make it persist as l ...

Are your custom guards failing to function properly now?

Previously, the code below was functioning properly until typescript 2.0: class Aluno{ escola: string; constructor(public nome: string){ this.escola = ""; } } class Pessoa{ morada: string; constructor(public nome: string){ this.morada = ...

Styling Angular 5 components without scoped styles

Currently, I am facing a dilemma with my Angular component that embeds a Microsoft PowerBI Report. The powerbi-client utilizes the nativeElement from an ElementRef to inject an iframe containing the report. My goal is to customize the styling of the border ...

Expanding the HTTP Get URL with a click in Ionic 2 and Angular 2

I recently performed a search for my ionic app, which fetches data from an api using a http get method as shown below static get parameters() { return [[Http]]; } searchRecipes(id) { var url = 'http://api.yummly.com/v1/api/recipes?_app_id=// ...

Tips on showcasing information with ng for in Ionic 2

https://i.sstatic.net/MKIcJ.jpgI am currently working on the thank you page for my project. When the success call is made, it will display both ORDER DETAILS and Delivery Details. However, in the event of a failure call, only the ORDER DETAILS are displaye ...

Every checkbox has been selected based on the @input value

My component has an @Input that I want to use to create an input and checkbox. import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; @Component({ selector: 'app-aside', templateUrl: './aside.component ...

What is the best way to separate a string using a comma as a delimiter and transform it into a string that resembles an array with individual string elements

I am in search of a way to transform a string, such as: "one, two, three, four" into a string like: "["one", "two", "three", "four"]" I have been attempting to devise a solution that addresses most scenarios, but so far, I have not been successful. The ap ...

Encountering an issue during the installation of Angular CLI

I am encountering an error while attempting to install angular/cli on my 64-bit Windows 10 machine. The specific error I am receiving is as follows: npm ERR! code ENOGIT npm ERR! Error while executing: npm ERR! undefined ls-remote -h -t ssh://<a href=" ...

Angular 4: Conditional CSS classes causing issues with transitions

After scouring through stackoverflow, I have yet to find a solution to my current issue. I am utilizing a conditional class on a div that is applied when a boolean variable becomes true. Below is the code snippet in question: <div [class.modalwindow-sh ...

Is it possible to eliminate a parameter when the generic type 'T' is equal to 'void'?

In the code snippet below, I am attempting to specify the type of the resolve callback. Initially: Generic Approach export interface PromiseHandler<T> { resolve: (result: T) => void // <----- My query is about this line reject: (error: a ...

Struggling to retrieve data with arrow function in Vue

I'm currently learning Vue and facing an issue with fetching data from an API to my component. I have a service class that successfully retrieves data from the API, as the API itself is working fine. Here's the code snippet: import IReview from & ...

Is there a way for me to access the names of the controls in my form directly from the .html file?

I have a list where I am storing the names of my form controls. In order to validate these form controls, I need to combine their names with my code in the HTML file. How can I achieve this? Below is my code: .ts file this.form = this.formBuilder.group({ ...

A Model in TypeScript

{ "title": { "de-DE": "German", "fr-FR": "French", "en-CA": "English" }, "image": "/tile.jpg", "url": "/url/to/version" } After receiving this JSON data, my model structure is as follows: export class MyModelStruct ...

Could an OpaqueToken be assigned using an observable?

I am attempting to establish an opaque token in the providers using an observable. The purpose behind this is that I am retrieving the value through the Http provider (from an external JSON file). This is my current approach: { provide: SOME_ ...

Angular EventEmitter fails to emit event

I am currently working with an Angular vertical stepper (using Angular Material) consisting of separate components for each step, with a parent component calling all these child components. My challenge is in passing data between the parent and child compo ...

Enhance your text in TextInput by incorporating newline characters with advanced editing features

I'm encountering an issue with my Textarea component that handles Markdown headers: type TextareaProps = { initValue: string; style?: StyleProp<TextStyle>; onChange?: (value: string) => void; }; type OnChangeFun = NativeSynthetic ...

Ways to include a link/href in HTML using a global constants file

I have a constants file with a links node that I need to integrate into my HTML or TypeScript file. Constants File export const GlobalConstants = { links: { classicAO: '../MicroUIs/' } } I created a public method called backToClassicAO ...

Is React Spring failing to trigger animations properly on iOS devices?

I have a code that functions perfectly on my desktop and across all browsers. Each button is designed to trigger a 4-second animation upon load or hover, initiating the playback of various videos. However, there's an issue with iOS where the video or ...

Is it feasible to utilize GraphQL subscriptions with Azure Functions?

Exploring the potential of implementing GraphQL subscriptions on Azure Functions. Unfortunately, it seems that apollo-server-azure-functions may not be compatible. Are there any other options or strategies to successfully enable this functionality? ...