0

I got a directive that loads a different template depending on the variable type that is passed to it. I pass to the isolated scope of the directive the variables patient and service too.

.directive('serviceCharts', serviceCharts);

function serviceCharts() {
  return {
    restrict: 'E',
    link: function (scope, element, attrs) {
      if(attrs.type) {
         scope.template = 'views/' + type + '.html';
    }
    attrs.$observe('type', function (type) {
      if(attrs.type) {
        scope.template = 'views/' + type + '.html';
      }
    });
  },
  template: '<div ng-include="template"></div>',
  scope:{
    patient:'=',
    service:'='
  }
};

}

In the template (views/myservice.html for example) I load the controller:

 <div ng-controller="myCtrl as vm"> 
     VIEW
 </div>

And in the controller (myCtrl) I access to the patient and service this way:

  service = $scope.$parent.$parent.service;
  patient = $scope.$parent.$parent.patient;

This works fine, but I don't like this way of accessing the variables via the $parent.$parent. This is messing with my tests too.

Is there another (better) way to do this?

Thank you!

2 Answers 2

1

You could create a wrapper object for patient & service properties. That can be named as model & then provide that model object to your directive.

Then problem with your current approach is, ng-include create a child scope for template which it renders in it. So as your passing primitive type object binding to directive, If you are changing any of child primitive type binding in child scope. It loses a binding that's why tend to using $parent.$parent notation exactly bind to original source object.

$scope.model = {
  patient:'My Patient',
  service:'My Service'
};

By making above object structure will ensure you're following Dot Rule. Usage of Dot Rule will avoid $parent.$parent explicit scope annotation.

Directive scope binding will changed down to below

scope:{
   model:'='
}

And directive usage will look like below

<service-charts type="{{'sometype'}}" model="model"></service-charts>


The other alternative than Dot Rule to such kind of scoping related issue is follow controllerAs pattern. But then as you are gonna use isolated scope with controllerAs you should make bindToController: true option to true for making sure all the scope are merged down to controller context.

scope:{
    patient:'=',
    service:'='
},
controllerAs: '$ctrl',
bindToController: true

And then use $ctrl before each directive scoped variable.

Sign up to request clarification or add additional context in comments.

5 Comments

Thank you so much for your answer. I didn't know the "bindToController: true", this looks prominsing! I'm aware that ng-include is not a good solution, but i need a dynamic controller too, changing for the different "type", and the "controller" option of the directive doesn't allow me to use an expresion. Do you know how could I change the controller depending on the "type" variable?
Could you provide me a pluker.. suggested solution should work AFAIK
Thanks, I'm on it :)
Ok, my code now is something like this: plnkr.co/edit/ryuBp6UjH4xBHlRm8lYf?p=preview Can you do something to improve the way I pass the variables and define the controller (so I can remove the ng-include) but with the controller depending on the value of type? Thanks!
Sorry, I pressed the Enter key before I could finish :)
0

Yes, there is a better way to do this. You should use services and store variables in those services (in your case you should create a factory for storing data). Then you can inject those services and access their data.

Sidenote: You can use { ..., controller: 'controllerName', controllerAs: 'vm' } syntax in your directive so you do not need to declare those in your html.

2 Comments

Thanks for your answer. You're right, services are the way to store this variables, but at least I need the ids of the "patient" and "service" that I got from the route. And you are right about the controller: and controllerAs too, but can I make these dynamic changing with the value of "type"?
@Luisma depends on what sets those templates. In most of the cases I would suggest using a router which would display different templates based on a route. Also, as Pankaj mentioned, a plunker would really help.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.