2

I have code in a directive relating to a "highlightable image." The goal is to be able to create highlights on an image and attach a comment to it. So when you click on the image, it creates an annotation.

I have code in the controller for a tooltip toolbar, which you can use to attach a comment to the annotation. Currently, when the 'comment' button on this toolbar is pressed, the information is stored into the database. If you click 'cancel' on the toolbar, the highlight should be deleted.

My dilemma is that I'm not sure how to structure things to conform to the MVC design pattern. Specifically, clicking cancel occurs in the toolbar, but must affect the highlights (which are managed by the directive). And clicking comment must make a call to a service to modify the database.

I've considered moving the toolbar code into the directive, but decided otherwise because directives shouldn't be dealing with backend. And ideally, the toolbar should be in its own directive. I'd like to know what you think the 'correct' way of doing it is.

Daniel Que
  • 1,734
  • 4
  • 20
  • 31
  • Nor should controllers having to deal directly with tha backend. Services are for that purpose. You can inject the service into the directive and use that for "backend-dealing". – gkalpak May 23 '14 at 18:25
  • I've considered injecting the service into the directive, but I read that it was bad practice. Thoughts? – Daniel Que May 23 '14 at 18:27
  • Where did you read this ? Directives use services all the time (even Angular's directives use a bunch of services). – gkalpak May 23 '14 at 19:08
  • Oh I must've misinterpreted it. It was this post: http://stackoverflow.com/a/15569566/2901178 – Daniel Que May 23 '14 at 19:13

2 Answers2

5

Based on the functionality that you described,

Create a service:

highlightImageService (this will use the $http service to persist data to the database)

  • addHighlightToImage(image, highlight)
  • attachComment(highlight, comment)
  • deleteHighlight(highlight)

Create a controller:

highlightImageController

  • createHighlight()
  • attachComment()
  • deleteHighlight()

In your directive, specify your controller and inject your service:

.directive('imageHighlighter', function(highlightImageService) {
     restrict: ...
     scope: ...
     controller: highlightImageController,
     link: function(scope, element, attr, controller) ...
})

Tie everything together in a module:

var module = angular.module('imageHighlighter', [...]);
module.controller(highlightImageController);
module.directive(imageHighlighter)
module.factory(highlightImageService);

Since everything is self-contained in a module (directives, controllers, services), all one has to do to use your module is add it as a module dependency and add directives to your page:

Script:

 var app = angular.module('app', ['imageHighlighter']);

Html:

  <body ng-app="app">
     <div image-highlighter></div>
  </body>
Michael Kang
  • 52,003
  • 16
  • 103
  • 135
0

There's another way to structure this.

  1. Create directive Toolbar
  2. Create directive Highlighter
  3. Create service DataService
  4. Create callback functions in your controller's scope
  5. Pass these functions as attributes to your directive
  6. After dealing with all UI related issues, your directive will execute the appropriate callbacks
  7. The callbacks in the controller's scope will call DataService to take the appropriate action such as: Delete the comment, Save the comment
  8. This way you can avoid calling the service directly from the directive and have it only deal with UI issues.
  9. Here's how to pass a function to the directive: Passing a function as an attribute to a directive
Community
  • 1
  • 1
Sid
  • 7,511
  • 2
  • 28
  • 41