1

Let's say there is a "conversation" directive, made of "message" directives. The message directive has a button to delete it. The conversation controller has a method to remove a message from its list.

In Angular documentation, they say we can use "require" to access a parent controller from a directive controller.

And here, the answer suggests to use require too, and to create a service only if you can't use require because the 2 directives are not related.

Isn't it a bad practice to call a controller from another controller ? I thought service was typically used to share information between controllers.

Don't you think it would be better to create a service with the deleteMessage method, and inject this service in the message controller ?

Community
  • 1
  • 1

2 Answers2

1

I'm personally not a fan of calling a function on the parent or root or stuff like that, as its coupled in a kind of implicit way. I prefer to use a service as you mentioned or injecting the concrete function(s) into your directive.

Below are some pros and cons for both approaches. Please note they are based on my personal experience (and I'm not an expert).

Services

Services are singletons, meaning there is only one instance in your whole application. This can have several advantages, if you need them:

  • it's always there (you don't need to create it explicitly)
  • it can cache data which can be usefull, e.g. to maintain the state of a view/page
  • it can be used to exchange data between different components
  • it can easily be injected where ever you need it

This can also lead to some disadvantages though:

  • if different components share the same service, they might mess up each others data
  • components (i.e. directives) will depend on that service, leaving the user of the directive no flexibility in how he wants to use that directive (e.g. what should happen when a user clicks a button). Meaning that basically the concrete functionality is "hard-coded" in to the directive.

I personally like to use services, if they have a direct link to the directive (and to nothing else) or do not store any state, for example if they only contain simple helper functions.

If in your application you have one conversation list, then I would consider implementing that in a service that exposes functions like addMessage, deleteMessage, sortBy, etc.. Then it can be injected in to any component which needs access to that (central) list.

Passing functions as arguments

On the other hand, if you have a message-directive, you might want to use it for other kind of messages as well..? That is messages which are not from the conversation but maybe from a mailbox (just a stupid example ;)). Then I wouldn't couple the service and the directive. You could inject the deleteMessage-function, which in one case would remove it from the conversation and in the other case remove it from the mailbox.

I think both approaches are valid, but always depend on the scenario and how the components are shared/reused over your application.

The second approach might be nicer from a "coupling"-perspective, but might get complicated in case of lots of parameters and when passing parameters over several levels of components (e.g. to child-child-child directives).

The first approach is easy to implment and can have several advantages, but results in the component being directly coupled to that service, lowering its reusability.

PzYon
  • 2,963
  • 3
  • 16
  • 27
0

Do you really need to put the delete button in the message directive ?

Since the delete button is to suppress the message from the conversation controller list, I'd rather put the button in the conversation view.

That being said, if you really want to have the delete button on the messagedirective, I would simply pass the delete method as an argument in your directive. When doing this you don't have to worry about which controller defined the function, you simply call it from your child directive (and if you want the parent controller to execute it, simply pass a binded function to your directive).

aherve
  • 3,795
  • 6
  • 28
  • 41