1

I'm using multer to make an upload file system, everything works fine, the file is uploaded to the right folder which is src/assets/img/profile, but when I upload the file and refresh the page, the image doesn't display and I get a 404 error the file is not found in the browser console unless I run ng serve . What am I doing wrong ?

back end

function makeid() {
    var text = "";
    var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

    for (var i = 0; i < 5; i++)
    text += possible.charAt(Math.floor(Math.random() * possible.length));

    return text;
}

var storage = multer.diskStorage({
  destination: function (req, file, cb) {
    cb(null, './client/src/assets/img/profile');
  },
  filename: function (req, file, cb) {
    User.findOne({_id:req.decoded.userId},(err,user)=>{
        if(err){
            res.json({success:false,message:err});
        }
        else{
            if(!user){
                res.json({success:false,message:"User not found"});
            }
            else{
                cb(null, "profile" + user.username +makeid());
            }
        }

    });

  }
});
router.post('/edit-photo', upload,function (req,res){
        console.log(req.file);
      if (!req.file) {
        res.json({success:false,message:"No file was provided"});
      }
      else{
        User.findOne({_id:req.decoded.userId},(err,user)=>{
            if(err){
                res.json({success:false,message:'Something went wrong: '+err});
            }
            else{
                if (!user) {
                    res.json({success:false,message:'User not found'});
                }
                else{

                    user.img=req.file.filename;
                    user.save({ validateBeforeSave: false },(err)=>{
                        if(err){
                            res.json({success:false,message:'Something went wrong: '+err});
                        }
                        else{
                            res.json({success:true,file:req.file});
                        }
                    });
                }
            }
        });
      }
    });

For the front I send a XMLHttpRequest auth.service.ts

makeFileRequest(url: string,params: string[],files: File[]): Observable<any>{
    return Observable.create(observer => {
      let formData: FormData = new FormData();
      let xhr: XMLHttpRequest = new XMLHttpRequest();

      for(let i =0; i<files.length;i++){
        formData.append('file',files[i],files[i].name);
      }

      xhr.onreadystatechange = ()=>{
        if(xhr.readyState === 4){
          if(xhr.status===200){
            observer.next(JSON.parse(xhr.response));
            observer.complete();
          }
          else{
            observer.error(xhr.response);
          }
        }
      };

      xhr.upload.onprogress = (event)=>{
        this.progress = Math.round(event.loaded / event.total *100);

        this.progressObserver.next(this.progress);
      }
      xhr.open('POST',url,true);
      xhr.setRequestHeader('authorization',this.authToken);
      xhr.send(formData);
    });
  }

edit-profile.component.ts

upload(){
    this.authService.makeFileRequest('http://localhost:8080/authentication/edit-photo',[],this.filestoUpload).subscribe((data)=>{
      this.profilePic=data;
      window.location.reload();
    });
  }

  onFileChange(fileInput: any){
    this.filestoUpload=fileInput.srcElement.files;
  }

edit-profile.component.html

    <img  class="img-thumbnail img-responsive" [src]="profilePic" width="300px" height="300px">
  <label class="btn btn-default" for="file">Edit Photo</label>
  <input style="display: none;" id="file" type="file" name="file" (change)="onFileChange($event)">
<button (click)="upload()" class="btn btn-primary">Send</button>
Azoulay Jason
  • 2,787
  • 5
  • 21
  • 46
  • You just need to set the `url` of the image in the `` tag with some dummy (unique/not previously used) query parameter to make the browser reload the image. – Günter Zöchbauer Aug 30 '17 at 12:50

1 Answers1

1
<img class="img-thumbnail img-responsive" (src)="profilePic" width="300px" height="300px">

should be

<img class="img-thumbnail img-responsive" [src]="profilePic" width="300px" height="300px">

[] instead of ()

If you set profilePic

this.profilePic = this.profilePic + Date.now();

then the browser should reload the image. Ensure that you only upate profilePic after uploading the image is completed.

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
  • It still doesn't work, maybe i should provide my back/end code so you understand – Azoulay Jason Aug 30 '17 at 12:57
  • I don't think I need your backend code. Rather the Angular code you use to upload. You need to ensure you change `this.profilePic` only after the upload is completed. – Günter Zöchbauer Aug 30 '17 at 12:58
  • Ok, I understand, All my angular code to upload is here. I need to check the observable to see when the upload is completed right ? – Azoulay Jason Aug 30 '17 at 13:01
  • This should be where this code `console.log('sent');` is. Just ensure in your backend code that the request is only completed after the image became available for download. I can't help you with Node.js backend code. – Günter Zöchbauer Aug 30 '17 at 13:04
  • 1
    Ok thanks men, I'm gonna try. I'll probably come back to you if I have a problem .. – Azoulay Jason Aug 30 '17 at 13:05
  • I've tried like this `onChange(event){ var files=event.srcElement.files; this.authService.makeFileRequest('http://localhost:8080/authentication/edit-photo',[],files).subscribe((data)=>{ this.profilePic="../../../assets/img/profile"+data.file.filename; console.log(this.profilePic+'onChange'); }); }` And I get a GET error 404, meaning it doesn't fid the file despite that it's uploaded to the server. I've also changed the backend so it sends a response with the file. – Azoulay Jason Aug 30 '17 at 13:27
  • I'm not sure how I should be able to help you with that. If the file doesn't exist, then you either create the wrong path or the server is not serving the file where you expect. I have no knowledge about your directories. Have you checked how the path the browser tries to access and where the file actually is differ? – Günter Zöchbauer Aug 30 '17 at 13:33
  • The thing is that whenever I run `ng serve`, it finds the file.What I think is that, Angular doesn't recognize the file when browser refresh because it needs to be recompile so the actual file exists in Angular's "memory". Apparently it's not an usual issue since I've found nothing about this around the web. Maybe there"s a problem with my angular CLI ? – Azoulay Jason Aug 30 '17 at 13:39
  • Image files are not included into the Angular project, they are loaded from the server every time. The browser might cache the file, this is why I suggested to add `?someRandomNumber` to the filename, so that the browser thinks it's a different file and requests it from the server instead using the one it already has in the cache. `?...` is a query parameter and is probably just ignored on the server, therefore it's only effect should be to trick the browser. – Günter Zöchbauer Aug 30 '17 at 13:42
  • Ok so maybe the problem is there ? All my uploaded files are stored in the src>assets folder inside Angular. Is it better to store them outside Angular in a root folder with my server files ? – Azoulay Jason Aug 30 '17 at 13:46
  • I think "inside Angular" is not the right way to see it. Angular is stored on the server **with** the image files. The browser loads the Angular application, when the Angular application is executing it causes the browser to load other files from the directory Angular is in. It might still be a good idea to store the images in a different path, so you don't override them every time you build a new version of your Angular application. – Günter Zöchbauer Aug 30 '17 at 13:48
  • Ok i'm gonna try again this way because I've already tried but didn't work, the images didn't even display . Anyway thanks for your help Gunter – Azoulay Jason Aug 30 '17 at 13:51
  • 1
    You need to carefully check the URL the browser tries to load the images from, and the path where the images actually are stored and what the mismatch is. – Günter Zöchbauer Aug 30 '17 at 13:54
  • It still doesn't work ... According to this https://stackoverflow.com/a/42660412/7857994 Angular only points to src/assets folder. I've also checked the URLs and they're fine. – Azoulay Jason Aug 30 '17 at 14:15
  • As I understand this is only relevant for relative paths. For absolute paths Angular isn't involved, it's only between the browser and the server. If the server doesn't serve the image on the path you say is correct, there is nothing you can do from Angular. – Günter Zöchbauer Aug 30 '17 at 14:18
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/153262/discussion-between-azoulay-jason-and-gunter-zochbauer). – Azoulay Jason Aug 30 '17 at 14:21