0

I'm calling an api with Kotlin and Ktor to get a book in return as json response. From this response I want to load the book cover in my frontend Freimarker .ftl file. I'm doing this call in javascript and write it to html. When I'm calling the function like in my code shown, only the first element in the list get the book cover. The rest is empty. The javascript is executed as inline code in html. I was excepting this function will be called for every new item in the list.

So what can I do to load the image for every element in my list?

index.ftl:

<#-- @ftlvariable name="books" type="kotlin.collections.List<com.nw.models.Book>" -->
<#import "_layout.ftl" as layout />
<@layout.header>
    <#list books?reverse as book>
<div class="container-fluid">
    <hr>
        <div class="row justify-content-center">
        <div class="card" style="width: 18rem;">
            <img id="img-book" class="card-img-top" src="https://via.placeholder.com/128x209.png">
            <div class="card-body">
                <h5 class="card-title">${book.title}</h5>
                <p class="card-text">${book.author}</p>
                <input type="hidden" id="img-url" name="imageUrl" placeholder="${book.imageUrl}">
                <script type="text/javascript">
                    (function() {
                        let a1 = document.getElementById("img-url").getAttribute("placeholder");
                        const image = document.getElementById("img-book");
                        image.src = a1;
                    })();
                </script>
                <a href="/books/${book.id}" class="btn btn-outline-primary">Go to Book</a>
            </div>
        </div>
        </div>
</div>
    </#list>
    <hr>
    <p>
        <a href="/books/new">Create book</a>
    </p>
</@layout.header>
1
  • With the current DOM scripting approach the OP has to assure that the html render process actually creates a unique id value for each book item, thus img-url is not a valid id value for each book item. The same btw applies to each image element's img-book id value. And the placeholder attribute is not to be abused as data storage; the correct way is the usage of a custom data-* attribute. Commented Nov 3, 2022 at 22:34

1 Answer 1

1

With the current DOM scripting approach the OP has to assure that the html render process actually creates a unique id value for each book item, thus img-url is not a valid id value for each book item. The same btw applies to each image element's img-book id value. And the placeholder attribute is not to be abused as data storage; the correct way is the usage of a custom data-* attribute.

One very easily could even implement an approach which is entirely free of id attributes and hidden input fields by just using both data related features the custom data-* attribute and the element's related dataset property.

<#-- @ftlvariable name="books" type="kotlin.collections.List<com.nw.models.Book>" -->
<#import "_layout.ftl" as layout />
<@layout.header>

  <#list books?reverse as book>
    <div class="container-fluid">

      <hr>
      <div class="row justify-content-center">
        <div class="card" style="width: 18rem;">

          <img data-book-cover-src="${book.imageUrl}" class="card-img-top" src="https://via.placeholder.com/128x209.png">

          <div class="card-body">
            <h5 class="card-title">${book.title}</h5>
            <p class="card-text">${book.author}</p>
            <a href="/books/${book.id}" class="btn btn-outline-primary">Go to Book</a>
          </div>

        </div>
      </div>

    </div>
  </#list>

  <script type="text/javascript">
    document
      .querySelectorAll('img[data-book-cover-src]')
      .forEach(elmNode =>

        elmNode.src = elmNode.dataset.bookCoverSrc
      );
  </script>

  <hr>
  <p>
    <a href="/books/new">Create book</a>
  </p>
</@layout.header>
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.