javascriptwebpackaurelia

Image source binding in Aurelia


I am trying to bind the src attribute of an img tag in an aurelia component, how can I do so?

I'm creating some images in a reapeat.for loop this way:

<img repeat.for="picture of infoboard.memberPictures" src.bind="picture">

In which, the memberPictures array comes from the view model, and the value of picture is a relative address: ../../../assets/pictures/img_avatar.png.

In the view model, I fetch members' info from the database and by processing the data, populate the memberPictures array this way:

this.httpClient.fetch(`boards/membersof/${this.infoboard.id}`)
      .then(response => response.json())
      .then(data => {
        this.infoboard.memberPictures = data.result.map(element => `../../../assets/pictures/${element.profile_pic}.png`);
      });

Binding the address this way, the images do not load, like this:

picture of the problem

and also the browser console shows the following error:

img_avatar.png:1 GET http://localhost:8080/assets/pictures/img_avatar.png 404 (Not Found)

when inspecting the elements, the picture tag for member avatar is this:

<img src.bind="picture" class="au-target" au-target-id="10" src="../../../assets/pictures/img_avatar.png">

But if we provide the image source with a static image with the exact same address generated in the above example as shown below:

<img repeat.for="picture of infoboard.memberPictures" src.bind="../../../assets/pictures/img_avatar.png">

there will be no problem:

picture of the problem

and now by inspecting elements there is different result:

<img src="/a5e81f19cf2c587876fd1bb08ae0249f.png">

Apparently, there is a difference in handling static files in aurelia. How is the image source changed this way, and what is the correct way of binding the image source?


Solution

  • This is because you are using webpack to bundle your project.

    One of the things webpack does, is pack all of your static files (images, fonts etc.) into the bundle - and then replacing all the static references with a different "url" that points to the same asset in the bundle.

    At run time, you don't have access to things that are out of the bundle.

    By the way, this is why we need to use PLATFORM.moduleName() for all aurelia components, because webpack doesn't pick these up by default.

    In your case, you are binding the img tag to dynamic urls. Webpack doesn't have any way of bundling them into the output bundle, because those url's are generated at runtime.

    You need to use the require keyword for this to work at runtime for a directory structure like this:

    directory structure

    export class App {
      public urls:string[] = ["test", "t1", "t2", "t3"];
    
      getUrl(name)
      {
        return require(`./assets/${name}.png`);
      }
    }
    
    <template>
      <img repeat.for="url of urls" src.bind="getUrl(url)">
    </template>
    

    Edit:

    in your case, simply use:

    this.httpClient.fetch(`boards/membersof/${this.infoboard.id}`)
          .then(response => response.json())
          .then(data => {
            this.infoboard.memberPictures = data.result.map(element => require(`../../../assets/pictures/${element.profile_pic}.png`));
          });