Angularjs: parent and child scope - angularjs

point 1
i just do not understand why i could not access child controller property this way {{$scope.parentcities}}. but if i write like this way {{parentcities}} then it is working. so why we can not write $scope dot and then property name
<div ng-app ng-controller="ParentCtrl">
<div ng-controller="ChildCtrl as vm">
{{$parent.cities}}
<br>
{{$scope.parentcities}}
</div>
</div>
function ParentCtrl($scope) {
$scope.cities = ["NY", "Amsterdam", "Barcelona"];
}
function ChildCtrl($scope) {
$scope.parentcities = $scope.$parent.cities;
}
point 2
need some guide line what kind of syntax it is ChildCtrl as vm ?
when we need to mention controller in html ChildCtrl as vm like this way ?
does it carry any special meaning?
looking for some guidance. thanks

Well, the point of $scope is that you don't need to write it when you bind values to the view. So $scope.supervalue = 'Hallo' will be accessed in the view like this {{ supervalue }}. That's it.
$parentis a keyword from the Angular framework to reference the parent scope.
The controllerAs syntax is made to get rid of the $scope keyword alltogether. So inside the controller, you can write it like this:
var self = this;
self.supervariable = 'Hallo';
In your config for this route, you specifiy controllerAs: 'vm'. So you can access your values in the view via {{ vm.supervariable }}. Have a look here to learn all about it.
But, it seems like you should do some groundwork first and learn about the basic Angular mechanism before you dive into controllerAs, which has some tricky parts to it later on.

As long as you are going to use Ctrl as c syntax please assign values to this variable
function ParentCtrl($scope) {
$scope.cities = ["NY", "Amsterdam", "Barcelona"];
}
function ChildCtrl($scope) {
this.parentcities = $scope.$parent.cities;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app ng-controller="ParentCtrl">
<div ng-controller="ChildCtrl as vm">
{{$parent.cities}}
<hr>
{{vm.parentcities}}
</div>
</div>

Related

AngularJS | Handling $broadcast & $on for specific instance of the same controller

I have a utility controller build to manage documents attachments for reusing across my application.
<div ng-controller="someController">
<div ng-controller="documentController as temp1"></div>
<div ng-controller="documentController as temp2"></div>
</div>
Under the parent controller i.e. someController I have a broadcast method..
var module = angular.module("MyModule");
module.controller("someController",
function ($scope) {
$scope.$broadcast("callSomeFunctionInDocumentsController");
});
module.controller("documentController",
function($scope) {
$scope.$on("callSomeFunctionInDocumentsController", function() {
//do something here
});
});
Now the problem I am facing is that since the documentController is added twice to the view, the $on method is executed twice as well. Whereas based on some condition I would want to call the $on method either in temp1 or temp2 instance and not both.
I am not sure if what I wish to achieve is possible but any help will be much appreciated.
Thanks.
The $broadcast works simply: everyone who registered is notified through $on.
In your example, both controllers are registered.
So why do you use the same controller twice? Maybe worth to switch to component?
What about this one:
<div ng-controller="someController">
<div ng-controller="documentController as temp1"></div>
<div ng-if="oneCtrlGotNotification" ng-controller="documentController as temp2"></div>
</div>
where oneCtrlGotNotification is some flag (maybe under $rootScope).
So you will display second controller only when 1st already notified.
But it is a workaround.
One approach is to give a unique id to each element with a controller:
<div ng-controller="someController">
<div id="temp1" ng-controller="documentController as temp1"></div>
<div id="temp2" ng-controller="documentController as temp2"></div>
</div>
Then use the $attrs local to differentiate:
app.controller("documentController", function($scope, $attrs) {
$scope.$on("callSomeFunctionInDocumentsController", function() {
if ($attrs.id == "temp1") {
//do something specific to "temp1" controller
});
});
})
For more information, see
AngularJS Comprehensive Directive API Reference - controller
AngularJS $attrs Type API Reference

How to avoid using `$parent.$parent.$parent` in nested scopes

How can I know the Parent controller name in controller chain of Angular?
I'm new to Angular so I have one basic question.
Suppose, In Angular, I have a controller's chain like below.
<div ng-controller="parentController">
... something in the parent element
<div ng-controller="childController">
... something in the child element
</div>
</div>
Is there any way to write the code in the child element so that I can know the parent controller name in the output (In this case output should be 'parentController')?
I need this because I have a too big project and want to know the parent of each controller because someone has wrote the code like
googleOAuth= $scope.$parent.$parent.$parent.$parent.status.googleOAuth
and I'm not able to understand so want to know the parent of each $scope.
On approach is to use "controller as" syntax:
<div ng-controller="parentController as top">
<!-- ... something in the parent element -->
<div ng-controller="childController">
<!-- ... something in the child element -->
{{top.status.googleOAuth}}
</div>
</div>
This requires the controller be written using the this context instead of $scope.
Another approach is to use a property of an object in the parent scope:
app.controller("parentController", function($scope) {
$scope.top = {status: {} };
$scope.top.status.googleOAuth = value;
});
<div ng-controller="parentController">
<!-- ... something in the parent element -->
<div ng-controller="childController">
<!-- ... something in the child element -->
{{top.status.googleOAuth}}
</div>
</div>
Because scopes use prototypical inheritance, the top property is available to child scopes.
See AngularJS Developer Guide - Scope Hierarchies.
As georgeawg said, using $parent is not optimal because it relies on a constant number of scopes.
Instead, you could write a service to deal with your googleOAuth.
The service can then be injected in each controller and will function as a single source of truth because services are singletons in AngularJS.
e.g. something like this
angular.module('appModule', [])
.factory('googleOAuthService', [function() {
var googleOAuth = {
// your googleOAuth stuff here
};
return {
get: get,
set: set,
stuff: stuff
}
function get () {
return googleOAuth;
}
function set (newGoogleOAuth) {
googleOAuth = newGoogleOAuth;
}
function stuff () {
// Do stuff to googleOAuth
}
}])
.controller('parentController', ['googleOAuthService', function(googleOAuthService) {
googleOAuthService.stuff();
}])
.controller('childController', ['googleOAuthService', function(googleOAuthService) {
googleOAuthService.stuff();
}]);
For more info, see https://docs.angularjs.org/guide/services

Variable defined in controller not available in the html

I'm trying to access variables defined in my Angular Controller in an html file using this controller. But they're not there. Here's my code:
In MapsController:
angular.module('Maps').controller('MapsController', ['$scope', '$location', 'MapsService', function($scope, $location, MapsService) {
$scope.number = 5;
... ...
}]);
In Search.html:
<div class="generic-container" ng-controller="MapsController as ctrl">
number: {{ctrl.number}}
</div>
When I run this, number is always empty. What am I missing?
(This is obviously a simplified version. In fact I'm trying to access an array that gets populated by the database. But it seems like in principal the idea is the same.)
Using contoller as syntax (MapsController as ctrl) you tell angular to assign the controller instance to scope's variable ctrl. So add you property number to the controller instead of scope.
Change $scope.number = 5; to this.number = 5; and it will work.
You are using the controller wrong in html
<div class="generic-container" ng-controller="MapsController as ctrl">
number: {{ctrl.number}}
</div>
this will not work because you don't need to create an alias for a Controller in html.
<div class="generic-container" ng-controller="MapsController">
number: {{ctrl.number}}
</div>
Also to access any variable in the scope of controller, you don't need to specify the controller object to access it.
<div class="generic-container" ng-controller="MapsController">
number: {{number}}
</div>
it should do the job.

Preserving Scope in ng-repeat ( not wanting child scope )

I might be missing something conceptually but I understand that ng-repeat creates child scopes but for my scenario this is undesirable. Here is the scenario. I have a 3way bind to a firebase dataset. The object is an object with n sub objects. In my current code structure I use ng-repeat to iterate and render these objects with a custom directive. The issue is that these objects are meant to be "live" ( meaning that they are 3-way bound. The highest level object is bound with angularfire $bind ).
So the simple scenario in my case would be where the ng-repeat created scope was not isolated from the scope that it was created from.
I am looking for ideas on how to do this? Or suggestions on other approaches.
This won't be a complete answer, but I can help with the angularFire portion, and probably an angular guru can fill in the blanks for you (see //todo).
First of all, don't try to share scope. Simple pass the variables you want into the child scope. Since you'll want a 3-way binding, you can use & to call a method on the parent scope.
For example, to set up this pattern:
<div ng-repeat="(key,widget) in widgets">
<data-widget bound-widget="getBoundWidget(key)"/>
</div>
You could set up your directive like this:
.directive('dataWidget', function() {
return {
scope: {
boundWidget: '&boundWidget'
},
/* your directive here */
//todo presumably you want to use controller: ... here
}
});
Where &boundWidget invokes a method in the parent $scope like so:
.controller('ParentController', function($scope, $firebase) {
$scope.widgets = $firebase(/*...*/);
$scope.getBoundWidget = function(key) {
var ref = $scope.widgets.$child( key );
// todo, reference $scope.boundWidget in the directive??
ref.$bind(/*** ??? ***/);
};
});
Now you just need someone to fill in the //todo parts!
You still have access to the parent scope in the repeat. You just have to use $parent.
Controller
app.controller('MainCtrl', ['$scope', function ($scope) {
$scope.someParentScopeVariable = 'Blah'
$scope.data = [];
$scope.data.push({name:"fred"});
$scope.data.push({name:"frank"});
$scope.data.push({name:"flo"});
$scope.data.push({name:"francis"});
}]);
HTML
<body ng-controller="MainCtrl">
<table>
<tr ng-repeat="item in data | filter: search">
<td>
<input type="text" ng-model="$parent.someParentScopeVariable"/>
<input type="text" ng-model="item.name">
</td>
</tr>
</table>
</body>
Plunker

Angularjs - Using controller

I am new to Angular.js. I currently have the following html code, where I define my div with my file html ( ng-include ) and my controller ( ng-controller ):
<div id="customerinformation-maxi" ng-include="'pages/customerinformation-maxi.html'" ng-controller="customerInformationMaxiController" class="col-md-12"></div>
This is the html code for the called html in directive ng-include ( customer-information.html ):
<div class="row">
<div class="col-md-2">
<span>Customer Number</span>
<span>{{customer.number}}</span>
</div>
<div class="col-md-2">
<span>Portfolio</span>
<span>{{custom.portfolio}}</span>
</div>
</div>
This is the js controller:
angularRoutingApp.controller('customerInformationMaxiController', function($scope, $http) {
//Here i need to load the model variable with a literal text {{customer.number}} and {{customer.portfolio}}, how could do it? using scope object? with a json file?
});
Here I need to load the model variable with a literal text {{customer.number}} and {{customer.portfolio}}.
How could do it? Using scope object? With a json file?
Thanks for any help.
Yes, you should do it using the $scope object.
To get a general overview, here is a hello-world example:
<div ng-controller="HelloController">
{{ helloMessage }}
</div>
And in you controller's code (js file or script tag into the html):
var myApp = angular.module('myApp',[]);
myApp.controller('HelloController', ['$scope', function($scope) {
$scope.helloMessage= 'Hello World!';
}]);
But I foresee some nesting in the provided snippet of your question, so you 're probably dealing with a collection of objects which means that you have to iterate through it, in the html part, using the ng-repeat directive, like:
<tr ng-repeat="customer in customers>
<td>{{customer.number}}</td>
<td>{{customer.portfolio}}</td>
</tr>
So, your controller's functionality should contain the customers object, like:
angularRoutingApp.controller('customerInformationMaxiController', function($scope, $http) {
var customers=[
{
number:'123',
portfolio: 'blah blah'
},
{
number:'124',
portfolio: 'blah blah'
},
{
number:'125',
portfolio: 'blah blah'
}
];
});
For further reference, you could read two respective example I have written:
Angular.js Controller Example
Angular.js JSON Fetching Example
The second one is only to see a sample usage of traversing collections, it is not meant that you have to use json, as you stated in your question; but I see that you also defined the $http service in your controller, so if it's about data that are going to be fetched from a remote destination, the JSON Fetching Example should probably help you better).
You should use scope objects to give values to your modal variables.
angularRoutingApp.controller('customerInformationMaxiController', function($scope, $http) {
$scope.customer.number = 'sample number';
$scope.customer.portfolio = 'sample portfolio';
});

Resources