0

I'm using the GridLoadingEffects library by Codrops along with Angular JS to feed it list items with data from wordpress. Everything works in terms of Angular retrieving the data via $http request and storing the variables asynchronously. The data is processed and binded to HTML via ng-bind-html.

<body ng-app="myApp">
    <div class="container" ng-controller="myController">
        <ul class="grid effect-6" id="grid" ng-bind-html="bindHTML(html_code)"></ul>
    </div>
</body>

After a slight delay as a result of retrieving the data, I can see that the HTML is in fact loaded into the DOM in the inspector. However, the problem is that the GridLoadingEffects effect immediately sees that there are no list items in the DOM, and therefore throws an undefined error.

I'm not an experienced web developer, so I can't precisely determine where the call is made to check for the DOM's li elements and apply the effect, and this library has many dependencies including modernizr.js, masonry.js, imagesloaded.js, AnimOnScroll.js, and more. What confuses me further is that these files are loaded in different places in the HTML, some in the head and some at the end of the body. So in terms of the execution flow, I'm really lost as to how to solve this problem. I'm not sure but I think this function is what instantiates the effect.

<script>
window.onload = function() {
    new AnimOnScroll( document.getElementById( 'grid' ), {
        minDuration : 0.4,
        maxDuration : 0.7,
        viewportFactor : 0.2
    } );
}
</script>

It is to be placed at the end of the body, as per the example html file provided by Codrops. I think that in order to rectify the issue, the function above has to run once Angular has fed the data to the ul tag. Even though there's a window.onload attached to it, it probably doesn't consider that there's more to load with angular.

Am I correct in my assumptions? I'm sure there's an easy fix to this. Can anyone help?

UPDATE: Here is how the $http request is initiated:

(function() {
  'use strict'

  angular.module('myApp', [])
  .controller('myController', myController);

  myController.$inject = ['$scope', '$sce','$http']

  function myController ($scope, $sce, $http) {


    $http({
      method : "GET",
      url : myURL
    })
    .then(function(response) {
      $scope.myData = response.data;
      var list = new Array
      for (var i = 0; i < $scope.myData.length; i++) {
        var string = '<li><figure class="blurfilter semitransparent"><img src=myURL><figcaption><h3>' + $scope.myData[i]['title']['rendered'] + '</h3></figcaption></figure></li>';
        list.push(string)
      }
      $scope.html_code = list.join("")
      $scope.bindHTML = function(html_code) {
        return $sce.trustAsHtml(html_code)
      };
    });    
  };
})();

UPDATE 2:

My HTML now using ng-repeat to separate model and view:

<li ng-repeat="(key, val) in myData">
    <h3>{{val.title.rendered}}</h3>
</li>

And my angular code (omitted the http requests):

(function() {
  'use strict'
  angular.module('myApp', [])
  .controller('myController', myController);
  myController.$inject = ['$scope', '$sce','$http']
  function myController ($scope, $sce, $http) {
    $scope.$watch('myData', function() {
    // if the myData is loaded
        if ($scope.myData.length > 0) {
            new AnimOnScroll( document.getElementById( 'grid' ), {
                minDuration : 0.4,
                maxDuration : 0.7,
                viewportFactor : 0.2
            });
        }
    });

Now I get $scope.myData is undefined. $scope.myData is defined in the .then of my http request. Maybe it's helpful to mention that this error points to a line in the angular.min.js file, not to my app.js.

parsa_047Fletcher
  • 427
  • 1
  • 5
  • 9
  • Can you please show use where the http request is initiated? It is very likely that that will be where to add the code – Vlad274 Aug 29 '18 at 15:01
  • Sure. I edited my question – parsa_047Fletcher Aug 29 '18 at 15:14
  • Are you sure the undefined error is caused by the animation? I'm surprised there isn't an issue with the `bindHTML` function since it isn't added to the scope until the request completes – Vlad274 Aug 29 '18 at 15:18
  • Oh that's probably it. I just tried putting `bindHTML` outside the `.then` function with sample html as `html_code` and the animation picked up on it. So how can I add it to the scope properly? I just tried declaring the `$scope.bindHTML` function outside the http request while keeping `$scope.html_code` still within and got an error from masonry: TypeError: this.items[0] is undefined, which I assume means that the `li`s couldn't be located. – parsa_047Fletcher Aug 29 '18 at 15:25

2 Answers2

0

You can try to use $scope.$watch function in your angular controller on the data variable after you get the data using $http service.

   $scope.$watch('myData', function() {
       // if the myData is loaded
       if ($scope.myData && $scope.myData.length > 0) {
           // your code
       }
   });
muzychuk
  • 288
  • 1
  • 2
  • 13
  • So in the `.then` function, I paste the code you mentioned and paste the `new AnimOnScroll` function after the if statement? – parsa_047Fletcher Aug 29 '18 at 15:17
  • First of all you need to separate model and view. You should use ng-repeat to iterate through your data items instead building html page in the controller. Then you can paste the code above anywhere in the controller, not just in .then callback since it check the scope variable. – muzychuk Aug 29 '18 at 15:28
  • In fact I was using ng-repeat but I had the same problem. I figured building the html in the controller would solve it. I'll give it a go now. – parsa_047Fletcher Aug 29 '18 at 15:33
  • I've edited my question to show the changes, but $scope.myData is said to be undefined. Also, I get a source map error. It's strange and I never know why, sometimes it happens and I still get the result I want... – parsa_047Fletcher Aug 29 '18 at 15:45
  • You can try with additional conditions, like if($scope.myData && $scope.myData.length > 0) – muzychuk Aug 29 '18 at 15:48
  • Ok so that solved the error. I have no idea why but it did. But now it's worse. The effect doesn't work and there are no errors. The DOM is populated properly. The images are at opacity 0 but that's necessary for the loading effect. I've copied my project to a fiddle: https://jsfiddle.net/hk78Luqy/6/ Could you maybe take a look at it here? – parsa_047Fletcher Aug 29 '18 at 16:09
0

I understand my problem deviated a little from running a function after data has been retrieved to running the function after the retrieved data has populated the DOM. For anyone stuck on the same problem (not when the data is retrieved but after retrieved and DOM has been populated), you need to use directives. Check this post: ng-repeat finish event. Your solution is here.

parsa_047Fletcher
  • 427
  • 1
  • 5
  • 9