2

I have a PHP function that loops through image results in a database, formats them with HTML, then returns the variable containing the HTML layout to my page.php. This is all working okay, but in the loop I have some script tags that call a function in my script.js file. It takes two parameters (url and count). I am trying to pass the url of the result from the database to the function, create a new img element, and append the passed url to the src attribute of the newly created img tag. This appears to be working so far - when I console.log the result, I get a load of <img> tags, all with corresponding src attached to them.

I am having trouble with actually getting these back to the front end, though.

My code below shows the part of the php that gets looped through, followed be the Javascript function it calls on each loop.

    public function getResultsHtml($page, $pageSize, $term) {
        $fromLimit = ($page - 1) * $pageSize;
        $query = $this->con->prepare("SELECT * FROM images 
            WHERE (title LIKE :term
            OR alt LIKE :term) AND broken=0
            ORDER BY clicks DESC
            LIMIT :fromLimit, :pageSize");

        $searchTerm = "%" . $term . "%";
        $query->bindParam(":term", $searchTerm);
        $query->bindParam(":fromLimit", $fromLimit, PDO::PARAM_INT);
        $query->bindParam(":pageSize", $pageSize, PDO::PARAM_INT);
        $query->execute();

        $resultsHtml = "<div class='image-results'>";

        $count = 0;
        while($row = $query->fetch(PDO::FETCH_ASSOC)) {
            $count++;
            $id = $row["id"];
            $imgUrl = $row["imgUrl"];
            $siteUrl = $row["siteUrl"];             
            $title = $row["title"];
            $alt = $row["alt"];

            if($title){
                $displayText = $title;
            } else if ($alt) {
                $displayText = $alt;
            } else {
                $displayText = $imgUrl;
            }

            $resultsHtml .= "<div class='grid-item image$count'>
                                <a href='$imgUrl'>
                                    <script>
                                        document.addEventListener('DOMContentLoaded', function() {
                                            loadImage(\"$imgUrl\", \"image$count\");
                                        });
                                    </script>
                                    <span class='details'>$displayText</span>
                                </a>

                            </div>";
            }
            $resultsHtml .= "</div>";
            return $resultsHtml;
        }

    var loadImage = function(src, className){

        var image = document.createElement("img");
        var aTag = document.querySelectorAll("." + className + " a");

        image.onload = function(){
            aTag.innerHTML = image;
        };
        image.onerror = function(){

        };

            image.setAttribute("src", src);

    }

At the moment I'm not geting any results at the front end. In the page source, I can see that inside each anchor tag are script tags, which show the function preloaded with the parameters (loadImage(http://www.com, image22)), but it isn't actually getting a return from the function.

The solution for this with jQuery is below, but I really don't want to use jQuery!

            function loadImage(src, className) {

                var image = $("<img>");

                image.on("load", function() {
                    $("." + className + " a").append(image);
                });

                image.on("error", function() {

                });

                image.attr("src", src);

            }

I know that there is some trouble with dynamically writing <script> tags with .innerHTML, but I don't think this is the problem as the script tags are written before the function is called.

I think I have something firing in the wrong order, or I'm missing something that jQuery handles automatically with the .append function.

I have also tried aTag.appendChild(image);, which also gives no results.

I have been using jQuery for a few months, but I am trying to learn Vanilla JS thoroughly - I'm trying to grasp how the jQuery functions actually work, rather than just relying on them blindly.

Any help is massively appreciated!

6
  • 3
    Did you predefine something like $resultsHtml = ''; before everything? Commented Jan 10, 2019 at 16:32
  • I did! $resultsHtml = "<div class='image-results'>"; is just above $count = 0;. I have an almost duplicate PHP file doing the same thing but it just reads text from the database and outputs it to the DOM - I'm just having trouble with this one becuase of the <script> elements within the loop! Commented Jan 10, 2019 at 16:39
  • Ah ok. Well, if this is a JS issue, I am not the guy for this. There's an answer given, give that a go. Commented Jan 10, 2019 at 16:44
  • I'll take a look now - thank you anyway! I have also edited and attached the entire function, for your interest! Commented Jan 10, 2019 at 16:45
  • 1
    Haha it's okay. Who needs a reputation anyway... Commented Jan 10, 2019 at 16:51

2 Answers 2

0

Beware of that querySelectorAll() returns an array-like NodeList (https://developer.mozilla.org/en-US/docs/Web/API/NodeList), so it should be like this:

(If you only want one element returned user querySelector(), then you don't need the loop)

function loadImage(src, className) {
  var image = document.createElement("img");
  image.src = src;
  image.onload = function() {
    var tags = document.querySelectorAll("." + className + " a");
    for (var i = 0; i < tags.length; i++) {
      tags[i].appendChild(image);
    }
  }
}
<div class='grid-item image2'>
  <a href='https://cdn.pixabay.com/photo/2015/08/21/21/55/star-wars-899693_960_720.jpg'>
    <script>
      document.addEventListener('DOMContentLoaded', function() {   loadImage("https://cdn.pixabay.com/photo/2015/08/21/21/55/star-wars-899693_960_720.jpg", "image2");
          });
    </script>
    <span class='details'>Star Wars 1</span>
  </a>

</div>

Sign up to request clarification or add additional context in comments.

2 Comments

Actually, it returns an array-like object, not an array.
Well, changing querySelectorAll to querySelector solved the problem, and it's now functioning as intended. I was under the impression that querySelector would only target the first <a> on the page - I didn't take into consideration that className gives it a unique identifier! Thank you for your answer!
0

The problem is that you are using querySelectorAll, which returns a NodeList instead of a single DOM node. This means, you have to iterate over the NodeList and append the image to all the nodes within. For this, you have can either create new copies for each place you want to insert the image, or use cloneNode multiple times.

var each = function (xs, func) {
  for (var i = 0; i < xs.length; i += 1) {
    func(xs[i]);
  }
  return xs;
}


var loadImage = function(src, className){

    var image = document.createElement("img");
    var aTag = document.querySelectorAll("." + className + " a");

    image.onload = function(){
      each(aTag, function (a) {
        a.appendChild(image.cloneNode());
      });
    };
    image.onerror = function(){};
    image.alt = '';
    image.src = src;

}



loadImage('http://www.fillmurray.com/500/300', 'wrap')
<div class="wrap">
  <a href="#"></a>
  <a href="#"></a>
  <a href="#"></a>
</div>

1 Comment

Thanks for your answer! This was exactly the problem - I was thrown off for the last couple of hours because I thought querySelector was only going to target the first <a> on the page..

Your Answer

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