Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AngularJS: What is the best practice to make communication between components?

I have a problem reasoning about components communication. The main question I tried to reason about and failed: what should I use - $watch or $on ($broadcast/$emit) to establish the communication between components?

I see three basic cases:

  1. Controller + Directive. They communicate naturally using the $scope bidibinding. I just put the service, which incapsulates some shared state, in the $scope using some object ($scope.filter = {}). This approach seems very reasonable to me.

  2. Controller + Controller. I use the DI to inject singleton services with incapsulated state to communicate between controllers. Those services are bounded to directives using the previous approach. This gives me the data binding out-of-the-box.

  3. Directive + Directive. This is the blind spot in my reasoning. I have directives, that reside in different scopes, in the same scope, etc. I have directives that must reflect all changes (think about slider + charts) and directives, that must trigger the http request (think about select input).

So, the questions are:

  1. What should I use - $watch or $on ($broadcast/$emit) to establish the communication between components?
  2. Should I tend to use $watch in directive-to-directive communication?
  3. Or should I tend to use $broadcast in directive-to-directive case?
  4. Is it better to share the state using injection+binding or injection+events?
like image 373
Mr_Mig Avatar asked Mar 03 '26 08:03

Mr_Mig


1 Answers

I think this depends on the use case for your directives/components. If you expect to be able to re-use a component without having to modify the scope that the component lives in then using broadcast/emit/on would make more sense. IMO if a component internally has some information that I want to be able to retrieve and do different things with, then the broadcast/emit/on scheme makes the most sense.

If on the other hand I need to trigger some service calls in response to something in a directive or I want to share state between a couple of views I end up using a service.

As noted in the comments another alternative that exists is using the require property in the directive definition object:

require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent']

require - Require another directive and inject its controller as the fourth argument to the linking function. The require takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the injected argument will be an array in corresponding order. If no such directive can be found or if the directive does not have a controller, then an error is raised. The name can be prefixed with:

  • (no prefix) - Locate the required controller on the current element.
  • ? - Attempt to locate the required controller, or return null if not found.
  • ^ - Locate the required controller by searching the element's parents.
  • ?^ - Attempt to locate the required controller by searching the element's parents, or return null if not found.

This can be useful in cases where you're creating a "compound component" where multiple directives make more sense than trying to encapsulate all of the functionality into one directive, but you still require some communication between the "main/wrapping directive" and it's siblings/children.

I know this isn't a clear cut answer but I'm not sure that there is one. Open to edits/comments to modify if I'm missing some points.

like image 130
shaunhusain Avatar answered Mar 05 '26 22:03

shaunhusain