0

I have a semi-complex directive. Here's the HTML which it uses as a template...

<div ng-hide="hidden" class="alert-container">
  <div ng-class="startFade ? ['alert-box', 'fade', colorClass] : ['alert-box', colorClass]">
    <span class="glyphicon glyphicon-alert"></span><p>{{ content }}</p>
  </div>
</div>

And here's the relevant JS...

svs.directive("alertBox", function () {
  return {
    restrict: "E",
    templateUrl: "resources/html/directives/alertBox.html",
    link: function(scope, element, attrs, ctrl) {
      ctrl.init(element);
    },
    controller: function($scope, $timeout, alertBoxService) {
      var context = this;
      function trigger(content, color) {
        $scope.content = content;
        $scope.colorClass = color;
        $scope.hidden = false;
        $scope.hide();
      }
      function init(element) {
        context.element = element;
        context.callback = trigger;
        alertBoxService.register(context);
      }
      context.trigger = trigger;
      context.init = init;
    }
  };
});

This directive compliments a service which I intend to inject into my controllers. Here's the service's JS...

svs.service("alertBoxService", function($compile) {
  var alertBoxes = [];
  var alertCounter = -1;
  this.register = function(ctrl) {
    alertBoxes[alertCounter] = ctrl;
  }
  this.trigger = function(content, color) {
    alertCounter++;
    angular.element(document.getElementById('alert-boxes')).append($compile("<alert-box></alert-box>"));
    if (typeof(color) === 'undefined') color = "red";
    alertBoxes[alertCounter].callback(content, color);
  }
});

The idea is to have a service which I can inject into my controllers. When I call the trigger method on that service, I can provide a color, and some content. The service then compiles a new instance of the directive, the newly compiled directive registers itself with the service, then the trigger method passes the directive's callback a color and the content.

I believe my problem lies in compiling the new element. In the console, I get this error...

TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'

What is the issue here, and how can I modify my code to reach my desired result?

Allenph
  • 1,875
  • 27
  • 46
  • @PatrickEvans Look at the directive. The directive should be the only thing that ever calls the `.register()` method. It's a sub/pub model. So, The `trigger()` method should be called, the counter should be incremented, THEN, the directive should call the `register()` method. – Allenph Aug 30 '16 at 22:37
  • If I understand correctly, the incrementer could go in either function without effect. – Allenph Aug 30 '16 at 22:39
  • Ok I see the flow now, my mistake. What line gives that error? – Patrick Evans Aug 30 '16 at 22:45
  • I believe it is the second line in the `trigger` method. – Allenph Aug 30 '16 at 22:47
  • `$compile()` returns a function in which you pass a scope and then you get the actual node element. You need to do `$compile('')($scope)` where `$scope` would be whatever parent scope, ie your controllers scope – Patrick Evans Aug 30 '16 at 22:54
  • Is there a way to do it without the scope? There is no scope. We're in a service. – Allenph Aug 30 '16 at 22:56
  • `$rootScope` if it doesn't have a parent one. Is `alert-boxes` a controller or in one for instance, you can get that controller's scope by `angular.element('#alert-boxes').scope()` – Patrick Evans Aug 30 '16 at 22:57
  • @PatrickEvans that did indeed solve one problem. However, there is another one. I've used `console.log()` to diagnose the new problem. It appears that the `register()` method is not called until after `trigger()` finished. This results in the `alertBoxes` array not containing references to the directive controllers. – Allenph Aug 30 '16 at 23:01

0 Answers0