Angularjs "Controller As" or "$Scope"

Angularjs Controller as or $scope

I've written a few answers to this question in the past, and they all essentially boil down to the same thing. In Angular, you are using $scope, even when you aren't expressly referencing it.

The ControllerAs syntax allows Angular to help you to write more efficient, fault tolerant controllers. Behind the scenes, when you use ng-controller="theController as ctrl", Angular creates theController as a property on $scope and assigns it as ctrl. You now have an object property you are referencing from scope, and are automatically protected from prototype inheritance issues.

From a performance perspective, since you are still using $scope, there should be little to no performance difference. However, since your controller is now not assigning variables directly to $scope on it's own, it does not need to have $scope injected. Also, the controller can much more easily be tested in isolation, since it is now just a plain JavaScript function.

From a forward thinking perspective, it's well known by now that Angular 2.0 will not have $scope, but instead will use features of ECMAScript 6. In any previews released by the Angular team showing migrations, they first begin by refactoring the controller to eliminate $scope. If your code is designed without the use of $scope based controllers, your first step in a migration is already complete.

From the designer's perspective, the ControllerAs syntax makes it much clearer where objects are being manipulated. Having customerCtrl.Address and storeCtrl.Address makes it much easier to identify that you have an address assigned by multiple different controllers for different purposes than if both used $scope.Address. Having two different HTML elements on a page which both are bound to {{Address}} and knowing which one is which only by the controller the element is contained in is a major pain to troubleshoot.

Ultimately, unless you are trying to spin up a 10 minute demo, you really should be using ControllerAs for any serious Angular work.

AngularJS : access scope object from parent to child

You can use angular $q service

Using promises and $q to handle asynchronous calls

var app = angular.module("MY_APP", []);
//Parent Controller
app.controller("MyCtrl1", [
'$scope','$q','$timeout', function($scope,$q,$timeout) {

$scope.async = function(name) {
var deferred = $q.defer();
//Async call: Use your ajax call here instead of $timeout
/*
$http.get('/someUrl')
.success(function(data) {
$scope.myVar = 'xyz';
deferred.resolve(data);
}).error(function(msg, code) {
deferred.reject(msg);
$log.error(msg, code);
});
*/
$timeout(function() {
deferred.notify('About to greet ' + name + '.');
if (name) {
deferred.resolve('Hello, ' + name + '!');
} else {
deferred.reject('Greeting ' + name + ' is not allowed.');
}
}, 1000);
return deferred.promise;
}
}]);
//Child Controller
app.controller("MyCtrl2", [
'$scope','$q', function($scope,$q) {
// call parent async method
var promise = $scope.$parent.async('Sai');
promise.then(function(greeting) {
//check your variable here
/*
console.log($scope.$parent.myVar);
*/
alert('Success: ' + greeting);
}, function(reason) {
alert('Failed: ' + reason);
}, function(update) {
alert('Got notification: ' + update);
});

}]);

Fiddle example

var vs this vs $scope in AngularJS (1.4)

The keyword var is pure javascript and is just how you declare variables in javascript. Like so:

var myName = 'Nikolaj';
var myAge = 1700;
// etc.

If you're unfamiliar with var you should start by learning Javascript before venturing into Angular, since the learning curve of Angular can be quite steep.

With that said I'll try to explain the other concepts.

Using controllerAs

When using the recommended controllerAs syntax, you get a reference to the controller instance in your template. This is what happens when you use <div ng-controller="myController as ctrl"></div>;

Your controller is basically "newed" and stored in a variable called ctrl which is made available in the template by angular. This allows you to access your controller members (public functions and variables) in the template like this:

<div ng-controller="myController as ctrl">
<p>{{ctrl.name}}</p>
</div>

In order for the variable name to be available in the template, it must first be declared as a public member/variable of your controller. That is where the this-keyword comes into play. When you create your controller, to make the variable name public, you'd do it like this:

angular.module('app').controller('myController', function(){
this.name = 'My name variable';
});

Here this is a special concept in Javascript that is a reference to the function context - but just basic Javascript.

Using $scope

When you instead use your controller like this: <div ng-controller="myController"></div> you don't have direct access to the controller instance in your template. Instead, every time you use something in an Angular expression, for instance {{name}}, Angular implicitly assumes the variable name exists on the $scope variable. Each controller has a $scope variable associated with it when it is linked to the template. To access this variable inside your controller body, you'll access it like this:

angular.module('app').controller('myController', function($scope){
$scope.name = 'My name variable';
});

The reason why the controllerAs syntax is recommended, is in part because when using $scope, it can be difficult to determine which scope you're referring to when you have multiple nested scopes (i.e. nested controller). As in this example:

<div ng-controller="FirstController">
<h1>{{firstControllerVariable}}</h1>
<div ng-controller="SecondController">
<h2>{{whereDoIBelong}}</h2>
</div>
</div>

With the controllerAs syntax, it is pretty clear which variable belongs to which controller:

<div ng-controller="FirstController as first">
<h1>{{first.firstControllerVariable}}</h1>
<div ng-controller="SecondController as second">
<h2>{{second.iKnowWhereIBelong}}</h2>
</div>
</div>

Another reason to use the controllerAs syntax is because it'll make it easier to migrate to ES2016 and above.

AngularJS 'controller as' and form.$valid

You could do as @ons-jjss suggested but if you prefer not to inject $scope into you controller, then just change your form name as

<form name="main.contactForm" novalidate>

and it'll work like a charm.

How to get data from Angularjs Service Response to Controller Scope Object

There is no need to manufacture a promise with $q.defer as the $http service already returns a promise:

app.factory('websiteService', function ($http, $q) {
var factory = [];
̶v̶a̶r̶ ̶d̶e̶f̶e̶r̶r̶e̶d̶ ̶=̶ ̶$̶q̶.̶d̶e̶f̶e̶r̶(̶)̶;̶
var baseURI = 'http://localhost:59029/api';

factory.getAllStudents = function () {
return $http({
method: 'GET',
url: baseURI + '/Website/GetAllStudents'
}).then(function (response) {
return response.data;
});
}
return factory;
});

For more information see Is this a "Deferred Antipattern"?

In Angular JS, $scope object approach of controller creation?

Finally I have the exact answer for which I am looking for

In AngularJS 1.2, the “controller as” syntax was introduced, and made controller code creation more readable.

Usually we create a controller using the $scope object as shown in the listing below:

myApp.controller("AddController", function ($scope) {
$scope.numb1;
$scope.numb2;
$scope.result;
$scope.add = function () {
$scope.result = $scope.numb1 + $scope.numb2;
}
});

Above we are creating the AddController with three variables and one behaviour, using the $scope object controller and view, which talk to each other. The $scope object is used to pass data and behaviour to the view. It glues the view and controller together.

Essentially the $scope object performs the following tasks:

  1. Pass data from the controller to the view

  2. Pass behaviour from the controller to the view

  3. Glues the controller and view together

  4. The $scope object gets modified when a view changes and a view gets modified when the properties of the $scope object change

    We can rewrite the above controller using the controller as syntax and the vm variable as shown in the listing below:

    myApp.controller("AddVMController", function () {
    var vm = this;
    vm.number1 = undefined;
    vm.number2=undefined;
    vm.result =undefined;
    vm.add = function () {
    vm.result = vm.number1 + vm.number2;
    }

    });

Essentially we are assigning this to a variable vm and then attaching a property and behaviour to that. On the view we can access the AddVmController using controller as syntax. This is shown in the listing below:

<div ng-controller="AddVMController as vm">

<input ng-model="vm.number1" type="number" />

<input ng-model="vm.number2" type="number" />

<button class="btn btn-default" ng-click="vm.add()">Add</button>

<h3>{{vm.result}}</h3>

</div>

Here are some steps to use the controller as syntax:

  1. Create a controller without $scope object.

  2. Assign this to a local variable. I preferred variable name as vm, you can choose any name of your choice.

  3. Attach data and behaviour to the vm variable.

  4. On the view, give an alias to the controller using the controller as syntax.

  5. You can give any name to the alias. I prefer to use vm unless I’m not working with nested controllers.

In the controller as syntax, we have more readable code and the parent property can be accessed using the alias name of the parent controller instead of using the $parent syntax.

I will conclude this by saying that it’s purely your choice whether you want to use the controller as syntax or the $scope object. There is no huge advantage or disadvantage to either, simply that the controller as syntax you have control on the context is a bit easier to work with, given the clear separation in the nested controllers on the view.

Does $scope is automatically injected to controller in Angular js?

You have a couple different things going on.

First, you need to bind the app in some way to the DOM, in this case you named your module docsSimpleDirective so you need to add ng-app="docsSimpleDirective a the same level or above your controllers

<!-- added ng-app="docsSimpleDirective" -->
<div ng-app="docsSimpleDirective" ng-controller="Controller">
<input type="text" ng-model="fname">
<span ng-bind="fname"></span>
</div>

Second, you are using the array annotation for defining dependencies which is good. You will run into problems if you don't do this and you try to uglify your code. The way you currently have it bound you do not pass $scope to the controller you are passing $http with the name $scope.

angular.module('docsSimpleDirective', [])
.controller('Controller', ['$scope', function($scope) {
// Not ['$http', function($scope)....
$scope.fname = 'Foo Bar';
}])

If you want to pass $scope and $http to the controller it would be defined like this.

.controller('Controller', ['$scope','$http', function($scope,$http) { 

In short you could do .controller('Controller', ['$scope','$http', function(foo,bar) { ... and foo would equal $scopeand bar would equal $http. This is done so that when the code is uglified and uglifiery will not change the literal strings for $scope and $http so the references will not be broken.

Here is a working Fiddle



Related Topics



Leave a reply



Submit