A different approach for communicate between Modules in AngularJS

(by Mark Qian)
 
Common ways to communicate between modules of your application using core AngularJS functionality include:

    - Using services
    - A module can be injected into another module
    - Using events
    - By assigning models on $rootScope
    - Directly between controllers, using $parent, $$childHead, $$nextSibling, etc.
    - Directly between controllers, using ControllerAs, or other forms of inheritance
    - More...
    
    There are three categories: 
    	- global (such as rootScope) or relative (like parent)
    	- events
    	- DI
    	
    The problem with first two categories is that you have to hard code the reference of parties. This is really bad 
    as things changing during development and it is hard to be tested.
    
    To target the problem, AngularJS provides a powerful mean, DI, to isolate service producers and consumers. 
    Even though DI provides some degree of isolation, it uses references(the machine addresses) to represent dependencies,
    which reduces a lot of potential on flexibility. 
    
    My point is that to achieve the better flexibility, the application level logic including module relation such as dependencies 
    between modules should not reside in codes. They are the "spirit" of the application just like human being mind should be 
    isolated/extracted from the body (codes of modules). DI in Angular can not achieve this since all the logic is represented by references.  
    
    An ideal flexible application should be built into two parts: a container with all the modules 
    in your layout and the logic that make the modules work together. It will be perfect if the logic can be
    extracted out of codes (container) and loaded as needed (at runtime!).
    	  
    My "different approach" is point-to-point publish/subscribe with dependency out of codes as plain text. 
    
    You may say, wait a minute: Angular has built-in environment for publish/subscribe - the emit and broadcast. 
    If you don't use broadcast heavily, it might be OK. It will become a performance issue if you have a huge scope 
    hierarchy and use publish/subscribe as your major mean for communication between modules or any DOM components. 
    The broadcasting is really overkill for most cases. Instead, straight point to point invocation is enough for many of us.
    
    The key points of my approach:
    
    	- It is point to point invocation without traveling in scope hierarchy
    	- It is built into DOM so it is so easy to access (to do publishing and subscribing)
    	- It also supports browser/tab synchronization: 
    	  the topic can travel to reach all browser/tab instances.
    	  To try it out, just load current page into two browser instances side by side 
    	  and play to see topics reach in all the browser/tab instances!
    	- The module relation/dependencies is presented as plain text so it is very easy to be saved in configuration file.
    	
    	  You may ask: why I want to save the dependencies/logic into files? In some cases, you want to extract the logic out of codes
    	  and pass it around. One example is the feature "browser synchronization" of my approach above.
    	  The Web Storage can only store plain text so it is hard for DI to save communication info and pass it to
    	  other browser instances.
    	      	     
    	  Another example, in case of SAAS, you may deploy the same "container" to different clients with different logic in files 
    	  (which is loaded at runtime) according to the client's paid plan meaning that features are enabled/disabled
    	  by plain text in configuration files instead of codes.
    	  
    	  Or it can be used as access control: the container loads different logic for different roles. For example, there are 
    	  many admin-level publisher/topic but non-admin user's relation contains no subscription to the admin-topic 
    	  so can never act as an admin.
     

All Source Codes

See how it is running:

Case 1: Communicate between directives

    The following is a case where two directives (publisher and subscriber) communicate with publish/subscribe. 
	Actually, this two "sample" directives can be used as a mean to able any DOM element publish/subscribe-able: 
    just add the directive "publisher" (as an attribute) to a DOM element to make it publish a topic or add 
    the directive "subscriber" (as an attribute) to a DOM element to make it subscribe a topic (in other words, 
    it will carry out an action as it receives a topic).   
	
<div id="e1" publisher="{'topic':'TopicA', 'event':'click'}" style="cursor:pointer;border-style: ridge; width: 300px; margin: 10px">e1</div>
<div id="e2" subscriber="{'topic':'TopicA', 'handler':'handlerE2'}" style="border-style: ridge; width: 300px; margin: 10px">e2</div>


Case 2: Communicate between controllers

    The following is a case where two controllers (publishController and subscribeController) communicate with publish/subscribe. 
	
I subscribe TopicB


Case 3: Communicate between Controllers and directives

    The following is a case where directive and controller communicate with publish/subscribe.
    The div on the left below (a directive) publish TopicB as your mouse is moved over and the right div 
    (a controller) in "Case 2" above subscribed the TopicB and react.
    
    Similarly, the div on the right (a controller) publish TopicA when clicked. The right div in   
    "Case 1" (a directive) subscribe TopicA and react.
	
<div id="e1" publisher="{'topic':'TopicB', 'event':'mouseover'}" style="cursor:pointer;border-style: ridge; width: 300px; margin: 10px">e1</div>