$scope.feeds is getting updated within the controller. But the view won't update the variable. The feeds variable is in a ng-repeat.
Angular Code:
$scope.openfeeds = function(category){
$http({
method: 'GET',
url: '/category/feeds/'+category.id
}).then(function successCallback(response) {
$scope.feeds = response.data;
console.log($scope.feeds);
});
};
HTML code:
<div class="c-Subscribe">
<div class="c-Subscribe_feeds" ng-repeat="feed in feeds" ng-controller="LinkController">
#{{feed}}
</div>
</div>
Whereas, there is another variable called categories which right above it. It is getting updated with the same way I am doing it to update the feeds.
<div class="c-modal_content">
<div class="c-categoryTile_blocks">
<div class="c-categoryTile" ng-repeat="category in categories">
<div class="c-categoryTile_background" style="background-image: url('/images/biker-circuit-competition-63249.jpg');">
#{{ category.category }}
</div>
</div>
</div>
</div>
Any ideas why this isn't working?
Pretty much the same answer that I gave to this question How to preserve scope data when changing states with ui-router?
You need to under stand how prototypal inheritance works. When a parent puts a property value on the scope with
$scope.value = 'something';
In a child component if you access $scope.value the inheritance chain will find $scope.value.
If the child sets
$scope.otherValue = 'something';
If follows the inheritance chain, doesn't find a value of otherValue and creates a property on the child scope, not the inherited prototype so the parent component and any other children of the parent do not see it.
You can use what is called the dot rule of prototypal inheritance. If the parent creates an object on the scope called something like data
$scope.data = { value: 'something' };
Now if the child puts a property on the data object
$scope.data.otherValue = 'something';
It looks for the data object, finds it in the inheritence chain and because you are adding a property to an instance of an object it is visible to the parent and any children of the parent.
let parent = {
value: 'some value',
data: { value: 'some value' }
};
let child = Object.create(parent);
console.log(child.value); // Finds value on the prototype chain
child.newValue = 'new value'; // Does not affect the parent
console.log(parent.newValue);
child.data.newValue = 'new value'; // newValue is visible to the parent
console.log(parent.data.newValue);
Short answer is to just never inject $scope and use controllerAs syntax.
To share data between controllers you use a service that is injected to both controllers. You have the spots collection on the service and use a route param to identify which spot the other controller should use or have a place on the service called currentSpot set by the other controller.
Services are a singleton object that you create at the module level and then all controllers that ask for them in their dependency list get the same instance. They are the preferred way to share data between controllers, $scope hierarchies are bound to lead to confusion as the prototypal inheritance nature of them can be confusing. A child $scope is prototypally inherited from it's parent, this seems like you should be sharing data but when a child controller sets a property it is not visible to the parent.
You are learning an outdated way of Angular programming. Injecting $scope is no longer a recommended way. Look at using components. Components are a wrapper for a controller with an isolated scope and using contollerAs syntax. Isolated scopes make it much cleaner to know where data comes from.
Take a look at my answer on this question
Trying to activate a checkbox from a controller that lives in another controller
Related
I have the following HTML structure:
<div class="order-table-page" ng-controller="SummaryController as summaryCtrl">
<h3>Summary</h3>
<!-- Statutes summary information -->
...
<!--List of orders with selected statuses-->
<div ng-controller="OrderTableController as orderTableCtrl">
...
</div>
</div>
So, OrderTableController is a child of SummaryController. Now, in child controller I want to get access to the parent property. In parent class I define:
orderApp.controller('SummaryController', ['$location', 'ordersApi', function($location, ordersApi){
var ctrl = this;
ctrl.summary = [];
ctrl.test = 'test';
...
}]);
And in child controller I try to get "test" property:
orderApp.controller('OrderTableController', ['$location', '$scope', 'ordersApi', function($location, $scope, ordersApi){
var table = this;
table.orders = [];
console.log("Table orders 1");
console.log($scope.$parent.test);
...
}]);
I expect that $scope.$parent will contain SummaryController scope. But I'm not sure what it contains, because $scope.$parent.test is undefined and $scope.$parent has property named summaryCtrl.
My question is how to get parents property "test" form OrderTableController?
As your are using Controller As feature, it creates a property inside the $scope which will represent the controller itself.
So, in your SummaryController you have a test property. And in scope of this SummaryController it will be like $scope.summaryCtrl.test - because you defined it as SummaryController as summaryCtrl.
Therefore, you need to go in the same path from you child controller to get test property (it will be more elegant than working with $scope.$parent).
If you need to share some data between controllers, you can try to use shared services (as they are singletons) and use them in related controllers.
You simply have to add a refference in OrderTableController of SummaryController and you'll get everything from SummaryController in OrderTableController :)
Using $scope.$parent is not very elegant. Not neccesary wrong, but not elegant.
This may be because you are using this instead of $scope in the parent controller, if you do $scope.test='test' you could get it in the way you want $scope.$parent.test. See this fiddle: http://jsfiddle.net/f2zyvf17/
PD: You can see the difference of using $scope or this in this question:
'this' vs $scope in AngularJS controllers
Here, the author mentions
the $scope object used by the two controllers are not the same $scope object
Snippet for the same:
Now consider a little modification to the above code.
<body ng-app="myapp">
<div ng-controller="myController1">
<div>{{data.theVar}}</div>
<div>{{data.common}}</div>
<div ng-controller="myController2">
<div>{{data.theVar}}</div>
<div>{{data.common}}</div>
<div>{{temp}}</div>
<div>{{newTemp}}</div>
</div>
</div>
<script>
var module = angular.module("myapp", []);
var myController1 = module.controller("myController1", function($scope) {
$scope.data = {
theVar : "Value One",
common : "common Value"
};
$scope.temp = "John Wick 2 is going to be released soon";
});
var myController2 = module.controller("myController2", function($scope) {
$scope.data = {
theVar : "Value Two"
};
$scope.newTemp = $scope.temp;
console.log("");
});
</script>
</body>
The view corresponding to controller2 has been moved inside the view for controller1.
For this piece of code inside the controller2,
$scope.newTemp = $scope.temp;
Are $scope highlighted above one and the same object?
If yes, how does AngularJS know this?
Had they been same, $scope.temp in controller2 would be undefined and so then $scope.newTemp?
For me, they are not the same, considering the o/p of the above program. See below:
But then, I am perplexed as to why they both comes out to be one & the same when I debug,
How does AngularJS able to access value of $scope.temp from controller1 in controller2?
Please clarify?
Lastly,
Altough it's true that the $scope used in two controllers are not the same, they can inherit eachother's properties. Angular's $scopes are like a tree, the trunk is the $rootScope and every other $scope branches from that or another $scope, so since your myController2 is a child of myController1 you can access the variables in it.
$rootScope -> myController1 -> myController2
The myController2 can access all the parent $scopes, the myController1 can access $rootScope and the $rootScope can only access itself.
For your last part, as both controllers have property by name data, angular will look into current scope first and then hierarchically move up i.e. parent's scope. Therefore, angular founds data in second controller's scope itself and hence need not refer parent's scope data variable. But there is no common key inside that property and hence does not output anything out.
Do look into controller as syntax of angular, it is meant to keep these conflicts at bay.
I have a child controller that references values from it's parent.
The problem is: ng-repeat within the child controller view doesn't get updated when the parent controller values are updated.
So my question is: How does one update the child controller ng-repeat when parent controller values are updated while child values are by reference?
Child Controller:
angular.module('angularApp').controller('PostController', function ($scope)
{
$scope.mainController = $scope.$parent.getMainController();
$scope.editController = $scope.$parent;
$scope.posts = $scope.mainController.currentStation.posts;
$scope.featuredAlbums = $scope.$parent.featuredAlbums;
$scope.updatePost = function(postId){
$scope.editController.updatePost(postId);
};
$scope.updateFeatured = function(featuredId){
$scope.editController.updateFeatured(featuredId);
};
});
ng-repeat under the child controller
<div ng-controller="PostController" class="posts">
<div ng-repeat="featuredAlbum in featuredAlbums">
Example that breaks:
http://plnkr.co/edit/GKjYAWEEWOrp84bwIIOt?p=info
** Answer **
Thanks for the fast response guys, I realise that everything created within the controller is passed by value and not reference, even values referenced from parent controllers are recreated as locally scoped controller values.
So the solution? Simple.
Just call the parent directly instead of recreating locally scoped vars
$scope.$parent.$someValue
Imagine the scenario:
app.controller('ParentController', function($scope) {
$scope.rawValue = 3;
$scope.hiddenValue = false;
$scope.objectValue = {
name: 'David',
age: 27
};
$scope.someFunction = function(input) {
return input;
}
});
app.controller('ChildController', function($scope) {
$scope.hiddenValue = true;
//Notice i don't need to wrap calls to parent functions or reassign parent data.
//this is because the $scope object will automatically inherit from it's parent.
});
<div ng-controller="ParentController">
{{ hiddenValue }} //false, remains false as setting only occured on child scope;
{{ rawValue }} //3, remains 3 as setting will only occur on child scope;
{{ objectValue.name }} // 'David' however will dynamically update with input below.
<div ng-controller="ChildController">
{{ hiddenValue }} //true because now it's scoped;
<input type="button" ng-click="someFunction('hello')" value="calls function on parent scope" />
<input type="text" ng-model="rawValue" /> //will initialise as 3 but as soon as updated it will be scoped on this scope.
<input type="text" ng-model="objectValue.name" /> //will initialise as David and will correctly update parent scope as edited.
</div>
</div>
So why does this work?
Anytime you are accessing a property or function it will automatically travel up the $scope hierarchy to find the value. No need to specify $parent expressly as this is how javascript inheritance works.
However whenever you are modifying/setting a value it will occur on the nearest $scope and be 'scoped'. that's what happens with hiddenValue and rawValue in example above. however notice that it works as expected on objectValue.name this is because in order to set the name property you must first 'get' objectValue. therefore javascript inheritance travels up the scope chain to get objectValue from the parent scope and then sets it's name property.
Two guidelines:
ng-model should usually use a '.' so that it forces this scope walking.
using $parent is usually a bad sign. If used correctly parent properties should already be available through the current $scope alone.
I am not sure I understand your question correctly. So I created a plunker that included two controllers. It seems to me that child values are always updated. Can you show us how your original questions are related or not?
`http://plnkr.co/edit/9aHqdbbIe5aGJSuHogPA?p=preview`
What's happening is that you are getting a new copy of the data in the child scope and the parent scope is not updated.
The simplest way to make it work is not to store any objects that need to be accessible by child controllers directly on the parent scope. You will have less code and far fewer complications.
In your case, in the parent have something like:
$scope.media = {
featuredAlbums : [ ... ],
currentStation : {
posts : {...}
}
}
$scope.functions = {
updatePost : function (pid) {
// your function
},
updateFeatured : function (pid) {
// your function
}
}
and in the child don't bother with all the inheritance and just call functions directly :
$scope.functions.updatedFeatured(featureID);
$scope.functions.updatePost(postId);
it doesn't matter which parent controller your functions and data are in, it will find them if you attach to a property of the controller but not the controller itself.
Take a look at this video which explains it better.
https://egghead.io/lessons/angularjs-the-dot
EDIT
As David Beech points, there is no need to store parent scope functions in a property because the function is not being modified. However, this approach is meant to be a simple rule that will work without any extra thinking about which data/functions are read-only and which are writable.
Apologies if this has been asked before, I couldn't find anything on SO and I'm hoping for some clarification ( or a nice neat trick )
Given
<div ng-controller="Parent">
<div ng-controller="Child">
//child manipulation of parent scope object
</div>
</div>
Parent sets json object so it is available to multiple child scopes -
$scope.persistentData = getAJSONObject();
A child scope wants to do some calculations and update a key of the local json object it has inherited from the parent -
doCalculations( $scope.persistentData.keyIWantToAlter )
Do I need to explicitly assign the parent scope to the result of the calculation function in the child (shown below) or is there a way that I can propogate the changes to the parent scope by just using the child's inherited scope objects?
$parent.$scope.$persistentData.keyIWantToAlter =
doCalculations( $scope.persistentData.keyIWantToAlter)
I can't see any problems with the blurb you gave you will need to give us more. I can caution you about trying to "share" nested objects on scope.
This fiddle illustrates what happens if you are in the child and you "overwrite" the reference. The json2 shows that these start off the same, but I overwrite the reference in the child scope and now the variables are detached.
I think you are experiencing a similar issue but can't prove it until you provide more info.
<div ng-controller="ParentCtrl">
Hello, {{json2}}!
<div ng-controller="ChildCtrl">
Hello, {{json2}}!
</div>
</div>
function ParentCtrl($scope) {
$scope.json2 = {
child:{
name: 'parent'
}
}
}
function ChildCtrl($scope, $timeout) {
$scope.json2 = {
child:{
name: 'child'
}
}
$timeout(function(){
$scope.json2.child.name= 'nick';
},5000);
}
I read about the new syntax from angularJS regarding controller as xxx
The syntax InvoiceController as invoice tells Angular to instantiate
the controller and save it in the variable invoice in the current
scope.
Visualization :
Ok , so I wont have the parameter $scope in my controller and the code will be much cleaner in the controller.
But
I will have to specify another alias in the view
So Until now I could do :
<input type="number" ng-model="qty" />
....controller('InvoiceController', function($scope) {
// do something with $scope.qty <--notice
And now I can do :
<input type="number" ng-model="invoic.qty" /> <-- notice
....controller('InvoiceController', function() {
// do something with this.qty <--notice
Question
What is the goal of doing it ? removing from one place and add to another place ?
I will be glad to see what am I missing.
There are several things about it.
Some people don't like the $scope syntax (don't ask me why). They say that they could just use this. That was one of the goals.
Making it clear where a property comes from is really useful too.
You can nest controllers and when reading the html it is pretty clear where every property comes.
You can also avoid some of the dot rule problems.
For example, having two controllers, both with the same name 'name', You can do this:
<body ng-controller="ParentCtrl">
<input ng-model="name" /> {{name}}
<div ng-controller="ChildCtrl">
<input ng-model="name" /> {{name}} - {{$parent.name}}
</div>
</body>
You can modify both parent and child, no problem about that. But you need to use $parent to see the parent's name, because you shadowed it in your child controller. In massive html code $parent could be problematic, you don't know where that name comes from.
With controller as you can do:
<body ng-controller="ParentCtrl as parent">
<input ng-model="parent.name" /> {{parent.name}}
<div ng-controller="ChildCtrl as child">
<input ng-model="child.name" /> {{child.name}} - {{parent.name}}
</div>
</body>
Same example, but it is much much clearer to read.
$scope plunker
controller as plunker
The main advantage with controller as syntax I see is that you can work with controllers as classes, not just some $scope-decorating functions, and take advantage of inheritence. I often run into a situation when there's a functionality which is very similar to a number of controllers, and the most obvious thing to do is to create a BaseController class and inherit from it.
Even though there's is $scope inheritence, which partially solves this problem, some folks prefer to write code in a more OOP manner, which in my opinion, makes the code easier to reason about and test.
Here's a fiddle to demonstrate: http://jsfiddle.net/HB7LU/5796/
I believe one particular advantage is clear when you have nested scopes. It will now be completely clear exactly what scope a property reference comes from.
Source
Difference between Creating a controller using the $scope object and Using the “controller as” syntax and vm
Creating a controller using the $scope object
Usually we create a controller using the $scope object as shown in the listing below:
myApp.controller("AddController", function ($scope) {
$scope.number1;
$scope.number2;
$scope.result;
$scope.add = function () {
$scope.result = $scope.number1 + $scope.number2;
}
});
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:
Pass data from the controller to the view
Pass behaviour from the controller to the view
Glues the controller and view together
The $scope object gets modified when a view changes and a view gets modified when the properties of the $scope object change
We attach properties to a $scope object to pass data and behaviour to the view. Before using the $scope object in the controller, we need to pass it in the controller function as dependencies.
Using the “controller as” syntax and vm
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>
Ofcourse we can use another name than “vm” in the controller as syntax. Under the hood, AngularJS creates the $scope object and attaches the properties and behaviour. However by using the controller as syntax, the code is very clean at the controller and only the alias name is visible on the view.
Here are some steps to use the controller as syntax:
Create a controller without $scope object.
Assign this to a local variable. I preferred variable name as vm, you can choose any name of your choice.
Attach data and behaviour to the vm variable.
On the view, give an alias to the controller using the controller as syntax.
You can give any name to the alias. I prefer to use vm unless I’m not working with nested controllers.
In creating the controller, there are no direct advantages or disadvantages of using the $scope object approach or the controller as syntax. It is purely a matter of choice, however, using the controller as syntax makes the controller’s JavaScript code more readable and prevents any issues related to this context.
Nested controllers in $scope object approach
We have two controllers as shown in the listing below:
myApp.controller("ParentController", function ($scope) {
$scope.name = "DJ";
$scope.age = 32;
});
myApp.controller("ChildController", function ($scope) {
$scope.age = 22;
$scope.country = "India";
});
The property “age” is inside both controllers, and on the view these two controllers can be nested as shown in the listing below:
<div ng-controller="ParentController">
<h2>Name :{{name}} </h2>
<h3>Age:{{age}}</h3>
<div ng-controller="ChildController">
<h2>Parent Name :{{name}} </h2>
<h3>Parent Age:{{$parent.age}}</h3>
<h3>Child Age:{{age}}</h3>
<h3>Country:{{country}}</h3>
</div>
</div>
As you see, to access the age property of the parent controller we are using the $parent.age. Context separation is not very clear here. But using the controller as syntax, we can work with nested controllers in a more elegant way. Let’s say we have controllers as shown in the listing below:
myApp.controller("ParentVMController", function () {
var vm = this;
vm.name = "DJ";
vm.age = 32;
});
myApp.controller("ChildVMController", function () {
var vm = this;
vm.age = 22;
vm.country = "India";
});
On the view these two controllers can be nested as shown in the listing below:
<div ng-controller="ParentVMController as parent">
<h2>Name :{{parent.name}} </h2>
<h3>Age:{{parent.age}}</h3>
<div ng-controller="ChildVMController as child">
<h2>Parent Name :{{parent.name}} </h2>
<h3>Parent Age:{{parent.age}}</h3>
<h3>Child Age:{{child.age}}</h3>
<h3>Country:{{child.country}}</h3>
</div>
</div>
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 post 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.
I find the main advantage is a more intuitive api since the methods/properties are associated with the controller instance directly and not the scope object. Basically, with the old approach, the controller becomes just a decorate for building up the scope object.
Here are some more info on this: http://www.syntaxsuccess.com/viewarticle/551798f20c5f3f3c0ffcc9ff
From what I've read, $scope will be removed in Angular 2.0, or at least how we view the use of $scope. It might be good to start using controller as as the release of 2.0 nears.
Video link here for more discussion on it.