How to bind an Angular's controller function using javascript - 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.

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.

Define all functions on $scope?

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.

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.

Is ng-init truely a bad way set variable in view without controller

I am using ui-select to create a complex page with multuple views. For those that don't know each view is loaded via ajax when a user selects a tab (or in my case a dropdown). Views traditionally have their own controller and html templet. Views inherrit the scope of the parent page they are on, but have their own child scope.
In my case some of our views have no controller at all. They are so simple that we only have html pages for them. The problem is that I would like them to be able to toggle a boolean on a configuration object on the parent page's scope, to turn off on on some control fields on the parent page. Everything already exists, multiple pages use these views, I simply want to expand them to toggle something on the parent.
I could do this in three ways. I could in my ui-router use the resolve method to explicitly toggle the field I want when the view is loaded, but then I have to do this in each ui-router for each page explicitly; no cool code-reuse.
I could have my ui-router load a controller, where currently I have no controller, and the controller could do this. However, this means manually adding a controller that is mostly unneeded everywhere I use the view, and again doesn't feel like code reuse.
Or I could use ng-init to have my view's explicitly set the value I want at load time. To me this feels cleanest and easiest, since I don't already have a controller.
However, ng-init is frowned on, and should only be used for aliasing supposedly. Is there a cleaner approach then using the ng-init? is it really bad to have a view without a controller (to be more exact they have the parent controller still, but that isn't reloaded when a new view is opened).
The fact that you don't specify controller for the route doesn't change anything. The view has its own scope, so it can be manipulated with either route controller or with directives that don't have their own scope (e.g. ngInit).
The objective of well-known remark on ngInit
The only appropriate use of ngInit is for aliasing special properties
of ngRepeat, as seen in the demo below. Besides this case, you should
use controllers rather than ngInit to initialize values on a scope
is to keep you from 'html programming'. And it doesn't have too much sense because the separation of concerns is not among Angular's virtues. Angular's habit of evaluating the code from html attributes and the way how it is used by core directives prompt you to defy it even further.
Just dont init that variables at all. ng-show="smth", ng-if="smth" works ok if 'smth' is not defined and later u change it using ng-click="smth = !smth".

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.

Categories