Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
227 views
in Technique[技术] by (71.8m points)

javascript - How to Add(Upload) and Edit(Update) Image File in Firebase Storage using Ionic and Angular Frameworks with the help of Reactive Forms?

I have application that can add a new organization. User can interact using Reactive forms and fill the following requirements (Organization Name, Description, and Image).

Application can add the following inputs (Name and Description) but unfortunately Images cant be add in the database.

The adding of images is possible with Firebase Cloud Functions but unfortunately the functions is not free so I will focus on Firebase Storage instead.

I try this following function but failed:

  1. In organization.service.ts, I grouped the Image File with Text using FormData and passed it as a request in the Firebase Storage and this error exists. This is the error

organization.service.ts

  //For Adding Organization to Firebase
  addOrg(name: string, description: string, imageUrl: string){
    let generatedId: string;

    const newOrg = new Organization(
      Math.random().toString(),
      name,
      description,
      imageUrl,
      'adm'
    );
    
    return this.http
    .post<{name: string}>('https://db-student-portal-default-rtdb.firebaseio.com/add-organization.json', {...newOrg, id: null})
    .pipe(
      switchMap(resData => {
        generatedId = resData.name;
        return this.allOrg;
      }),
      take(1),
      tap(org => {
        newOrg.id = generatedId;
        this.organization.next(org.concat(newOrg));
      })
    );
  }

  //For Uploading the Image
  uploadImage(image: File){
    const uploadData = new FormData();
    uploadData.append('image', image);

    //This is where I want to upload the image. This is Firebase Storage
    return this.http.post<{imageUrl: string, imagePath: string}>(
      'db-student-portal.appspot.com/', 
       uploadData);
  }

new-org.page.ts - this is the page where the user can add organization or data

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { LoadingController } from '@ionic/angular';
import { switchMap } from 'rxjs/operators';

import { OrganizationService } from '../../organization/organization.service';

//Conversion in base64
function base64toBlob(base64Data, contentType) {
  contentType = contentType || '';
  const sliceSize = 1024;
  const byteCharacters = atob(base64Data);
  const bytesLength = byteCharacters.length;
  const slicesCount = Math.ceil(bytesLength / sliceSize);
  const byteArrays = new Array(slicesCount);

  for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
    const begin = sliceIndex * sliceSize;
    const end = Math.min(begin + sliceSize, bytesLength);

    const bytes = new Array(end - begin);
    for (let offset = begin, i = 0; offset < end; ++i, ++offset) {
      bytes[i] = byteCharacters[offset].charCodeAt(0);
    }
    byteArrays[sliceIndex] = new Uint8Array(bytes);
  }
  return new Blob(byteArrays, { type: contentType });
}

@Component({
  selector: 'app-new-org',
  templateUrl: './new-org.page.html',
  styleUrls: ['./new-org.page.scss'],
})
export class NewOrgPage implements OnInit {
  formGroup: FormGroup;

  constructor(private orgService: OrganizationService,
              private router: Router,
              private loadingCtrl: LoadingController) { }

  ngOnInit() {
    this.formGroup = new FormGroup({
      orgName: new FormControl(null, {
        updateOn: 'change',
        validators: [Validators.required]
      }),
      orgDesc: new FormControl(null, {
        updateOn: 'change',
        validators: [Validators.required]
      }),
      imageOrg: new FormControl(null)
    });
  }

  //Adding of Organization in FrontEnd view
  onAddOrg(){
    if (!this.formGroup.valid || !this.formGroup.value.imageOrg) {
      return;
    }
    this.loadingCtrl.create({
      message: 'Creating Organization: ' + this.formGroup.value.orgName,
      spinner: 'circular'
    }).then(loadingEl => {
      loadingEl.present();
      this.orgService.uploadImage(this.formGroup.value.imageOrg)
      .pipe(switchMap(uploadRes => {
        return this.orgService.addOrg(
          this.formGroup.value.orgName, 
          this.formGroup.value.orgDesc, 
          uploadRes.imageUrl);
      }))
      .subscribe(() => {
        loadingEl.dismiss();
        this.formGroup.reset();
        this.router.navigateByUrl('/homepage');
      });
    });

  }

  //Converting of String to File
  onImagePicked(imageData: string | File){
    let imageFile;
    if (typeof imageData === 'string') {
      try {
        imageFile = base64toBlob(imageData.replace('data:image/jpeg;base64,', ''), 'image/jpeg');
      } catch (error) {
        console.log(error);
        return;
      }
    } else {
      imageFile = imageData;
    }
    this.formGroup.patchValue({ imageOrg: imageFile });
  }
}

image-picker.component.ts - component that handles the image from local machine

import { Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { Plugins, Capacitor, CameraSource, CameraResultType } from "@capacitor/core";
import { Platform } from '@ionic/angular';

@Component({
  selector: 'app-image-picker',
  templateUrl: './image-picker.component.html',
  styleUrls: ['./image-picker.component.scss'],
})
export class ImagePickerComponent implements OnInit {
  @ViewChild('filePicker') filePickerRef: ElementRef<HTMLInputElement>;
  @Output() imagePick = new EventEmitter<string | File>();
  @Input() showPreview = false;
  selectedImage: string;
  usePicker = false;

  constructor(private platform: Platform) { }

  ngOnInit() {
    console.log('Mobile: ' + this.platform.is('mobile'));
    console.log('Desktop: ' + this.platform.is('desktop'));
    console.log('Hybrid: ' + this.platform.is('hybrid'));
    console.log('Android: ' + this.platform.is('android'));
    console.log('iOS: ' + this.platform.is('ios'));

    if ((this.platform.is('mobile') && !this.platform.is('hybrid')) || this.platform.is('desktop')) {
      this.usePicker = true;
    }
  }

 //Opens File Manager in local machine
  onPickImage(){
    if (!Capacitor.isPluginAvailable('Camera') || this.usePicker) {
      this.filePickerRef.nativeElement.click();
      return;
    }

    Plugins.Camera.getPhoto({
      quality: 50,
      source: CameraSource.Prompt,
      correctOrientation: true,
      height: 320,
      width: 300,
      resultType: CameraResultType.DataUrl
    }).then(image => {
      this.selectedImage = image.dataUrl;
      this.imagePick.emit(image.dataUrl);
    }).catch(error => {
      console.log(error);
      if (this.usePicker) {
        this.filePickerRef.nativeElement.click();
      }
      return false;
    });
  }
  

  //preview of image in the UI
  onFileChosen(event: Event){
    const pickedFile = (event.target as HTMLInputElement).files[0];

    if (!pickedFile) {
      return;
    }

    const fr = new FileReader();
    fr.onload = () => {
      const dataUrl = fr.result.toString();
      this.selectedImage = dataUrl;
      this.imagePick.emit(pickedFile);
    };
    fr.readAsDataURL(pickedFile);
  }

}

My Dependencies

  "dependencies": {
    "@angular/common": "~10.0.0",
    "@angular/core": "~10.0.0",
    "@angular/forms": "~10.0.0",
    "@angular/platform-browser": "~10.0.0",
    "@angular/platform-browser-dynamic": "~10.0.0",
    "@angular/router": "~10.0.0",
    "@capacitor/android": "^2.4.5",
    "@capacitor/core": "2.4.5",
    "@ionic-native/core": "^5.0.0",
    "@ionic-native/splash-screen": "^5.0.0",
    "@ionic-native/status-bar": "^5.0.0",
    "@ionic/angular": "^5.0.0",
    "@ionic/pwa-elements": "^3.0.2",
    "rxjs": "~6.5.5",
    "tslib": "^2.0.0",
    "zone.js": "~0.10.3"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.1000.0",
    "@angular/cli": "~10.0.5",
    "@angular/compiler": "~10.0.0",
    "@angular/compiler-cli": "~10.0.0",
    "@angular/language-service": "~10.0.0",
    "@capacitor/cli": "2.4.5",
    "@ionic/angular-toolkit": "^2.3.0",
    "@types/jasmine": "~3.5.0",
    "@types/jasminewd2": "~2.0.3",
    "@types/node": "^12.11.1",
    "codelyzer": "^6.0.0",
    "jasmine-core": "~3.5.0",
    "jasmine-spec-reporter": "~5.0.0",
    "karma": "~5.0.0",
    "karma-chrome-launcher": "~3.1.0",
    "karma-coverage-istanbul-reporter": "~3.0.2",
    "karma-jasmine": "~3.3.0",
    "karma-jasmine-html-reporter": "^1.5.0",
    "protractor": "~7.0.0",
    "ts-node": "~8.3.0",
    "tslint": "~6.1.0",
    "typescript": "~3.9.5"
}


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
等待大神答复

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...