Define all functions on $scope? - javascript

This is a very basic question. I have a function on one angularjs controller that does stuff. I don't need to use it directly from the view. No other controller needs this function, eliminating the need to define it on a service. Seems to me this does not need to be defined on $scope. It can just be,
function doStuff() {
// stuff done
}
Does convention dictate that I define all such simple functions on $scope?

No, only methods which serve some UI interaction purpose.

I would say no. It's simply a reusable function that you would define within the scope of the controller. If it's only used within, there's no need to muddy up your $scope with functions not being used with your user interface.

Related

initialize a scope variable with angularJs

I'm always using ng-init="controllerFunction()" to get data from the server and display it on a table, chart or anything else and it needs to get called on every page loading.
Now using ng-init is doing the job but is it the best practice ?
ng-init is mainly used to pass data to an init method, for example razor data (ng-init="someControllerFunction(#Model.ServerSideData)). If you don't pass any data you can just do it directly in your controller:
function myCtrl($scope) {
function myInitFunction(){
// fetch data etc.
}
myInitFunction();
}
This way you don't expose the init function and is nicely encapsulated inside your controller.
The documentation clearly states (in a big red alert) that ngInit has only a few focused use-cases, and should not be used outside of these scenarios
This directive can be abused to add unnecessary amounts of logic into
your templates. There are only a few appropriate uses of ngInit, such
as for aliasing special properties of ngRepeat, as seen in the demo
below; and for injecting data via server side scripting. Besides these
few cases, you should use controllers rather than ngInit to initialize
values on a scope.

Do all methods in Angular controllers have to be on `$scope`?

So many controllers I see have no members except for this on scope. I would imagine shared validation and business logic code never accessed directly from a binding expression need not know about the non-scope code, and only members accessed from the view actually have to be on the scope.
Could someone please clear this up for me?
That's right. Functions available to your expressions in the partials and directives should be assigned to the $scope object.
All your other logic does not have to be. If you're planning to reuse any logic between controllers it is better to extract it into a factory/service.
$scope is what binds the controller to the view; it is a special prototypical object that can be dynamically adjusted, making it very easy to quickly hook up to the view. However, using $scope directly isn't the only way to handle your controllers.
Due to the prototypical nature of $scope, and the fact that there can be multiple scopes present on a given page, it's been commonly suggested to follow the "Dot Rule" when dealing with $scope. In essence, the dot rule simply suggests that instead of assigning primitives to $scope, e.g. $scope.myString, it's always preferable to "use a dot", or, assign objects to the $scope, a la $scope.someObject.myString.
Starting with angular 1.2, a new syntax was introduced which is designed to help with this task, the ControllerAs syntax. In essence, it allows you to assign your controller (which is already an object) directly to the $scope, using a syntax like ng-controller = "someController as ctrl", and then refer to all of your bindings as properties of the controller, a la ctrl.myString. You are now automatically using the "Dot Rule", without even having to think about it.
app.controller('someController', function () {
var ctrl = this; //self reference for this
ctrl.myString = 'Some title';
});
Note that even though we are still ultimately using $scope, we don't actually need to provide $scope as a dependency on the controller, and don't need to interact with it directly. However, it is still available, should we need to use an advanced service like $broadcast.
Using the ControllerAs syntax does not eliminate $scope, because the controller is still a property of $scope, but it does allow you to break the coupling between your controller and scopes down a bit, and can make your HTML / controllers easier to read. having customerCtrl.name and companyCtrl.name is much easier to understand than having two name properties which are only really understood in context of the surrounding elements.
Unfortunately, the vast majority of documentation and tutorials still use the $scope object directly, and migration to the ControllerAs syntax has been slow. However, $scope will not exist in angular 2, and the first step to migrating from 1.x to 2.x will be to convert to the ControllerAs syntax, so if you write your code this way now, it will make it trivial to migrate.
There can be methods in controllers that are not in $scope also (May be you'll be using them as helper methods that'll be calling from $scope methods). Normally methods you wanted to call my view or variable that needed to be bind to view are kept in $scope.

Angularjs - create globally accessible (accessible in templates too) function in a module

We want to create a reusable library/module for our ACL functionality. Basically, to check if the logged-in user has access to the particular UI resource and also has permissions to perform actions like click etc... So, we want to expose a hasAccess() function which can be called from inside directives like - ng-show, ng-hide, ng-disabled etc...
We explored few options like angular-acl (https://github.com/mikemclin/angular-acl). With this solution, in every controller, we need to add a line like this: $scope.can = AclService.can; which is bit pain, given that we are having many controllers in our application.
So, was exploring on what is the best way this can be achieved? Is there a way we can export global functions from inside our module service, so that the same is accessible in every template?
Some of the solutions we found was to write code inside module.run() method, and set $rootScope.fn = . But, can we write a run() for a module that is being shared as a library? Is this valid, and if yes, then, when exactly will this run() be called is not clear.
Any idea, what is the best practice solution for such a scenario, where we want to expose a global method/function from inside a service, such that the same can be accessed in templates?

In AngularJS, what's the difference between $scope and the native context?

I'm just starting to look at Angular, but having a hard time wrapping my head around the need for $scope. Javascript already has a concept of scope via the context (i.e. this) and allows programmers to inject that context on a function using call or apply.
Are there any differences between Angular's, $scope, and the keyword this?
If there is a difference, then what is the value of this within a controller or directive?
Thanks in advance :)
Yes, they are not the same at all. The constructor is just an instantiated new ed constructor (the function you wrote) created by the injector.
$scope is more conceptually related to the DOM. In that elements with ng-controller get that $scope and child elements do as well. If a child element with its own scope (controller/directive) had the same properties as the parent scope You wouldn't be able to access them. It also has all of the internal information angular uses in its digest loop (dirty checking/ data binding) like watches,events,etc. I'd have a read through this
As for the myCtrl as syntax, this is nice but all it really does is put the controller instance onto the scope. With the name that you set.
eg myCtrl as foo is basically $scope.foo = myCtrlInstance;. Which you are capable of doing in your controller as well.

How to bind an Angular's controller function using javascript

Is there a way in AngularJS to programmatically bind a controller method using only javascript(instead of using ng-* markup)?
Something like
$("#foo").click(FooController.foo)
PS: I don't have access to $compile
Do you really need controller's methods or scope's?
in case if you need scope's you can use angular.element('#myid').scope().method
But please keep in mind that any modification of scope's values are not detected if you do them outside of AngularJS event processing, so you need to wrap your code into $apply function of scope.
Also keep in mind that in AngularJS DOM modifications from JS are generally "big no no"
Ofcourse there are controller's functions (created using "this.xxx = function () .."). I am not sure that it is good to access them as they are kind of private, but you should be able to access same way: element(..).controller().method
It is not officially supported. For sure it is technically possible with some hacks but binding event handlers from JavaScript would mean getting access to a DOM element from a controller and it goes against principles of AngularJS.
To extend #Valentyn's answer somewhat, if you had wanted to access a controller method (and not a $scope method) -- e.g., a method defined with this in the controller constructor function (on the Angular homepage, the "tabs" directive defines function "addPane" on the controller using this) -- you can use
angular.element('#myid').controller().method()
You can, but you shouldn't. You'll likely run into trouble down the road.
If you can give a bit more explanation as to why you want to do this, there might be a better (and easier) method.

Categories