I'm implementing an AngularJS directive on Angular 1.4.12 using the controllerAs and bindToController "pattern" in order to have a clean controller which doesn't depend on $scope.
However I still find hard to get rid of $scope on these lines:
$scope.$on( '$destroy', function() {...} );
$scope.$on( '$stateChangeSuccess', function() {} );
Any idea how to handle this case?
Thanks
The idea behind not using $scope is to:
not pollute the HTML with variables that have no context and potentially have conflicting variable names in the same scope.
ng-model="name" VS ng-model="userController.user.name"
not pollute you javascript code by preceding every variable and
function with $scope
If you need to broadcast events or watch changes, it's perfectly fine to use $scope (especially if you have no alternative like .components in angular 1.5)
See $scope as a service provided to you by Angular just like $window or $state.
If you need it, you can use it. (but don't go and put code in there, even if you can)
Related
What is the disadvantage of using the $scope as variable in AngularJS, to share $scope of a controller inside the app.run()?
Actually I am doing that to make code generic to be called from all the controllers with same function in app.run().
The function I am using is with the
$rootScope.getUserInfo = function($scope){
$scope.userinfo = '---------';
}
where $scope is the variable that I am passing from every controller like that
$rootScope.getUserInfo($scope);
I don't think there's inherently something wrong with passing around a scope. People do this a lot in AngularJS services and it's internally done a lot, too: your created controller is passed a scope to work with.
However, I would say it's not necessary in your example to have getUserInfo to depend on a scope being passed. Why not return the user information and have the caller put it on the scope? That way, you can use it in parts of your app that don't have a scope.
Instead of using $scope, you can use var vm = this; and define everything in that controller with vm.variablename_or_funcname instead of $scope.variablename_or_funcname
And you can attach that controller in html like ng-controller = "mycontroller as vm"
More info:
https://johnpapa.net/angularjss-controller-as-and-the-vm-variable/
I have a fairly straightforward AngularJS question to which I cannot seem to find an answer:
How would I go about using $scope.$watch() in a directive controller while also using the controllerAs and bindToController options?
Please let me know if you need any clarification on what I mean exactly.
Well, $scope.$watch watches for expressions so assuming you're binding your controller to the name vm (e.g. controllerAs: 'vm') you should use
$scope.$watch('vm.somethingToWatch', function(newval, oldval) {...})
You will need to still inject the $scope though, since $watch is not available on controller instances by themselves.
In an AngularJS app, I have a service that uses $http and returns a promise. I have a controller which requires the service. In the controller DataService.then(function(data){ scope.viewModel.data = data;})
Then I have a directive with isolate scope.
scope: { data: '='} then do something with scope.data inside the directive.
Finally the html
<div ng-controller="myCtrl">
<div my-cool-directive="" data="viewModel.data"></div>
</div>
My question is this presents a chicken before the egg scenario. When the service data is hard coded, all is well and glorious, however when using async $http to actually call a server and get data, scope.data is null inside the directive. How can I properly get the directive the data it needs when the service call finishes and the controller scope property is set. I do not want the directive to have a dependency on the service. I prefer that the controller will drive the directive model. Is $emit or $broadcast the way to go and use a $watch? Basically eventing? or is there a preferred way to do this? I'm certain others have faced this exact issue. I would like the directive to continue to have isolate scope as I may want to extend at some point. I did try to Google first but I don't think I was phrasing the question correctly.
<div my-cool-directive="" data="viewModel.data" ng-if="viewModel.data"></div>
should do the trick.
You could also create a watch in the directive, so that the callback function of the watch is called when the data changes from undefined to something else.
I know that I should keep my controllers lean & mean, but if I do need a variable which will not be reflected in the view, should I declare it in $scope. or as var?
I declare them as var if I dont need two-way binding. When you put your data into $scope, you put a watch on them (and with this put it in the angular digest cycle) and that's redundant if you dont need to use the variable in the view. Simple rule: Don't use $scope if you dont need angular to update the view with it.
I am looking at some samples of how controllers work in angular and I see two ways of declaring them, one with just controller name and one with "as somename". Examples that use ng-controller = "myController" take a $scope as dependency when defining controller.
Then model is then set on the $scope, something like this
$scope.mymodel = somevalue;
Example that uses "as" syntax such as ng-controller = "MyControler as vm" never uses $scope when setting up the model but ratther assigns it to "this" and binds using {{vm.something}}.
in controller:
var vm =this;
vm.something = somevalue;
How is that working in second example? Is that new way in latest version?
Using the "as" syntax exposes your entire controller to your view. In my opinion, that is a bad practice. Although I'm not sure which one is better performance wise, but using 'this' in javascript already has plenty of issues of its own, and I don't recommend adding another meaning to 'this'. So I would stick to $scope (since that is what they're using in the docs as well).
See this topic if you want to know more context about how the 'as' syntax work: 'this' vs $scope in AngularJS controllers