1

I'm trying to create an AngularJS directive for generating on the fly stacked canvas elements, some "static" and some generated / counted by an index.

The static canvas elements (class/id c-area in example code) are accessible in the link-function, so I get a canvas context but these generated by the ng-repeat directive are not.

Why are the ng-repeat generated canvas elements not really / yet there (in DOM)? In the generated HTML code they are visible.

What hasto be done / changed to get the context of these canvas elements?

[Edit] I found this question/answer "Calling a function when ng-repeat has finished". It could be a solution, but it looks for me more like a workaround / hack than a good and clean solution. [/Edit]

Here is a plunker with an simplified example of the situation with some console.logs to see the results.

The JS code for this directive:

var app = angular.module('canvasGroup', []);

app.run(['$templateCache', function($templateCache) {
  $templateCache.put('canvasgroup.tpl.html', '<div class="canvas-group" style="position:relative">' +
    '<canvas ng-repeat="group in ps.groups" id="group-{{group}}" width="{{ps.width}}" height="{{ps.height}}" class="group group-{{group}}" style="position:absolute;">No canvas support</canvas>' +
    '<canvas id="c-area" class="c-area" width="{{ps.width}}" height="{{ps.height}}" style="position:absolute;">No canvas support</canvas>' +
    '</div>');
}]);

function canvasgroupDirectiveController() {
  var ps = this;
  ps.groups = [1, 2];
  ps.width = 400;
  ps.height = 300;
}


app.directive('canvasGroup', function() {
  return {
    restrict: 'E',
    templateUrl: 'canvasgroup.tpl.html',
    controller: canvasgroupDirectiveController,
    controllerAs: 'ps',
    bindToController: {
      groups: '='
    },
    link: function(scope, element, attrs, canvasGroupCtrl) {

      var canvasArea = document.getElementsByClassName('c-area');
      console.log("canvasArea", canvasArea); // [canvas#c-area.c-area, c-area: canvas#c-area.c-area]
      var ctxCanvasArea = canvasArea[0].getContext('2d');
      console.log("ctxCanvasArea", ctxCanvasArea); // CanvasRenderingContext2D {}

      var group_1_el = element[0].getElementsByClassName('group-1');
      console.log("group_1_el", group_1_el);// [] empty objekt
      console.log("group_1_el[0]", group_1_el[0]); // undefined

      var group_1_doc = document.getElementsByClassName('group-1');
      console.log("group_1_doc", group_1_doc);// [] empty objekt
      console.log("group_1_doc[0]", group_1_doc[0]); // undefined

      //var ctxCanvasGroup = group_1_doc[0].getContext('2d'); // TypeError: Cannot read property 'getContext' of undefined
      //console.log("ctxCanvasGroup", ctxCanvasGroup);

    }
  }
});
Community
  • 1
  • 1
Billy G
  • 658
  • 1
  • 8
  • 20

1 Answers1

0

A solution seams to be to include ("transclude") the whole link-function part into a $timeout function like this:

link: function(scope, element, attrs, canvasGroupCtrl) {
  $timeout(function() {
    var canvasArea = document.getElementsByClassName('c-area');
    console.log("canvasArea", canvasArea); // [canvas#c-area.c-area, c-area: canvas#c-area.c-area]
    var ctxCanvasArea = canvasArea[0].getContext('2d');
    console.log("ctxCanvasArea", ctxCanvasArea); // CanvasRenderingContext2D {}

    var group_1_el = element[0].getElementsByClassName('group-1');
    console.log("group_1_el", group_1_el); // HTMLCollection[canvas#group-1.group.group-1]
    console.log("group_1_el[0]", group_1_el[0]); // <canvas id="group-1" class="group group-1" style="position:absolute;" height="300" width="400" ng-repeat="group in ps.groups">

    var group_1_doc = document.getElementsByClassName('group-1');
    console.log("group_1_doc", group_1_doc); // HTMLCollection[canvas#group-1.group.group-1]
    console.log("group_1_doc[0]", group_1_doc[0]); // <canvas id="group-1" class="group group-1" style="position:absolute;" height="300" width="400" ng-repeat="group in ps.groups">

    var ctxCanvasGroup = group_1_doc[0].getContext('2d');
    console.log("ctxCanvasGroup", ctxCanvasGroup); // CanvasRenderingContext2D {}
  });
}

If this a good / the best solution? I can not tell right know, but it gives the wanted behavior. Maybe someone has a more elegant way to solve this or can show where some drawbacks can be on the above solution?

Here is an updated plunker

Billy G
  • 658
  • 1
  • 8
  • 20