2

OK So I created a chat widget that isn't hardcoded instead it it is created by a service for example:

$chatWidget.setParent(parent).setUser(user).setMessages(messages).build();

Here is the build function of the $chatWidget service:

var build = function () {
        if (parentElement && myUser && myMessages) {
            parentElement.append('<re-chat></re-chat>');
        }
    }

Here is a simplified version of the chat directive:

    angular
    .module('app')
    .directive('reChat', function ($chatWidget) {
        return {
            restrict: 'E',
            replace: true,
            template: 

    '<div id="chat-widget-container"><div id="chat-widget-header">reUser.name</div>'+
    '<div id="chat-widget-body"<div ng-repeat="message in reMessages"><div>' +
    '<p> {{message.body}} </p></div></div></div>' +
      '<textarea ng-model="messageToSend" id="message-to-send" placeholder ="Type your message" rows="3"></textarea>' +
      '<button class="btn btn-default">Send</button></div>',
            scope: {
                reMessages: '=',
                reParent: '<',
                reUser: '<'
            },
            link: function (scope, element, attrs) {    
            scope.reUser = $chatWidget.getMyUser();
            scope.reMessages = $chatWidget.getMyMessages();
            scope.reParent = $chatWidget.getParent();
        };
    });

HERE IS THE PROBLEM

My re-chat directive appears in the DOM structure but its inner html is completely empty.

I've tried several alternatives including removing the template and doing this:

var html = '[TEMPLATE HERE]' 
element.html(html);
$compile(element.contents())(scope);

or:

var html = '[TEMPLATE HERE]';
element.replaceWith(html);

Both to no avail. So, How can I get my directive's html to show up???

EDIT

The widget appears fine if I hard code it like the following:

<re-chat re-messages="messages" re-my-user="user"></re-chat>

But this is not the behavior I want. I want the directive to be added dynamically.

isherwood
  • 58,414
  • 16
  • 114
  • 157
  • @JCFord The service methods are just basic getters and setter which seem to be working fine. Whats interesting is my link function in the directive doesn't appear to be executing at all when I do it the dynamic way. – RudolphRedNose Feb 21 '18 at 20:38

1 Answers1

1

Try changing your directive to use shared scope and get rid of the link function.

Then create a new child scope in your service build() method. Attach data for the directive onto that new child scope. Then compile the new directive with the child scope and attach it to DOM.

var build = function () {
    if (parentElement && myUser && myMessages) {
        var childScope = scope.$new(); //pass true here if you want to
                                       //inherit parent scope properties.
        childScope.reMessages = myMessages;
        parentElement.append($compile('<re-chat></re-chat>')(childScope));
    }
}
JC Ford
  • 6,946
  • 3
  • 25
  • 34
  • My build function is in my factory. To my knowledge I can't access scope from a factory. I want the chat widget to be independent of any view or controller. – RudolphRedNose Feb 21 '18 at 21:02
  • 1
    You generally shouldn't inject `$scope` into a service, but you can pass it from a controller into a service function. Pass a scope object into `.build()` when you call it. – JC Ford Feb 21 '18 at 21:07
  • Angular will never compile your directive until you tell it to. You do that by adding the directive to a template which will be compiled or by injecting the `$compile` service and calling it yourself. If your `build()` function is where you want to create the `` element then you need to compile it against a scope object there. – JC Ford Feb 21 '18 at 21:09
  • Works perfectly now, I'll accept your answer and thanks a lot for the help! – RudolphRedNose Feb 21 '18 at 21:23