title: ERROR TypeError: Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'. Angular 6
body: <p>PostCreateComponent.html:56 ERROR TypeError: Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'.</p>
  
  <pre><code>at PostsService.push../src/app/posts/posts.service.ts.PostsService.addPost (posts.service.ts:99)
  
  at PostCreateComponent.push../src/app/posts/post-create/post-create.component.ts.PostCreateComponent.onSavePost (post-create.component.ts:165)
  </code></pre>
  
  <p>it is so frustrating not knowing why the error is happening because on MDN, it clearly state, when you append a form data, the optional input is the file name,</p>
  
  <p>Source: MDN</p>
  
  <p>There are two versions of this method: a two and a three parameter version:</p>
  
  <p>formData.append(name, value);
  formData.append(name, value, filename);
  ParametersSection name. The name of the field whose data is contained in the value.The field's value. This can be a USVString or Blob (including subclasses such as File). The filename reported to the server (a USVString), when a Blob or File is passed as the second parameter. The default filename for Blob objects is "blob". The default filename for File objects is the file's filename.</p>
  
  <p>Please see code below focus on posts.service.ts line 99</p>
  
  <p>post.create.component.ts</p>
  
  <pre><code>import { Component, OnInit, OnDestroy } from '@angular/core';
  import { FormGroup, FormControl, Validators } from '@angular/forms';
  import { ActivatedRoute, ParamMap } from '@angular/router';
  import { Subscription } from 'rxjs';
  import { PostsService } from '../posts.service';
  import { Post } from '../post.model';
  import { mimeType } from './mime-type.validator';
  import { AuthService } from 'src/app/auth/auth.service';
  
  export interface CATEGORY {
    value: string;
    viewValue: string;
  }
  
  export interface DURATION {
    value: string;
    viewValue: string;
  }
  
  @Component({
    selector: 'app-post-create',
    templateUrl: './post-create.component.html',
    styleUrls: ['./post-create.component.css']
  })
  export class PostCreateComponent implements OnInit, OnDestroy {
    types: CATEGORY[] = [
      {value: 'Feature Film', viewValue: 'Feature Film'},
      {value: 'Short Film', viewValue: 'Short Film'},
      {value: 'TV Series', viewValue: 'TV Series'}
    ];
  
    contracts: DURATION[] = [
      {value: '3 Month', viewValue: '3 Month'},
      {value: '6 Month', viewValue: '6 Month'},
      {value: '9 Month', viewValue: '9 Month'},
      {value: '12 Month', viewValue: '12 Month'},
    ];
  
    enteredName = '';
    enteredContent = '';
    enteredGenre = '';
    enteredAuthor = '';
    enteredDuration = '';
    enteredYear = '';
    enteredCategory = '';
    enteredContractDuration = '';
    post: Post;
    isLoading = false;
    isLinear = false;
    form: FormGroup;
    imagePreview: string;
    private mode = 'create';
    private postId: string;
    private authStatusSub: Subscription;
  
    constructor(
      public postsService: PostsService,
      public route: ActivatedRoute,
      private authService: AuthService
    ) {}
  
    ngOnInit() {
      this.authStatusSub = this.authService
      .getAuthStatusListener()
      .subscribe(authStatus =&gt; {
        this.isLoading = false;
      });
      this.form = new FormGroup({
        name: new FormControl(null, {
          validators: [Validators.required, Validators.minLength(3)]
        }),
        content: new FormControl(null, { validators: [Validators.required] }),
        image: new FormControl(null, {
          validators: [Validators.required],
          asyncValidators: [mimeType]
        }),
        genre: new FormControl(null, {
          validators: [Validators.required, Validators.minLength(3)]
        }),
        author: new FormControl(null, {
          validators: [Validators.required, Validators.minLength(3)]
        }),
        duration: new FormControl(null, {
          validators: [Validators.required, Validators.minLength(3)]
        }),
        year: new FormControl(null, {
          validators: [Validators.required, Validators.minLength(3)]
        }),
        category: new FormControl(null, {
          validators: [Validators.required, Validators.minLength(3)]
        }),
        contractDuration: new FormControl(null, {
          validators: [Validators.required, Validators.minLength(3)]
        })
      });
      this.route.paramMap.subscribe((paramMap: ParamMap) =&gt; {
        if (paramMap.has('postId')) {
          this.mode = 'edit';
          this.postId = paramMap.get('postId');
          this.isLoading = true;
          this.postsService.getPost(this.postId).subscribe(postData =&gt; {
            this.isLoading = false;
            this.post = {
              id: postData._id,
              name: postData.name,
              genre: postData.genre,
              author: postData.author,
              duration: postData.duration,
              year: postData.year,
              category: postData.category,
              content: postData.content,
              imagePath: postData.imagePath,
              creator: postData.creator,
              adminApproval: postData.adminApproval,
              isApproved: postData.isApproved,
              createdAt: postData.createdAt,
              contractDuration: postData.contractDuration
            };
            this.form.setValue({
              name: this.post.name,
              content: this.post.content,
              image: this.post.imagePath,
              genre: this.post.genre,
              author: this.post.author,
              duration: this.post.duration,
              year: this.post.year,
              category: this.post.category,
              contractDuration: this.post.contractDuration
            });
          });
        } else {
          this.mode = 'create';
          this.postId = null;
        }
      });
    }
  
    onImagePicked(event: Event) {
      const file = (event.target as HTMLInputElement).files[0];
      this.form.patchValue({ image: file });
      this.form.get('image').updateValueAndValidity();
      const reader = new FileReader();
      reader.onload = () =&gt; {
        this.imagePreview = &lt;string&gt;reader.result;
      };
      reader.readAsDataURL(file);
    }
  
    onSavePost() {
      if (this.form.invalid) {
        return;
      }
      this.isLoading = true;
      if (this.mode === 'create') {
        console.log(this.form.value.name,
          this.form.value.content,
          this.form.value.image,
          this.form.value.genre,
          this.form.value.author,
          this.form.value.duration,
          this.form.value.year,
          this.form.value.category,
          this.form.value.contractDuration);
        this.postsService.addPost(
          this.form.value.name,
          this.form.value.content,
          this.form.value.image,
          this.form.value.genre,
          this.form.value.author,
          this.form.value.duration,
          this.form.value.year,
          this.form.value.category,
          this.form.value.contractDuration
        );
      } else {
        this.postsService.updatePost(
          this.postId,
          this.form.value.name,
          this.form.value.content,
          this.form.value.image,
          this.form.value.genre,
          this.form.value.author,
          this.form.value.duration,
          this.form.value.year,
          this.form.value.category,
          this.form.value.contractDuration
        );
      }
      this.form.reset();
    }
  
    ngOnDestroy() {
     this.authStatusSub.unsubscribe();
    }
  }
  </code></pre>
  
  <p>post.service.ts</p>
  
  <pre><code>import { Injectable } from '@angular/core';
  import { HttpClient } from '@angular/common/http';
  import { Subject } from 'rxjs';
  import { map } from 'rxjs/operators';
  import { Router } from '@angular/router';
  
  import { Post } from './post.model';
  
  @Injectable({ providedIn: 'root' })
  export class PostsService {
    private posts: Post[] = [];
    private postsUpdated = new Subject&lt;{ posts: Post[]; postCount: number }&gt;();
  
    constructor(private http: HttpClient, private router: Router) {}
  
    getPosts(postsPerPage: number, currentPage: number) {
      const queryParams = `?pagesize=${postsPerPage}&amp;page=${currentPage}`;
      this.http
        .get&lt;{ message: string; posts: any; maxPosts: number }&gt;(
          'http://localhost:3000/api/posts' + queryParams
        )
        .pipe(
          map(postData =&gt; {
            return {
              posts: postData.posts.map(post =&gt; {
                return {
                  name: post.name,
                  genre: post.genre,
                  author: post.author,
                  duration: post.duration,
                  year: post.year,
                  category: post.category,
                  content: post.content,
                  id: post._id,
                  imagePath: post.imagePath,
                  creator: post.creator,
                  adminApproval: post.adminApproval,
                  isApproved: post.isApproved,
                  createdAt: post.createdAt,
                  contractDuration: post.contractDuration
                };
              }),
              maxPosts: postData.maxPosts
            };
          })
        )
        .subscribe(transformedPostData =&gt; {
          console.log(transformedPostData);
          this.posts = transformedPostData.posts;
          this.postsUpdated.next({
            posts: [...this.posts],
            postCount: transformedPostData.maxPosts
          });
        });
    }
  
    getPostUpdateListener() {
      return this.postsUpdated.asObservable();
    }
  
    getPost(id: string) {
      return this.http.get&lt;{
        _id: string;
        name: string;
        genre: string;
        author: string;
        duration: string;
        year: string;
        category: string;
        content: string;
        imagePath: string;
        creator: string;
        adminApproval: boolean;
        isApproved: boolean;
        createdAt: Date;
        contractDuration: string;
      }&gt;('http://localhost:3000/api/posts/' + id);
    }
  
    addPost(
      name: string,
      genre: string,
      author: string,
      duration: string,
      year: string,
      category: string,
      content: string,
      contractDuration: string,
      image: File) {
      const postData = new FormData();
      postData.append('name', name);
      postData.append('genre', genre);
      postData.append('author', author);
      postData.append('duration', duration);
      postData.append('year', year);
      postData.append('category', category);
      postData.append('content', content);
      postData.append('contractDuration', contractDuration);
      postData.append('image', image, name);
      this.http
        .post&lt;{ message: string; post: Post }&gt;(
          'http://localhost:3000/api/posts',
          postData
        )
        .subscribe(responseData =&gt; {
          this.router.navigate(['/programs']);
        });
    }
  
    updatePost(
      id: string,
      name: string,
      genre: string,
      author: string,
      duration: string,
      year: string,
      category: string,
      content: string,
      contractDuration: string,
      image: File | string) {
      let postData: Post | FormData;
      if (typeof image === 'object') {
        postData = new FormData();
        postData.append('id', id);
        postData.append('name', name);
        postData.append('genre', genre);
        postData.append('author', author);
        postData.append('duration', duration);
        postData.append('year', year);
        postData.append('category', category);
        postData.append('contractDuration', contractDuration);
        postData.append('content', content);
        postData.append('image', image, name);
      } else {
        postData = {
          id: id,
          name: name,
          genre: genre,
          author: author,
          duration: duration,
          year: year,
          category: category,
          contractDuration: contractDuration,
          content: content,
          imagePath: image,
          creator: null,
          adminApproval: null,
          isApproved: null,
          createdAt: null
        };
      }
      this.http
        .put('http://localhost:3000/api/posts/' + id, postData)
        .subscribe(response =&gt; {
          this.router.navigate(['/programs']);
        });
    }
  
    deletePost(postId: string) {
      return this.http
        .delete('http://localhost:3000/api/posts/' + postId);
    }
  }
  
  </code></pre>
  
  <p>post-create.component.html</p>
  
  <pre><code>&lt;mat-card&gt;
    &lt;mat-spinner *ngIf="isLoading"&gt;&lt;/mat-spinner&gt;
    &lt;form [formGroup]="form"  (submit)="onSavePost()" *ngIf="!isLoading"&gt;
      &lt;label class="ui-label" for="form_name"&gt;Title&lt;/label&gt;
      &lt;mat-form-field&gt;
        &lt;input matInput type="text" formControlName="name" placeholder="Teza"&gt;
        &lt;mat-error *ngIf="form.get('name').invalid"&gt;Please enter the films name.&lt;/mat-error&gt;
      &lt;/mat-form-field&gt;
      &lt;label class="ui-label" for="form_vertical_preview"&gt;Horizontal poster&lt;/label&gt;
        &lt;div class="ui-caption"&gt;
          Recommended: PNG or JPG file @ 740x420 resolution.
        &lt;/div&gt;
        &lt;button mat-stroked-button type="button" (click)="filePicker.click()"&gt;Pick Image&lt;/button&gt;
      &lt;div class="image-picker"&gt;
        &lt;input type="file" #filePicker (change)="onImagePicked($event)"&gt;
      &lt;div class="image-preview" *ngIf="imagePreview !== '' &amp;&amp; imagePreview &amp;&amp; form.get('image').valid"&gt;
        &lt;img [src]="imagePreview" [alt]="form.value.name"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
      &lt;label class="ui-label" for="form_description"&gt;Description&lt;/label&gt;
      &lt;mat-form-field&gt;
        &lt;textarea matInput rows="4" formControlName="content" placeholder="Set in 1970s Ethiopia, Teza (Morning Dew) tells the story of a young Ethiopian as he returns from West Germany a postgraduate. Anberber comes back to a country at the height of the Cold War and under the Marxist regime of Mengistu Haile Mariam."&gt;&lt;/textarea&gt;
        &lt;mat-error *ngIf="form.get('content').invalid"&gt;Please enter a description.&lt;/mat-error&gt;
      &lt;/mat-form-field&gt;
      &lt;label class="ui-label" for="form_genre"&gt;Genre&lt;/label&gt;
      &lt;mat-form-field&gt;
        &lt;input matInput type="text" formControlName="genre" placeholder="Action, Adventure, Romance ...."&gt;
        &lt;mat-error *ngIf="form.get('genre').invalid"&gt;Please enter a program genre.&lt;/mat-error&gt;
      &lt;/mat-form-field&gt;
      &lt;label class="ui-label" for="form_author"&gt;Author&lt;/label&gt;
      &lt;mat-form-field&gt;
        &lt;input matInput type="text" formControlName="author" placeholder="Haile Gerima, Zeresenay ..."&gt;
        &lt;mat-error *ngIf="form.get('author').invalid"&gt;Please enter an author.&lt;/mat-error&gt;
      &lt;/mat-form-field&gt;
      &lt;label class="ui-label" for="form_duration"&gt;Duration&lt;/label&gt;
      &lt;mat-form-field&gt;
        &lt;input matInput type="text" formControlName="duration" placeholder="2h35m"&gt;
        &lt;mat-error *ngIf="form.get('duration').invalid"&gt;Please enter a duration.&lt;/mat-error&gt;
      &lt;/mat-form-field&gt;
      &lt;label class="ui-label" for="form_year"&gt;Year&lt;/label&gt;
      &lt;mat-form-field&gt;
        &lt;input matInput type="text" formControlName="year" placeholder="2019"&gt;
        &lt;mat-error *ngIf="form.get('year').invalid"&gt;Please enter a year.&lt;/mat-error&gt;
      &lt;/mat-form-field&gt;
      &lt;label class="ui-label" for="form_category"&gt;Category&lt;/label&gt;
      &lt;mat-form-field&gt;
          &lt;mat-select placeholder="shortfilm, feature film, tv series" formControlName="category"&gt;
              &lt;mat-option *ngFor="let type of types" [value]="type.value"&gt;
                {‌{type.viewValue}}
              &lt;/mat-option&gt;
          &lt;/mat-select&gt;
        &lt;input matInput type="text" formControlName="category" placeholder=""&gt;
        &lt;mat-error *ngIf="form.get('category').invalid"&gt;Please enter a category.&lt;/mat-error&gt;
      &lt;/mat-form-field&gt;
      &lt;mat-form-field&gt;
          &lt;mat-select placeholder="3 Months, 6 Months ..." formControlName="contractDuration"&gt;
              &lt;mat-option *ngFor="let contract of contracts" [value]="contract.value"&gt;
                {‌{contract.viewValue}}
              &lt;/mat-option&gt;
          &lt;/mat-select&gt;
        &lt;input matInput type="text" formControlName="contractDuration" placeholder=""&gt;
        &lt;mat-error *ngIf="form.get('contractDuration').invalid"&gt;Please enter a contract Duration.&lt;/mat-error&gt;
      &lt;/mat-form-field&gt;
      &lt;button mat-raised-button color="accent" type="submit"&gt;Save Post&lt;/button&gt;
      &lt;/form&gt;
  &lt;/mat-card&gt;
  
  </code></pre>