AngularJS data-binding using ui-router and ControllerAs syntax without $scope - angularjs

I'm following the conventions made by John Papa, but unfortunately I'm not really figuring out how to bind values from children controllers to parent controllers, using ui-router, ControllerAs and vm variables instead of $scope.
I made two examples, first example illustrates the working environment, so without ControllerAs and the normal $scope variable, this works, but when I change $scope to
var vm = this;
it doesn't process any changes made to children controllers to the parent. I really want to make it work without working with some kind of PUBSUB pattern, because this is one of the most important features of working with two-way-data binding, but I don't know if this is possible within this situation?
I've created two Plunker examples to illustrate the problem:
Plunker example 1:
Controller + $scope
http://embed.plnkr.co/oNsCF2YnfKP3wzGNhFUi/preview
Plunker Example 2:
With vm variable and ControllerAs syntax
http://embed.plnkr.co/s68o08dtBafHKflD8ZLZ/preview
The first Example works, when changing some input fields within the template 'register-identification.html', this will directly change {{formData}} from the parent controller (RegisterBaseController).
The second Example doesn't process any changes.
I hope my explanation makes any sense? Hopefully someone can help me out!
Many thanks in advance!
Ken

This scenario is behaving as expected, but not as you want.
$scope Inheritance - pass model by reference
The reason is, that any child state, is provided with prototypically inherited version of a $scope:
$childScope = $scope.$new();
And that means, that any reference created on parent is available on child
$scope.Reference = {};
$scope.Reference.A = 1;
$childScope = $scope.$new();
// here both contain 1 as Reference.A
$childScope.Reference.A = 2;
// both contain 2
$childScope.Reference.A === $childScope.Reference.A
hidding reference with another
But what you do (what controllerAs does) is:
$scope.vm = controllerParent;
$childScope = $scope.$new();
$childScope.vm = controllerChild;
The reference to vm itself is changed.
solution with a dot - Model {}
So, what could be working is combination:
$scope.Model = {}
$scope.Model.vm = controllerParent;
$childScope = $scope.$new();
$childScope.Model.childVm = controllerChild;
$childScope.Model.vm ... // this is parent controller
Check the doc:
What Do Child States Inherit From Parent States?
and mostly:
Scope Inheritance by View Hierarchy Only
Keep in mind that scope properties only inherit down the state chain if the views of your states are nested. Inheritance of scope properties has nothing to do with the nesting of your states and everything to do with the nesting of your views (templates).
It is entirely possible that you have nested states whose templates populate ui-views at various non-nested locations within your site. In this scenario you cannot expect to access the scope variables of parent state views within the views of children states.
Check the dot in the model:
Model in a modal window in angularjs is empty

Related

AngularJs: Does same controller at different pages share scope?

I am new to learning Angularjs and kinda confused. I want to ask that if the same controller is binded at different pages does those pages share the same scope variable or they have their own isolated scope? Remember both of the pages are using the same controller.
From the documentation:
When a Controller is attached to the DOM via the ng-controller
directive, Angular will instantiate a new Controller object, using the
specified Controller's constructor function. A new child scope will be
created and made available as an injectable parameter to the
Controller's constructor function as $scope.
So 1) it is not the same controller, those are two instances of the same constructor functions (a.k.a class) and 2) new scope is created as a child of a scope controller is attached to.
Another point from documentation:
Scopes are arranged in hierarchical structure which mimic the DOM
structure of the application.
So two separate DOM elements cannot have same scope - it would heavily affect Angular structure. Each controller can only get an access to the scope of element it is attached to.
If you suffering because of one scope being updated when another one is changed, please post your code as you can have "surprise closure" in your controller definition.
I want to ask that if the same controller is binded at different pages does those pages share the same scope variable or they have their own isolated scope? Remember both of the pages are using the same controller.
Yes, I echo others thoughts here. if you are using same controller for any number of pages the scope will remains same for each page. Unless one does not change the scope, the value remains as it was during the initialization.
eg. Your controller is as below
myApp.controller('FirstCtrl', function( $scope){
$scope.myVar = 'this is my scope';
});
and if you are using same controller for two pages then for page one and page two will have same value of myVar. Hence below html in one page one
<div ng-model="myVar"></div>
and below html in page two
<span ng-model="myVar"></span>
will display as
<div ng-model="myVar">this is my scope</div>
and
<span ng-model="myVar">this is my scope</span>
respectively.
Given this, I would like to add that it is also possible of sharing $scope between different controllers using $emit, $broadcast and $on.
Read more about this at http://www.dotnet-tricks.com/Tutorial/angularjs/HM0L291214-Understanding-$emit,-$broadcast-and-$on-in-AngularJS.html
Hope this helps.

$scope binding in Angular

If you have a controller what is the preferred method for data binding, multiple smaller ones or one big object e.g.:
$scope.username = 'John Doe';
$scope.email = 'me#me.com';
$scope.city = 'Amsterdam';
or
var user = {};
user.username = 'John Doe';
user.email = 'me#me.com';
user.city = 'Amsterdam';
$scope.user = user;
I would go with second one, from angularjs wiki
Scope inheritance is normally straightforward, and you often don't
even need to know it is happening... until you try 2-way data binding
(i.e., form elements, ng-model) to a primitive (e.g., number, string,
boolean) defined on the parent scope from inside the child scope. It
doesn't work the way most people expect it should work. What happens
is that the child scope gets its own property that hides/shadows the
parent property of the same name. This is not something AngularJS is
doing – this is how JavaScript prototypal inheritance works. New
AngularJS developers often do not realize that ng-repeat, ng-switch,
ng-view and ng-include all create new child scopes, so the problem
often shows up when these directives are involved. (See this example
for a quick illustration of the problem.)
This issue with primitives can be easily avoided by following the
"best practice" of always have a '.' in your ng-models – watch 3
minutes worth. Misko demonstrates the primitive binding issue with
ng-switch.
Having a '.' in your models will ensure that prototypal inheritance is
in play. So, use
<input type="text" ng-model="someObj.prop1"> rather than
<input type="text" ng-model="prop1">.
If you really want/need to use a primitive, there are two workarounds:
Use $parent.parentScopeProperty in the child scope. This will prevent
the child scope from creating its own property. Define a function on
the parent scope, and call it from the child, passing the primitive
value up to the parent (not always possible)
https://github.com/angular/angular.js/wiki/Understanding-Scopes

Using AngularJs ControllerAs approach, How can I call a function in a parent controller from the child controller?

I know you may have seen this question before, but is there really an answer for it? I started to doubt it.
Simply, I am using controlleras syntax as recommended, I have no problem accessing parent controller members form within the view, but I cannot do it from the constructor function of my child scope. And here is some code from what I am having right now:
myapp.controller("ParentController", function() {
this.selectedItem = {
Id: 1,
name: 'item1'
};
this.setSelectedItem = function(item) {
this.selectedItem = item;
//do other stuff
}
});
myapp.controller("ChildController", function() {
this.onItemChanged = function(newItem) {
//How can I call the parent controller instance from here
}
});
Also please notice that I want to call the 'updateSelectedItem' function from my child controller in away that the 'this' keyword will refer to the parent controller instance not the child, because I want to change the parent controller instance, so how should I do this?
To answer your question as clearly as possible, you first must have a bit of background on how the Controller-As syntax actually works.
Using Controller-As does not mean that you are not using $scope. In reality, $scope still exists. Controller-As is shorthand which creates an object on $scope and attaches the properties assigned via this to that object. On the view side, this object is explicitly bound to all the controls. you could still reference $scope.vm.property. However, since $scope is implicit in this scenario, it is not necessary to create a dependency to it.
Accessing the properties of the vm object of the parent controller in a nested scenario is still possible, but only if each controller is referenced by a different name. If your objects are outerScope and innerScope, then inside the HTML template of innerScope, you can still refer to outerScope.someProperty.
If, however, all controllers are named the same (i.e. vm), then the only way to access the parent controller would be through a property of the child scope which is aliased to a $scope property, introducing the $scope dependency.
In practice, whenever you have a controller within another controller, it's much cleaner for the innermost item to be a directive which wraps its own content, and explicitly defines which variables it needs through an Isolate Scope. However, whenever this is not necessary, the fallback should be for inner controllers to be named uniquely from outer controllers.

AngularJS Scope Object Inheritance

Hi I need a AngularJS Wiz to point me in the right direction been trying to get my head around AngularJS Scope and Inheritance.
I have a child Scope which I add to a Parent Scope then I want to add a new object to the Parent scope via array.push(); but I'm not sure why the Child scope then inherits this new value. See the fiddle here http://jsfiddle.net/sjmcpherso/EFxuZ/ The first example using ng-repeat and objects causes the child to update:
$scope.childArr = [{'name':'peter'},{'name':'paul'},{'name':'perry'}];
$scope.parentArr = $scope.childArr;
$scope.parentArr.push({'name':'Why am I in now in the Child Array?'})
Whereas the second example using just a variable does not:
$scope.childVar = "Confused Muchly";
$scope.test.parentVar = $scope.childVar;
$scope.test.parentVar = "This wont change the child variable";
Ideally I would like to make changes to the child scope which would update the parent scope but not the other way around.
I have read of https://github.com/angular/angular.js/wiki/Understanding-Scopes while not fully understanding everything this issue seems a mystery to me.
Firstly, both of your models $scope.childArr and $scope.test.parentArr are in $scope of the controller. None of them is in parent scope.
If you want to have parentArr in the parent scope, then you should have a parent-child controller design or move your model inside the rootScope:
$rootScope.test = {};
$rootScope.test.parentArr = [ /* some items here */ ];
Secondly, $scope.childArr and $scope.test.parentArr both point to the same array. Changing either of them would mean changing both of them.
It is almost same as doing:
$scope.test = {};
$scope.childArr = $scope.test.parentArr = [
{'name':'peter'},
{'name':'paul'},
{'name':'perry'}
];
If you want to create separate copies so that changing one of them would not affect the other, then you can use angular.copy():
$scope.test.parentArr = angular.copy($scope.childArr);

What is “$rootScope” and how is it related with “$scope”? [duplicate]

Can anyone explain the difference between $scope and $rootScope?
I think
$scope:
We can get ng-model properties in particular controller from the particular page by using this.
$rootScope
We can get all ng-model properties in any controller from any page by using this.
Is this correct? Or anything else?
"$rootScope” is a parent object of all “$scope” angular objects created in a web page.
$scope is created with ng-controller while $rootscope is created with ng-app.
The main difference is the availability of the property assigned with the object. A property assigned with $scope cannot be used outside the controller in which it is defined whereas a property assigned with $rootScope can be used anywhere.
Example: If in the example below you replace $rootScope with $scope the department property will not be populated from the first controller in the second one
angular.module('example', [])
.controller('GreetController', ['$scope', '$rootScope',
function($scope, $rootScope) {
$scope.name = 'World';
$rootScope.department = 'Angular';
}
])
.controller('ListController', ['$scope',
function($scope) {
$scope.names = ['Igor', 'Misko', 'Vojta'];
}
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="example">
<div class="show-scope-demo">
<div ng-controller="GreetController">
Hello {{name}}!
</div>
<div ng-controller="ListController">
<ol>
<li ng-repeat="name in names">{{name}} from {{department}}</li>
</ol>
</div>
</div>
</body>
According to Angular's Developer's Guide to Scopes:
Each Angular application has exactly one root scope, but may have several child scopes. The application can have multiple scopes, because some directives create new child scopes (refer to directive documentation to see which directives create new scopes). When new scopes are created, they are added as children of their parent scope. This creates a tree structure which parallels the DOM where they're attached.
Both controllers and directives have reference to the scope, but not to each other. This arrangement isolates the controller from the directive as well as from DOM. This is an important point since it makes the controllers view agnostic, which greatly improves the testing story of the applications.
$rootScope is available globally, no matter what controller you are in, whereas $scope is only available to the current controller and it's children.
In other way we can look at this; $rootScope is global while $scope is local. When Controller is assigned to a page, so a $scope variable can be use here because it binds to this controller. But when we want to share its value across to other controllers or services, then $rootScope is being used (**there are alternative ways, we can share values across but in this case we want to use $rootScope).
Your second question about how you define those two words are correct.
Lastly a bit off track, please use $rootScope with care. Similar to the way you use global variables, can be a pain to debug and you may accidentally change the global variable somewhere inside a timer or something which makes your reading incorrect.
Every application has atleast one single rootScope and its lifecycle is the same as the app and every controller can have it's own scope, that is not shared with others.
Have a look at this article :
https://github.com/angular/angular.js/wiki/Understanding-Scopes
I recommend you read the official in-depth Angular documentation for scopes. Start at the section 'Scope Hierarchies':
https://docs.angularjs.org/guide/scope
Essentially, $rootScope and $scope both identify specific parts of the DOM within which
Angular operations are carried out
variables declared as part of either the $rootScope or $scope are available
Anything that belongs to the $rootScope is available globally across your Angular app, whereas anything that belongs to a $scope is available within the part of the DOM to which that scope applies.
The $rootScope is applied to the DOM element that is the root element for the Angular app (hence the name $rootScope). When you add the ng-app directive to an element of the DOM, this becomes the root element of the DOM within which $rootScope is available. In other words, properties etc of $rootScope will be available throughout your entire Angular application.
An Angular $scope (and all of it's variables and operations) is available to a particular subset of the DOM within your application. Specifically, the $scope for any particular controller is available to the part of the DOM to which that particular controller has been applied (using the ng-controller directive). Note though that certain directives e.g. ng-repeat, when applied within a part of the DOM where the controller has been applied, can create child scopes of the main scope - within the same controller - a controller doesn't necessarily contain only one scope.
If you look at the generated HTML when you run your Angular app, you can easily see which DOM elements 'contain' a scope, as Angular adds the class ng-scope on any element to which a scope has been applied (including the root element of the app, which has the $rootScope).
By the way, the '$' sign at the start of $scope and $rootScope is simply an identifier in Angular for stuff that's reserved by Angular.
Note that using $rootScope for sharing variables etc. between modules and controllers isn't generally considered best practice. JavaScript developers talk about avoiding 'pollution' of the global scope by sharing variables there, since there may be clashes later on if a variable of the same name is used somewhere else, without the developer realising it's already declared on the $rootScope. The importance of this increases with the size of the application and the team that's developing it. Ideally the $rootScope will only contain constants or static variables, that are intended to be consistent at all times across the app. A better way of sharing stuff across modules may be to use services and factories, which is a another topic!
Both are Java script objects and the difference is illustrated by diagram as below.
NTB:
First angular application try to find the property of any model or function in $scope , if it doesn't
found the property in $scope , then it search in parent scope in upper hierarchy. If the property is
still not found in upper hierarchy then angular tries to resolve in $rootscope.
New styles, like John Papa's AngularJS Styleguide, are suggesting that we shouldn't be using $scope to save current page's properties at all. Instead we should use the controllerAs with vm approach where the view binds to the controller object itself. Then use a capture variable for this when using the controllerAs syntax. Choose a consistent variable name such as vm, which stands for ViewModel.
You will still need the $scope for its watching capabilities though.

Resources