Stack Overflow is a community of 4.7 million programmers, just like you, helping each other.

Join them; it only takes a minute:

Sign up
Join the Stack Overflow community to:
  1. Ask programming questions
  2. Answer and help your peers
  3. Get recognized for your expertise

I've got the following directive (I've cut out the non-important part for the sake of brevity) :

I basically use the ng-include directive to dynamically load my templates.

Directive

module chat.directives {
  "use strict";
  export class ChatWindow implements ng.IDirective {
    public restrict = 'E'
    public static DirectoryName = "chatWindow";
    public scope = {
      chatModel: '=',
      chatSection: '@chatSection'
    }

    public template(element : ng.IAugmentedJQuery, attrs : IChatWindowAtributes) {
      return '<div ng-include="getTemplateUrl()"></div>';
    }

    public link(scope:chat.controllers.IChatScope, element:ng.IAugmentedJQuery, attrs:ng.IAttributes) {

      scope.getTemplateUrl = () => {
        return "/chat/directives/" + scope.chatSection + "-chat-window-template.html";
      }
    }


    public static factory():ng.IDirectiveFactory {
      var directive = () => new ChatWindow();
      directive.$inject = [];
      return directive;
    }
  }

  interface IChatWindowAtributes extends ng.IAttributes {
    chatSection : string;
  }

  angular
    .module('chat')
    .directive(chat.directives.ChatWindow.DirectoryName, chat.directives.ChatWindow.factory());
}

Problems do arise as soon as I try to implement an event in one of the templates, for example ng-click.

Because I am using the ng-include hack, element.html() of the linkage function refers to <div ng-include="getTemplateUrl()"></div> and thus doesn't allow me to setup an eventhandler programmatically.

HTML Template

<!-- Chat window-->
<div class="col-xs-4 chat-window">
  <aside>
    <div class="panel panel-default">
      <div class="panel-heading">
        <span class="glyphicon glyphicon-list-alt icon"></span>
      </div>
      <div class="chat-output">

      </div>
      <form action="">
        <input id="msgInput" autocomplete="off"/>
        <button ng-click="chat.sendMessage('hi')" stop-event>Send</button>
      </form>
    </div>
  </aside>
</div>

Additionally, any call from the template with ng-click="chat.sendMessage('hi')" doesn't trigger the corresponding function in my controller.

Controller Implementation

module chat.controllers {
  'use strict';

  class ChatCtrl {

    public chatHistory : Array<Common.Services.IMessage> = [];
    public chatSection : string;
    public currentMessage : string;

    // $inject annotation.
    // It provides $injector with information about dependencies to be injected into constructor
    // it is better to have it close to the constructor, because the parameters must match in count and type.
    // See http://docs.angularjs.org/guide/di
    public static $inject = [
      '$scope',
      'UserService',
      'MessageService'
    ];

    // dependencies are injected via AngularJS $injector
    constructor(private $scope: IChatScope, private userService : User.Services.IUserService, private messageService : Common.Services.IMessageService) {
      this.$scope.chatModel = {
        chatHistory: this.chatHistory,
        userService : this.userService,
        messageService: this.messageService,
        storeChatSectionInCtrl : this.storeChatSectionInCtrl,
        subscribeToChatSectionEvents : this.subscribeToChatSectionEvents,
        fetchChatHistory : this.fetchChatHistory
      }
    }

    public storeChatSectionInCtrl(section){
      // Store the section additionally to the directive in the controller
      this.chatSection = section;
    }

    public subscribeToChatSectionEvents(section : string){
      var self = this;

      // Subscribe for the chat section for incoming messages
      this.messageService.addMessageListener(section + "ChatMessage", function(){

      });

      // Subscribe for incoming messages to load the chat history
      this.messageService.addMessageListener(section + "ChatHistory", function(message : ChatHistoryMessage){
        self.chatHistory = message.data.chatHistory;
      });
    }

    // Send a chat message to the server
    public sendMessage(message : string){
      var messageObj = new ChatInputMessage({
        chatSectionPrefix : this.chatSection,
        chatMessageObj : new ChatMessage({
          message : message
        })
      });

      this.messageService.sendMessage(messageObj);
    }

    // Send a request for the chat history to the server
    public fetchChatHistory(section : string){
      var messageObj : ChatHistoryMessage = new ChatHistoryMessage({
       chatSectionPrefix : section,
       chatHistory : null
       });

       // Send a request in order to retrieve the chat history of the given section
       this.messageService.sendMessage(messageObj);
    }
  }

  export interface IChatScope extends ng.IScope {
    getTemplateUrl : () => string;
    chatModel : IChatModel;
    chatSection : string;
  }

  export interface IChatModel {
    chatHistory :  Array<Common.Services.IMessage>;
    userService: User.Services.IUserService;
    messageService : Common.Services.IMessageService;
    storeChatSectionInCtrl : (section : string) => void;
    subscribeToChatSectionEvents: (nameOfEventListener : string) => void;
    fetchChatHistory : (section: string) => void;
  }

  // Message
  export interface IChatMessage {
    message : string;
    creationDate? : string;
    from? : string;
    to? : string;
  }

  export class ChatMessage implements IChatMessage {
    public message : string;
    public creationDate : string;
    public from : string;
    public to : string;

    constructor(message : IChatMessage){
      this.message = message.message;
      this.creationDate = message.creationDate;
      this.from = message.from;
      this.to = message.to;
    }
  };

  // Message Service
  export interface IChatData{
    chatSectionPrefix : string;
    chatMessageObj : IChatMessage;
  }

  export class ChatInputMessage extends Common.Services.ClientMessage<IChatData> {
    static NAME = "ChatMessage";

    constructor (chatData: IChatData) {
      super(chatData.chatSectionPrefix + ChatInputMessage.NAME, chatData);
    }
  }

  // Chat history
  export class ChatHistoryMessage extends Common.Services.ClientMessage<IChatHistory> {
    static NAME = "ChatHistory";

    constructor (chatData: IChatHistory) {
      super(chatData.chatSectionPrefix + ChatHistoryMessage.NAME, chatData);
    }
  }

  export interface IChatHistory{
    chatSectionPrefix : string;
    chatHistory : Array<IChatMessage>;
  }

  /**
  * @ngdoc object
  * @name chat.controller:ChatCtrl
  *
  * @description
  *
  */
  angular
    .module('chat')
    .controller('ChatCtrl', ChatCtrl);
}

HTML

 <div ng-controller="ChatCtrl">
      <chat-window chat-model="chatModel" chat-section='lobby'></chat-window>
    </div>

Solution

For some reason I though I would operate on the controller instead of the directive - thus using sendMessage('hi') instead of chat.sendMessage('hi') solved the issue ...

share|improve this question

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.