简体   繁体   中英

angular get image data and again append it to FormData

In angular 5 I am getting the images for hotelgallery from mongodb through my service. So basically the data what I am getting is like this

{
  fieldname: "hotelgallery", 
  originalname: "e.jpg", 
  encoding: "7bit", 
  mimetype: "image/jpeg", 
  destination: "./public/",
  encoding : "7bit",
  filename : "1521139307413.jpg"
  mimetype : "image/jpeg"
  path : "public/1521139307413.jpg"
  size : 66474
}
{
  fieldname: "hotelgallery", 
  originalname: "e.jpg", 
  encoding: "7bit", 
  mimetype: "image/jpeg", 
  destination: "./public/",
  encoding : "7bit",
  filename : "1521139307413.jpg"
  mimetype : "image/jpeg"
  path : "public/1521139307413.jpg"
  size : 66474
}
{
  fieldname: "hotelgallery", 
  originalname: "j.jpg", 
  encoding: "7bit", 
  mimetype: "image/jpeg", 
  destination: "./public/",
  encoding : "7bit",
  filename : "1526753678390.jpg"
  mimetype : "image/jpeg"
  path : "public/1526753678390.jpg"
  size : 66470
}
{
  fieldname: "hotelgallery", 
  originalname: "k.jpg", 
  encoding: "7bit", 
  mimetype: "image/jpeg", 
  destination: "./public/",
  encoding : "7bit",
  filename : "7865456789413.jpg"
  mimetype : "image/jpeg"
  path : "public/7865456789413.jpg"
  size : 66300
}

Now I want to again append those data to FormData but its not working.

The code what I have done so far

export class HotelEditComponent implements OnInit {
   formData = new FormData();
   ngOnInit() {
    this.getOneHotel(this.route.snapshot.params['id']);
   }

 getOneHotel(id) {
    this.http.get( this.apiUrl + '/api/hotel/' + id).subscribe(data => {
      this.hotel = data;
      this.appendImages(data['hotelimages']); //Here I am getting the data as mentioned here
    });
 }

 public appendImages(imagedata) {
    for (var i = 0; i < imagedata.length; i++) {
      console.log(imagedata[i]);
      this.formData.append('hotelgallery', imagedata[i], imagedata[i]['originalname']);
    }
    console.log(this.formData);
  }
 }

So can someone tell me how can I append the existing image data to FormData? Any help and suggestions will be really appreciable.

UseCase for this: Actually I had used formData to upload images in angular. Now in the edit page the images are showing fine. But lets say a user edits some data and upload some images or remove some images. In that case I am getting the images from the database and again trying to upload them with formdata.

I have used this module and multer for nodejs to upload images with formData.

So can someone tell me how can I append the existing image data to FormData? Any help and suggestions will be really appreciable.

Actually, this approach need more add script solution. for example

1. Get Image Blob from server

Since you return detail object of images, not with the blob. You need have a endpoint to return as blob. (or if return as data buffer then it transform to blob you can use BlobUtil )

2. Put Blob to append form data

You need use blob to append in param 2 no a path, see documentation .

name

The name of the field whose data is contained in value.

value

The field's value. This can be a USVString or Blob (including subclasses such as File).

filename Optional

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.

That what you need, but that is bad practice .

Let's say, you have 30 images to edit, then you need request blob endpoint to get those images blob to appends. But user only want to update 1 image, wasting time to request image blob, right?

For edit image usually we don't need append to file form ( <input type="file" /> ).

Just show it as thumbnail to see what image uploaded and let file form empty.

What we do usually, thumbnail that image.

When user what to change, user put new image and replace old image with new want and update database.

if not, do nothing for image. ( YAGNI )

FormData's append is silently failing here. You need to attach the 'image' as a blob. See the MDN docs .

formData.append('hotelgallery', new Blob([imagedata[i]], { type: "text/xml"}), imagedata[i]['originalname']);

Also, just printing formData won't show anything, instead try:

console.log(this.formData.getAll('hotelgallery'));

or

for (var value of this.formData.values()) {
   console.log(value);
}

But lets say a user edits some data and upload some images or remove some images. In that case I am getting the images from the database and again trying to upload them with formdata.

So, you can pass object to universal method and on result get formData . Object data even can contain nested objects.

 static createFormData(object: Object, form?: FormData, namespace?: string): FormData {
        const formData = form || new FormData();
        for (let property in object) {

            if (!object.hasOwnProperty(property) || object[property] === undefined) {
                continue;
            }

            const formKey = namespace ? `${namespace}[${property}]` : property;

            if (object[property] instanceof Date) {                 
                formData.append(formKey, object[property].toISOString());
            } else if (typeof object[property] === 'object' && !(object[property] instanceof File)) {
                this.createFormData(object[property], formData, formKey);
            }
            else if (typeof object[property] === 'number') {
                let numberStr = object[property].toString().replace('.', ',');
                formData.append(formKey, numberStr);
            }
            else {
                formData.append(formKey, object[property]);
            }
        }

        return formData;
    }
}

In Component class:

export class HotelEditComponent implements OnInit {
   formData = new FormData();
   hotel: any;
   ...
   ngOnInit() {
    this.getOneHotel(this.route.snapshot.params['id']);
   }

 getOneHotel(id) {
    this.http.get( this.apiUrl + '/api/hotel/' + id).subscribe(data => {
      this.hotel = data;
    });
 }

 postToServer() {
  // or even can pass full `this.hotel` object
  // this.helperService.createFormData(this.hotel) 
  this.formData = this.helperService.createFormData(this.hotel['hotelimages']) 
  this.service.post(this.formData);

 }
...
}

It looks like you are trying to append a JSON array, since formData.append can only accept a string or blob, try the JSON.stringify() method to convert your array into a JSON string. (untested)

eg I think you can replace

this.appendImages(data['hotelimages']);

with

this.formData.append('hotelgallery', JSON.stringify(data['hotelimages']));

This is more of a design issue right now, rather then a tech problem. You are asking about posting FormData again and you want to fetch the images data again for that.

Now let's look at your current design.

  1. User uploads 3 images of 4MB size each
  2. On your edit page you downloads each of these images. Cost=12MB
  3. On the edit page user deletes 2 images and adds 2 images. Cost=12MB
  4. So final cost of updating 2 images of 8MB is 24MB. Which is a lot

Now before figuring out how to do FormData, figure out the right design for your app.

Consider the OLX site which allows you to post ads and later edit them. When you edit and remove a image, they call a API for removing the image

删除图片

The ideal design in my opinion would be below

  • Submit all images in your create
  • For edit create a add and remove endpoint for the image

Submitting text data again on a edit form is ok, but submitting the same images data again on a edit form is never ok. Reconsider your design

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM