Determine controllerAs Syntax from the Controller - angularjs

The ng-controller directive has two ways of instantiating a controller. Vanilla and controller as syntax. How can a controller determine which way it was invoked and adjust its behavior accordingly?
For example:
<div ng-controller="myController" >
<p> {{message}} World </p>
</div>
<div ng-controller="myController as myVm">
<p> {{myVm.message}} World </p>
</div>
<div ng-controller="myController as otherVm">
<p> {{otherVm.message}} World </p>
</div>
How can I make this work in my controller?
angular.module("myApp").controller("myController", function($scope) {
function usesClassSyntax() {
//what do i put here?
return true/false
};
if (usesClassSyntax()) {
var vm = this;
} else {
var vm = $scope;
};
vm.message = "Hello";
});

by using controller as syntax we just create a new variable in our scope..
angular.module("myApp").controller("myController", function($scope) {
function usesClassSyntax() {
//i think this will help
if (typeof $scope.myVm != 'undefined')
return true;
else
return false
};
if (usesClassSyntax()) {
var vm = this;
} else {
var vm = $scope;
};
vm.message = "Hello";
});

Related

Communication Between Two Controllers; References vs Primatives

I have seen an unexpected behaviour in Angularjs with its factories.
I used a factory to communication between two controllers.
In the first scenario it is working fine but not in second one. The only difference between them is that in first example I am accessing the name from the view but in second one I am accessing in scope variable.
Scenario 1
<div ng-controller="HelloCtrl">
<a ng-click="setValue('jhon')">click</a>
</div>
<br />
<div ng-controller="GoodbyeCtrl">
<p>{{fromFactory.name}}</p>
</div>
//angular.js example for factory vs service
var app = angular.module('myApp', []);
app.factory('testFactory', function() {
var obj = {'name':'rio'};
return {
get : function() {
return obj;
},
set : function(text) {
obj.name = text;
}
}
});
function HelloCtrl($scope, testFactory) {
$scope.setValue = function(value) {
testFactory.set(value);
}
}
function GoodbyeCtrl($scope, testFactory) {
$scope.fromFactory = testFactory.get();
}
Scenario 2
<div ng-controller="HelloCtrl">
<a ng-click="setValue('jhon')">click</a>
</div>
<br />
<div ng-controller="GoodbyeCtrl">
<p>{{fromFactory}}</p>
</div>
//angular.js example for factory vs service
var app = angular.module('myApp', []);
app.factory('testFactory', function() {
var obj = {'name':'rio'};
return {
get : function() {
return obj;
},
set : function(text) {
obj.name = text;
}
}
});
function HelloCtrl($scope, testFactory) {
$scope.setValue = function(value) {
testFactory.set(value);
}
}
function GoodbyeCtrl($scope, testFactory) {
$scope.fromFactory = testFactory.get().name;
}
The difference is:
Scenario I
$scope.fromFactory = testFactory.get();
<div ng-controller="GoodbyeCtrl">
<p> {{fromFactory.name}}</p>
</div>
The $scope variable is set to testFactory.get() which is an object reference. On each digest cycle the watcher fetches the value of the property name using the object reference. The DOM gets updated with changes to that property.
Scenario II
$scope.fromFactory = testFactory.get().name;
<div ng-controller="GoodbyeCtrl">
<p>{{fromFactory}}</p>
</div>
The $scope variable is set to testFactory.get().name which is a primative. On each digest cycle, the primative value doesn't change.
The important difference is that when a reference value is passed to a function, and a function modifies its contents, that change is seen by the caller and any other functions that have references to the object.

Factory value not updated in model ...what I am doing wrong?

I am new to angular-js. I have two controllers (welcomeContoller,productController) and both handling the same model within the factory.
When the model getting updating by one controller(productController) it should reflect the update in another controller. (welcomeContoller)
But its not happening now.
HTML code :
<body ng-app="myApp">
<div ng-controller="welcomeContoller">
{{totalProductCnt}}
</div>
<div ng-controller="productController">
<div class="addRemoveCart">
<span class="pull-left glyphicon glyphicon-minus" ng-click="removeProduct()"></span>
<span class="pull-right glyphicon glyphicon-plus" ng-click="addProduct(1)"></span>
</div>
</div>
JS code
var myApp = angular.module("myApp", ['ui.bootstrap']);
myApp.factory("productCountFactory", function() {
return {
totalProducts:0
};
});
myApp.controller("welcomeContoller", function($scope, productCountFactory)
{
$scope.totalProductCnt = productCountFactory.totalProducts;
});
myApp.controller("productController", function($scope, productCountFactory) {
$scope.addProduct = function() {
productCountFactory.totalProducts++;
alert(productCountFactory.totalProducts);
};
$scope.removeProduct = function() {
if(productCountFactory.totalProducts >=1)
productCountFactory.totalProducts--;
alert(productCountFactory.totalProducts);
};
});
Even after the addProduct is called the totalProductCnt is displaying as zero. I want to display the value for each increment.
Plunkr Link
Put the factory object reference on scope:
myApp.controller("welcomeContoller", function($scope, productCountFactory) {
$scope.productCountFactory = productCountFactory;
});
Watch the property of the object.
{{productCountFactory.totalProducts}}
The DEMO on PLNKR.
By putting a reference on scope, on every digest cycle the watcher looks up the value of the property and updates the DOM if there is a change.
The totalProductCnt from your welcomeController isn't updated because it is assigned only once when the controller is created.
You can use several solutions to refresh the displayed value. Use a getter for your totalProducts in the factory :
myApp.factory("productCountFactory", function() {
var totalProducts = 0;
return {
getTotalProducts: function() {
return totalProducts;
},
addProduct: function() {
totalProducts++;
},
removeProduct: function() {
totalProducts--;
}
};
});
myApp.controller("welcomeContoller", function($scope, productCountFactory) {
$scope.getTotalProducts = productCountFactory.getTotalProducts;
});
myApp.controller("productController", function($scope, productCountFactory) {
$scope.addProduct = function() {
productCountFactory.addProduct();
};
$scope.removeProduct = function() {
if (productCountFactory.getTotalProducts() >= 1)
productCountFactory.removeProduct();
};
});
And update the view accordingly:
<div ng-controller="welcomeContoller">
{{getTotalProducts()}}
</div>
Plunkr Link

passing ng-show between two different controllers

I have a button which falls into Controller B and two block of HTML code which kind of falls under controller A...............and button falls into one block of HTML code
Example:
<div ng-controller="A">
<div ng-show="now">
<div>
<Button ng-controller="B"></Button>
</div>
</div>
<div ng-show="later">
</div>
</div>
On one button click I show up now block and later on button click of B controller I kind of hide now block and display later block.
How do I achieve this functionality?? I am not able to pass ng-show varibales between two different controller files......what should I use???
Hope this helps...!
angular.module('app', [])
.controller('A', function($scope) {
console.log('A');
$scope.state = {
now: true
};
$scope.showLater = function() {
$scope.state.later = true;
};
})
.controller('B', function($scope) {
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-controller="A" ng-app="app">
<div ng-show="state.now">
<div>
<button ng-controller="B" ng-click="showLater()">Show Later</button>
</div>
</div>
<div ng-show="state.later">LATER
</div>
<p> <pre ng-bind="state | json"></pre>
</p>
</div>
You could use a simple service that stores the state.
Example:
angular.module('mymodule').service('ActiveService', function() {
var service = {};
var status = false;
service.getStatus = function() {
return status;
}
service.toggle = function() {
status = !status;
}
return service;
})
And in your controller:
angular.module('mymodule').controller('SomeController', function(ActiveService) {
$scope.status = ActiveService.getStatus;
})
The Angularjs service is a singelton, so it will hold your values for you across different controllers, directives or pages.
Could also be used directly:
// Controller
$scope.service = ActiveService;
// Html
<div ng-show="service.getStatus()">
...
</div>
You can also achieve this by declaring the variable in $rootScope and watching it in controller A,
app.controller('A', function($scope, $rootScope) {
$rootScope.now = true;
$rootScope.later = false;
$rootScope.$watch("now", function() {
$scope.now = $rootScope.now;
$scope.later = !$rootScope.now;
})
});
In Controller B, you just change the value of now based on previous value like this on ng-click,
app.controller('B', function($scope, $rootScope) {
$scope.testBtn = function() {
$rootScope.now = !$rootScope.now;
}
});
I have implemented a button within different divs(now and later) in a plunker,
http://embed.plnkr.co/xtegii1vCqTxHO7sUNBU/preview
Hope this helps!

How to update value in one controller if the value is updated in different controller?

I have a page design in which i have attached the main controller to body:
<body ng-controller="firstController">
first
second
<input ng-model="hello" ng-disabled="xyz()">
<button id="test" ng-disabled="xyz()">test button</button>
{{hello}}
<div ng-view></div>
</body>
I load a template for default as
var mainApp = angular.module('mainApp',['ngRoute'])
.config(['$routeProvider',function($routeProvider){
$routeProvider.when('/',{
templateUrl: 'partials/first.html',
controller: 'firstTemplate'
})
I my template i a check box as:
<div>
<input type="checkbox" ng-model="check">
</div>
Now i want the button #id to be disable the check box is unchecked, now i thought of using factory as these two are in different controllers:
mainApp.factory('clientId',function(){
var flag = true;
return flag;
});
mainApp.controller('firstController',['$scope','clientId',function($scope,clientId){
//$scope.check = true;
clientId.flag = false;
$scope.xyz = function(){
if(clientId){
return true;
}else{
return false;
}
}
}])
I am able to get the value from factory, now i want to update the value of the flag from different controller(template controller) and the value should reflect in first controller too so that the state of button can be updated.
mainApp.controller('firstTemplate',['$scope','clientId',function($scope,clientId){
}])
How can i update the value from second controller and make it reflect in first controller. If it is not possible is there and alternative to achieve this?
You can solve this using two ways.
1. using $rootScope.
2. using services.
using $rootScope:
<input ng-model="hello" ng-disabled="flagtoDisable">
<button id="test" ng-disabled="flagtoDisable">test button</button>
{{hello}}
<div ng-view></div>
mainApp.controller('firstController', ['$scope','$rootScope','clientId',function($scope,$rootScope,clientId){
//$scope.check = true;
clientId.flag = false;
$scope.xyz = function(){
if(clientId){
return true;
}else{
return false;
}
}
}])
mainApp.controller('firstTemplate','$scope','$rootScope','clientId',
function($scope,$rootScope,clientId){
$rootScope.flagtoDisable = false;
if($scope.check == true){
$rootScope.flagtoDisable = true;
}
}])
using Service:
mainApp.factory('clientId',function(){
var flag = {
status:false; };
return{
setFlag : funcion() {
flag.status = true;
}
getFlag : funcion() {
return flag;
}
});
mainApp.controller('firstController',['$scope','clientId',function($scope,clientId){
//$scope.check = true;
$scope.xyz = function(){
var flag = clientId.getFlag();
return flag.status;
}
}])
<input ng-model="hello" ng-disabled="xyz()">
<button id="test" ng-disabled="xyz()">test button</button>
{{hello}}
<div ng-view></div>
mainApp.controller('firstTemplate',['$scope','clientId',function($scope,clientId){
if($scope.check== true){
clientId.setFlag();
}
}])
This code is not tested.you can follow this approaches.
Yes, You can do it by using $rootScope
The ways are.
Initialize the $rootScope in your controller
Call the first controller scope variable from second controller
if 1st controller varaiable is $scope.name
now you just call $rootScope instead of $scope in second controller
like
$rootScope.name

Using 'controller as' syntax to pass object values to parent controller

When using the $scope controller syntax, it's simple to set a value on a parent controller's object. For example
<div ng-controller="ParentController">
{{myValue.a}}
<div ng-controller="ChildController">
{{myValue.a}}
</div>
</div>
app.controller('ParentController', function($scope) {
$scope.myValue = {};
$scope.myValue.a = 1;
});
app.controller('ChildController', function($scope) {
$scope.myValue.a = 2;
});
The above outputs:
2
2
Is there a way to achieve the same functionality with the controller as syntax without referencing $scope in the child controller?
You could do it using a service, or you could do it referencing the scope.
The behavior that you are using, scope inheritance, is often referred to as an unwanted side affect. This is why isolated scopes are used with the controllerAs syntax.
In the following example you can see we achieve the same result using sharing the myValue property on the $scope along with the controllerAs syntax.
angular.module('app', [])
.controller('ParentController', ParentController)
.controller('ChildController', ChildController);
ParentController.$inject = ['$scope'];
function ParentController($scope) {
this.myValue = {};
this.myValue.a = 1;
$scope.myValue = this.myValue;
}
ChildController.$inject = ['$scope'];
function ChildController($scope) {
this.myValue = $scope.myValue;
this.myValue.a = 2;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app'>
<div ng-controller="ParentController as parent">
parent: {{parent.myValue.a}}
<div ng-controller="ChildController as child">
child: {{child.myValue.a}}
</div>
</div>
</div>
This can be accomplished without $scope using a service:
angular.module('app', [])
.controller('ParentController', ParentController)
.controller('ChildController', ChildController)
.service('valueService', ValueService);
ParentController.$inject = ['valueService'];
function ParentController(valueService) {
this.myValue = {};
this.myValue.a = 1;
valueService.setValue(this.myValue);
}
ChildController.$inject = ['valueService'];
function ChildController(valueService) {
this.myValue = valueService.getValue();
this.myValue.a = 2;
}
function ValueService() {
var storedValue;
this.getValue = function() {
return storedValue;
}
this.setValue = function(value) {
storedValue = value;
}
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app'>
<div ng-controller="ParentController as parent">
parent: {{parent.myValue.a}}
<div ng-controller="ChildController as child">
child: {{child.myValue.a}}
</div>
</div>
</div>
if you don't like to use $scope you may pass outer controller downstream, see directives communication
No, it's not possible from within ChildController.
Don't think of ControllerAs as a newer style of $scope. Each has a different use.
ControllerAs does not publish values onto scope (it actually does - via the alias, but the alias should not be assumed to be known to a child Controller since the alias is defined in the View).
I use both where needed and I use the following convention:
app.controller("ParentCtrl", function($scope){
// $scope-inherited view model
var VM = $scope.VM = ($scope.VM || {});
// controller-specific view model
var vm = this;
VM.valueVisibleToChildControllers = "foo";
vm.valueVisibleOnlyToTheView = "bar";
});

Resources