Hi Currently I am having a angular 5 GUI and a spring boot application. I am having an angular component for displaying an image . However the image is not getting displayed.

avatar.component.html

<div class="avatar-circle" [style.background-image]="avatarBgImageStyle" [ngClass]="avatarClasses">
  <fa-icon *ngIf="!user?.avatar" icon="user"></fa-icon>
</div>
<div class="labels" *ngIf="user && (showFullName || showAccount || showAuthority)">
  <div *ngIf="showFullName" class="full-name">{{ fullName }}</div>
  <div *ngIf="showAccount && user.account" class="secondary-text">{{ user.account.name }}</div>
  <div *ngIf="showAuthority && user.authorities && user.authorities.length" class="secondary-text">{{ 'USER_ROLES.' + authority | translate }}</div>
</div>

avatar.component.ts

import { Component, Input, HostBinding } from '@angular/core';

import { User } from '../../models';
import { getUserFullName } from '../../utils';
import { FilesService } from '../../services';

@Component({
  selector: 'pc-avatar',
  templateUrl: './avatar.component.html',
  styleUrls: ['./avatar.component.scss']
})
export class AvatarComponent {
  @Input() user: User;
  @Input() showFullName = false;
  @Input() showAccount = false;
  @Input() showAuthority = false;
  @Input() bgColor = 'secondary';
  @Input() textColor = 'brand-secondary';

  @HostBinding('class')
  @Input()
  size: 'md' | 'lg' | 'xl' = 'md';

  get fullName() {
    return getUserFullName(this.user);
  }

  get authority() {
    return this.user.authorities[0];
  }

  get avatarBgImageStyle(): string {
    if (!this.user || !this.user.avatar) {
      return 'none';
    }

    const url = this.filesService.getFileUrl(this.user.avatar);
    return `url(${url})`;
  }

  get avatarClasses(): string[] {
    return [`bg-${this.bgColor}`, `text-${this.textColor}`];
  }

  constructor(private filesService: FilesService) {}
}

in the avatar.component.html you can see i am setting [style.background-image]="avatarBgImageStyle" it calls the method avatarBgImageStyle() in the avatar.component.ts and returns a string ( for example http://localhost:8080/api/files/file-id . my spring boot application has a resource method that can serve the file request. this resource is secured.

/**
 * REST controller for managing File.
 */
@RestController
@RequestMapping("/api")
public class FileResource {
 @GetMapping("/files/{id}")
    @Timed
    @Secured({AuthoritiesConstants.GLOBAL_ADMIN, AuthoritiesConstants.ACCOUNT_ADMIN, AuthoritiesConstants.CAMPAIGN_MANAGER, AuthoritiesConstants.TEAM_MEMBER})
    public ResponseEntity<Resource> getFile(@PathVariable UUID id) {
        log.debug("REST request to get File : {}", id);

        File file = fileService.findOne(id)
            .orElseThrow(FileNotFoundException::new);

        byte[] bytes = Bytes.getArray(file.getContent());

        ByteArrayResource resource = new ByteArrayResource(bytes);

        return ResponseEntity.ok()
            .contentLength(bytes.length)
            .contentType(MediaType.parseMediaType(file.getType()))
            .body(resource);
    }
}

when i check the developer tools i can see that the UI is issuing requests to server for image files , however the get requests are missing the Authorisation header. I am already having http interceptors in place to add authentication headers. however since the background image url is set to the div tag it dont call the http interceptor to attach authentication token and in the developer tool i can see 403 forbidden errors.

any idea what would be my code looks like if i want to access a file from the server as bytes and setting it as background image to the div tag.

I am having a FilesService class .

import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';

import { FileResponse, AppConfig } from '../models';
import { ConfigService } from './config.service';

@Injectable()
export class FilesService {
  config: AppConfig = this.configService.config;

  constructor(private http: HttpClient, private configService: ConfigService) {}

  get(id: string) {
    return this.http.get<FileResponse>(`${this.config.api}/files/${id}`);
  }

  upload(formData: FormData) {
    return this.http.post<FileResponse>(`${this.config.api}/files`, formData);
  }

  getFileUrl(id: string) {
    return `${this.config.api}/files/${id}`;
  }
}

this is my interceptor that add json web tokens

@Injectable()
export class AuthenticationInterceptor implements HttpInterceptor {
  constructor(private injector: Injector) {}

  intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    if (
      request.url.startsWith('/assets') ||
      request.url.startsWith('https://maps.googleapis.com/maps/api/staticmap')
    ) {
      return next.handle(request);
    }

    const authenticationService = this.injector.get(AuthenticationService);
    const notificationService = this.injector.get(NotificationsService);
    const router = this.injector.get(Router);

    if (!!authenticationService.token) {
      request = request.clone({
        setHeaders: {
          Authorization: `Bearer ${authenticationService.token}`
        }
      });
    }

    return next.handle(request).pipe(
      catchError(err => {
        if (
          request.url !== authenticationService.loginUrl &&
          err instanceof HttpErrorResponse &&
          err.status === 401
        ) {
          authenticationService.logout();
          notificationService.stopInterval();
          router.navigate(['/login'], {
            queryParams: {
              returnUrl: router.url
            }
          });
        }

        return _throw(err);
      })
    );
  }
}

appreciate any help thank you

2 Answers

0
Stöger On
<div class="avatar-circle" [ngStyle]="{ 'background-image': avatarBgImageStyle !== 'none' ? avatarBgImageStyle : ''" [ngClass]="avatarClasses">
  <fa-icon *ngIf="!user?.avatar" icon="user"></fa-icon>
</div>

Did you try this approach? I'm not entirely sure how that works with async obtained values, if that'll update once the variable is set, but I would suggest that you give it a try like this (sadly not able to try that at the moment myself).

0
Mohammadreza Imani On

use this format in your div:

[style.background-image]=" 'url(' +avatarBgImageStyle + ')'"