can i inherit a parent controller's variables? - angularjs

Here is my code:
function ParentCtrl($scope) {
$scope.people = ["Tom", "Dick", "Harry"];
$scope.count = $scope.people.length;
}
function ChildCtrl($scope) {
$scope.parentpeople = ParentCtrl.people //this is what I would like to do ideally
}
I am nesting one angular controller inside of another one. I would like to pass variables of the first controller to the second one. Does anyone know how to do this?
NOTE
I cannot do something like
ChildCtrl.prototype = new ParentCtrl();
because I will overwrite the people property of the ChildCtrl.

By default, child scopes prototypically inherit from the parent scope (see Scope), so you already have access to the parent controller's $scope properties in the child. To prove it:
function ChildCtrl($scope) {
alert($scope.people)
}

You're getting things wrong. You are mixing controller inheritance with scope inheritance, and they are different and loosly coupled in AngularJS.
What you actually want is:
function ParentCtrl($scope) {
$scope.people = ["Tom", "Dick", "Harry"];
$scope.count = $scope.people.length;
}
function ChildCtrl($scope) {
$scope.parentpeople = $scope.$parent.people;
}
And it will work for the case:
<div ng-controller="ParentCtrl">
<div ng-controller="ChildCtrl">
</div>
</div>
But as Mark and ganaraj noticed above, this has no sense, as you can access your property of $scope.people from both
ParentCtrl and ChildCtrl.
If you want to inherit controllers from each other, you need to use prototype inheritance of controller functions themselves.

The $scope inheritance is based upon where you reference your controllers using ng-controller.
If you have something like
<div ng-controller="ParentController">
<div ng-controller="ChildController">
</div>
</div>
Then yes, the child controller will inherit the properties of the parent controller.
Note : The child controller need not be defined on the direct child in the html. It can be any child within.

Also you can get the Scope of any controller by DOM:
$needleScope = angular.element(aDomElement).scope()
Using jQuery:
$needleScope = $('#aDomElementId').scope()
Or get all Scope in the document:
$allScopes = $('.ng-scope').scope()

It might help you!!!
Scope is a special JavaScript object that connects controller with views. Scope contains model data. In controllers, model data is accessed via $scope object.
<script>
var mainApp = angular.module("mainApp", []);
mainApp.controller("shapeController", function($scope) {
$scope.message = "In shape controller";
$scope.type = "Shape";
});
</script>
Scope Inheritance
Scope is controller-specific. If we define nested controllers, then the child controller inherits the scope of its parent controller.
<script>
var mainApp = angular.module("mainApp", []);
mainApp.controller("shapeController", function($scope) {
$scope.message = "In shape controller";
$scope.type = "Shape";
});
mainApp.controller("circleController", function($scope) {
$scope.message = "In circle controller";
});
</script>
Live example as give below.
<html>
<head>
<title>Angular JS Forms</title>
</head>
<body>
<h2>AngularJS Sample Application</h2>
<div ng-app="mainApp" ng-controller="shapeController">
<p>{{message}} <br/> {{type}} </p>
<div ng-controller="circleController">
<p>{{message}} <br/> {{type}} </p>
</div>
<div ng-controller="squareController">
<p>{{message}} <br/> {{type}} </p>
</div>
</div>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js"></script>
<script>
var mainApp = angular.module("mainApp", []);
mainApp.controller("shapeController", function($scope) {
$scope.message = "In shape controller";
$scope.type = "Shape";
});
mainApp.controller("circleController", function($scope) {
$scope.message = "In circle controller";
});
mainApp.controller("squareController", function($scope) {
$scope.message = "In square controller";
$scope.type = "Square";
});
</script>
</body>
</html>

Related

angularjs dom manipulation based on button click

basically i want to change the attribute value based on the button i clicked,
these are the two buttons
<button ng-click="fn(a)"></button>
<button ng-click="fn(b)"></button>
and then i have a prebuilt directive who takes value as input,
<div directive-name="" id="abc"></div>
if i click on first button,i want the value of directive based on button clicked.
What i did earlier;
$scope.go = function(data){
if(data==a){
var b = document.querySelector( 'div' );
b.setAttribute("directive-name","value");
}
else{}
}
here the problem is that it is selecting the first div of document and setting attribute value for that.
I also tried to pass it with id like
var b = angular.element(document.querySelector('#abc'));
I also saw some custom directives to do so, but they are not working
AngularJS DOM Manipulation through Directives
If possible provide me a demo in plunkr or fiddle
and also if i want to change css property of div based on button clicked
Thanks in advance
You can do it like this.
Assign the directive-name value to a $scope.variable and then use variable as the value in HTML.
HTML - 1:
<button ng-click="go(a)"></button>
<button ng-click="go(b)"></button>
HTML - 2:
<div directive-name="{{directive}}" id="abc"></div>
JS:
$scope.go = function(data){
if(data==a){
$scope.directive = "directive-1";
}else if(data==b){
$scope.directive = "directive-2";
}
}
To assign class name to div you can define other $scope.classVar and then use that in HTML like below:
<div directive-name="{{directive}}" id="abc" ng-class="classVar"></div>
I hope this will solve your problem.
This should work, (you had some errors in your code):-
var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
$scope.fn = function(data,id) {
if (data == 'a') {
var b = document.querySelector('#'+id);
b.setAttribute("directive-name", "value");
} else {
}
}
});
<!DOCTYPE html>
<html>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<body>
<div ng-app="myApp" ng-controller="myCtrl">
<div directive-name="" id="abc"></div>
<button ng-click="fn('a','abc')">A</button>
</div>
"Basically I want to change the attribute value based on the button I clicked."
You can do this by changing the attribute value the angular way, referencing a property of $scope or the controller instance in your template. When clicking a button, set the variable to the value you require to be passed to your directive.
Note: When you pass a value into your ngClick directive, you need to pass it as a string unless a and b are declared as properties of $scope.
Here's a basic example:
// app.js
(function() {
'use strict';
angular.module('app', []);
})();
// main.controller.js
(function() {
'use strict';
angular.module('app').controller('MainController', MainController);
MainController.$inject = ['$scope'];
function MainController($scope) {
$scope.fn = fn;
function fn(data) {
// set the value so it's accessable in the view
// therefore we can pass it into our directive
$scope.myVar = data;
}
}
})();
// directive-name.directive.js
(function() {
'use strict';
angular.module('app').directive('directiveName', directiveNameDirective);
function directiveNameDirective() {
return {
restrict: 'A',
scope: {
directiveName: '='
},
template: '<span>directiveName: {{ directiveName }}</span>'
};
}
})();
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
<div ng-app="app">
<div ng-controller="MainController as MainCtrl">
<!-- here we pass a and b as strings otherwise they get evaluated as variables -->
<button ng-click="fn('a')">Set a</button>
<button ng-click="fn('b')">Set b</button>
<hr>
<!-- here we pass myVar which is declared as a property of $scope when the fn function is called -->
<div directive-name="myVar" id="abc"></div>
<hr> myVar: {{ myVar }}
</div>
</div>

AngularJS - Controller values not binding

In my MVC program simple angular value controllers values are not binding.
My code is as follows :
_Layout.cshtml
<body data-ng-app="ShoppingCartApp">
<div class="container body-content">
#RenderBody()
#Scripts.Render("~/bundles/jquery")
#Scripts.Render("~/Scripts/angular.js")
#Scripts.Render("~/Scripts/Custom/App.js")
#Scripts.Render("~/Scripts/Custom/ShoppingCartController.js")
#RenderSection("scripts", required: false)
<hr />
</div>
</body>
App.js
var app = angular.module('ShoppingCartApp', []);
ShoppingCartController.js
app.controller('ShoppingCartController', function ShoppingCartController($scope, $http) {
$scope.ShoppingCartObj.products = [];
$scope.test = "ABC";
// On load events
// $scope.loadValues();
});
My Html Code is follows :
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<script></script>
<h2>Index</h2>
Total {{2+2}} // This value workd FINE
<div ng-controller="ShoppingCartController">
<div class="row">
<div class="nav navbar-nav navbar-left">
<h3>Total {{2+2}}</h3> // Not working THIS
</div>
<h1>{{test}}</h1> // Not working THIS
</div>
</div>
When i try to access value in controller or access directive inside controller it's not working. What i miss in here?
Change your controller to:
app.controller('ShoppingCartController', function($scope, $http) {....});
Or create a function named ShoppingCartController and then pass it to controller:
app.controller('ShoppingCartController', ShoppingCartController);
Also change $scope.ShoppingCartObj.products to $scope.ShoppingCartObj = {}; and then add products to that object $scope.ShoppingCartObj.products = []; because, prev you havnt defined what $scope.ShoppingCartObj is, so this object will be undefined.
If you're using Bundler you need to specify the Dependency Injection values
Also - ShoppingCartObj isn't declared anywhere so you can't assign to a property products
app.controller('ShoppingCartController', ['$scope', '$http',
function ShoppingCartController($scope, $http) {
$scope.ShoppingCartObj = {},
$scope.ShoppingCartObj.products = [];
$scope.test = "ABC";
}]);
Here's a working Jsfiddle

How to access parent property using Controller As notation

I'm using the Controller as in my view as follows:
<body ng-controller="MainCtrl as main">
<div ng-controller="ChildCtrl as child">
{{ main.parentValue }} + {{ child.childValue }}
</div>
</body>
Defining my controller like this:
app.controller('MainCtrl', function($scope) {
this.parentValue = 'Main';
});
app.controller('ChildCtrl', function($scope) {
this.childValue = 'Child';
// I want to access the property of the parent controller here
});
How can the ChildCtrl set the name property of the MainCtrl? Here the Plunkr.
Using the $scope notation, I could have accessed $scope.parentValue from the child controller. How can the same functionality be achieved using the Controller As notation?
Since your using the "controller as" notation, witin your ChildCtrl you can access the MainCtrl using $scope.main, for example $scope.main.name.
See my snippet below.
var app = angular.module('app', []);
app.controller('MainCtrl', function($scope) {
this.name = 'Main';
this.test = {};
});
app.controller('ChildCtrl', function($scope) {
this.name = 'Child';
alert($scope.main.name);
});
<html ng-app="app">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-controller="MainCtrl as main">
<div ng-controller="ChildCtrl as child">
{{ main.name }} + {{ child.name }}
</div>
</body>
</html>
You should not mix up "controller as" and $scope usage. To update data in a parent-scope you could/should use services.
Example: Changing the page-title from within any Child-Controller:
app.service("SiteService", function () {
return {
title: "Page title";
}
}
app.controller ("ParentCtrl", function (SiteService) {
this.site = SiteService;
}
app.controller ("ChildCtrl", function (SiteService) {
SiteService.title = "New Title";
}
And your template
<html ng-app="someApp" ng-controller="ParentCtrl as site">
<head>
<title>{{site.title}}</title>
</head>
</html>
The main advantage of this approach: You separate public mutable from private properties.
Putting the data in $scope is the angular way to do this. You could also set/get your data from a service which is then easy to include into either controller.
Check out this video: https://egghead.io/lessons/angularjs-sharing-data-between-controllers

window object not available on $scope in controller / link functions

I placed a kendo-window in my html.
according to the docs, the window object should be available on the scope.
now, I want to bind a listener to the window's activate event from within a controller that is declared inside the window. i.e.:
markup:
<body ng-app="app">
<div kendo-window='potatoWindow'>
<div ng-controller='PotatoController'>
here
</div>
</div>
js:
var app = angular.module("app", ["ngRoute", "kendo.directives"]);
app.controller("PotatoController", function($scope){
$scope.potatoWindow.bind("activate",
function () {
console.log("potato");
});
});
... but the window object (potatoWindow) is not found on the $scope during the controller.
Qs:
why is the window object not available? am i missing something?
if there is no way to access the window object - is there a way to get the same results by other means?
I think your kendo-window markup needs to be part of the controller markup.
Also, try using the k-on-activate binding and define your function in the controller like this:
MARKUP:
<div ng-controller='PotatoController'>
<div kendo-window='potatoWindow' k-on-activate='fry()'>
here
</div>
</div>
JS:
var app = angular.module("app", ["ngRoute", "kendo.directives"]);
app.controller("PotatoController", function($scope){
$scope.fry = function(e){
console.log('fried!');
};
});

how to modularize angular code?

I have two DIVs, each one is a self-contained user control or partial view, if I want one team to work on dog div, the other team work on fox div. can each team have their own angular module, controller, view, etc ? If yes, can you show me a code snippet?
another question: if I want to these two DIVs loosely coupled, what is the best angular way to let them communicate ?
<body ng-app>
<div id="dog">
<input type="text" ng-model="name"/> {{name}}
</div>
<div id="fox">
</div>
</body>
Thank you!
For other new ng developer's reference, this is the final code, if you have better solution, please feel free to improve it.
<body ng-app="airborneApp">
<div id="dog" ng-controller="dogController">
<input type="text" ng-model="name" /> {{name}}
</div>
<div id="fox" ng-controller="foxController">
<input type="text" ng-model="name" /> {{name}}
</div>
<script>
angular.module('airborneApp', ["dogCompany", "foxCompany"]);
angular.module('dogCompany', []).
controller('dogController', ['$scope', function ($scope) {
$scope.name = 'hello dog';
}]);
angular.module('foxCompany', []).
controller('foxController', ['$scope', function ($scope) {
$scope.name = "hello fox";
}]);
</script>
</body>
You can make as many modules as you can, you just have to reference all of them as a dependency in you main App module definition (and load them in correct order)
app
angular.module('myApp', ['firstModule', 'secondModule'])
modules
angular.module('firstModule', []) // empty array as a second parameter creates new module instead of using existing one
.controller(...)
.directive(...)
angular.module('secondModule', [])
.controller(...)
.directive(...)
For communication between different modules, the simplest way is to inject $rootScope into all controllers.
But preferred way is to create a service in main app module, which will be injected into both modules
angular.module('myApp')
.factory('SharedData', function() {
var a = {},
b = {};
return {
a: a,
b: b
}
})
and then use it
angular.module('firstModule')
.controller('something', function($scope, SharedData) {
SharedData.a.data = 'new data';
})
angular.module('secondModule')
.controller('something else', function(SharedData) {
console.log(SharedData.a.data); //will output 'new data'
})
each div can have a separate controller using:
<div ng-controller="firstCtrl"></div>
<div ng-controller="secondCtrl"></div>
for the other part of your question see:
What's the correct way to communicate between controllers in AngularJS?

Resources