admin管理员组

文章数量:1327123

I'm trying to use some of angulars best practices defined on the google-styleguide site: .html

But at the moment I'm struggling with some issues. Before I used this styleguide I had the $scope variable available to do a $watch on a variable for instance.

app.controller('myController',['$scope', function($scope) {
    $scope.$watch('myVariable', function(val) {
       alert("I'm changed");
    });
}]);

Now with my new approach I don't know how to handle this? Should I still inject $scope? Because I do not have to inject $scope when I'm not using $watch.

function myController($scope) {
   var vm = this;

   vm.myVariable = "aVariable";
   vm.$watch('vm.myVariable', function(val) {
      // error because $watch is undefined
   });

   //$scope.$watch - works
}

app.controller('myController',['$scope', myController]);

The styleguide also advices to make use of prototypes. But what if I had to inject a service? What is the best approach to use a service inside your prototype?

function myController(MyService) {
   var vm = this;

   vm.myService = MyService;
}

myController.prototype.callService = function() {
   var vm = this;

   vm.myService.doSomething();
}

Is this correct? Or am I missing something, is there a place where I can find more information about this style of angular programming?

In my opinion it feels more like natural javascript and I want to use this way of organizing my AngularJS apps.

Thanks in advance

Update

For the 'service' problem I was thinking of something as follows:

function MyBaseController(AService, BService, CService) {
   this.aService = AService;
   this.bService = BService;
   this.cService = CService;
}

function myController() {
   var vm = this;
   MyBaseController.apply(vm, arguments);
}

myController.prototype.doSomething() {
   var vm = this;
   this.aService.somethingElse();
}

But this doesn't feel right imo..

I'm trying to use some of angulars best practices defined on the google-styleguide site: https://google-styleguide.googlecode./svn/trunk/angularjs-google-style.html

But at the moment I'm struggling with some issues. Before I used this styleguide I had the $scope variable available to do a $watch on a variable for instance.

app.controller('myController',['$scope', function($scope) {
    $scope.$watch('myVariable', function(val) {
       alert("I'm changed");
    });
}]);

Now with my new approach I don't know how to handle this? Should I still inject $scope? Because I do not have to inject $scope when I'm not using $watch.

function myController($scope) {
   var vm = this;

   vm.myVariable = "aVariable";
   vm.$watch('vm.myVariable', function(val) {
      // error because $watch is undefined
   });

   //$scope.$watch - works
}

app.controller('myController',['$scope', myController]);

The styleguide also advices to make use of prototypes. But what if I had to inject a service? What is the best approach to use a service inside your prototype?

function myController(MyService) {
   var vm = this;

   vm.myService = MyService;
}

myController.prototype.callService = function() {
   var vm = this;

   vm.myService.doSomething();
}

Is this correct? Or am I missing something, is there a place where I can find more information about this style of angular programming?

In my opinion it feels more like natural javascript and I want to use this way of organizing my AngularJS apps.

Thanks in advance

Update

For the 'service' problem I was thinking of something as follows:

function MyBaseController(AService, BService, CService) {
   this.aService = AService;
   this.bService = BService;
   this.cService = CService;
}

function myController() {
   var vm = this;
   MyBaseController.apply(vm, arguments);
}

myController.prototype.doSomething() {
   var vm = this;
   this.aService.somethingElse();
}

But this doesn't feel right imo..

Share Improve this question edited Mar 28, 2014 at 8:12 Dieterg asked Mar 25, 2014 at 10:20 DietergDieterg 16.4k3 gold badges33 silver badges50 bronze badges 8
  • Great question! For your question about the $watch, I'm wondering if the style guide is trying to avoid calling $watch within a controller since they state "Controllers are classes." Since you know when data is changing within a controller, could it be that your "$watch" is executed when a specific method is called within the controller? – Pete Commented Mar 27, 2014 at 13:50
  • Actually I want to do a $watch on a variable that's getting changed inside a directive. I think there wouldn't be a problem when you change a variable inside a method. The, let's call it scope, will get updated anyway. – Dieterg Commented Mar 27, 2014 at 13:55
  • 1 In a directive, you can access scope from Link, Compile, and Controller, so $watch is accessible in those cases. – Pete Commented Mar 27, 2014 at 14:00
  • But how do I check for updates in my controller? I know I can $watch a variable inside my directive. But how do I reflect these changes to my controller? Normally I would do an $apply in my directive and afterwards I would $watch for a change inside my controller. – Dieterg Commented Mar 27, 2014 at 14:03
  • 2 I don't think you should be changing the controller variable within the directive because then the view is modifying the model. The directive, should pass mands to the controller, so you would know when the variable is changed. Otherwise, if you need to, you could have the directive-controller fire an event that the controller is listening to and then process the change. – Pete Commented Mar 27, 2014 at 14:07
 |  Show 3 more ments

2 Answers 2

Reset to default 7 +50

It is perfectly valid to inject $scope to get access to things like $watch even when your using the "controller as" syntax. For example:

JS

var MyController = function($scope) {
    $scope.$watch('ctrl.someVar' function() {
        ...
    });

    this.someVar = 123;
}

MyController.$inject = ['$scope'];

HTML

<div ng-controller="MyController as ctrl">
    ....
</div>

The first example you gave of injecting a service into a controller is good. For the inheritance example I would do something like this.

var BaseController = function(AService, BService) {
    this.aService = AService;
    this.bService = BService;
}

BaseController.prototype.doSomethingWithAAndB = function() {
    ...
}

var MyController = function(AService, BService, CService) {
    BaseController.call(this, AService, BService);

    this.cService = CService;
}

MyController.$inject = ['AService', 'BService', 'CService'];

//Note: you'll need to add a polyfill for Object.create if you want to support ES3.
MyController.prototype = Object.create(BaseController.prototype);

If you find it is too cumbersome to specify all the parameters in the child controller you could always just inject $injector and pass that up to your base controller.

@rob answer is correct. There are perfectly valid reasons to still want $scope injected in your controllers, $watch $on $emit $broadcast to name a few. Sure you can get away with this requirement in some cases using directives or services, but it's not always worth the time or plexity.

I've given the controller as syntax a go, but found that in most of my use cases I still had a dependency on $scope in my controllers. I disliked this and so I ended up with the following convention:

var MyController = function($scope) {
  $scope.vm = {};
  var vm = $scope.vm;

  vm.propA = 1;
  vm.propB = 2;
  vm.funcA = function(){};

  $scope.$watch('vm.propA' function() {
  });
}

So it uses the 'old school' approach but with a new school feel. Everything in the view hangs off vm.

本文标签: javascriptAngularJS best practicesStyleguideStack Overflow