I'm pulling my hair about a particular issue with my AngularJS application.
Basically, I have a controller, "PageCtrl", which pulls in a list of data via a service. The data is saved inside the PageCtrl. All works fine - so far so good.
Now my issue: for each object of the data inside the PageCtrl, I use ng-repeat to display each data just fetched.
In each of the ng-repeats, I use ng-include to get the correct template, depending of which data is in each object (basically the data is a list of elements that is to be displayed on the page. Each element has it's own controller.
As ng-include creates a newscope, all the created child scopes/controllers have access to the data, as it is located in the $parent controller - PageCtrl.
All works fine, except that each created controller in ng-repeat/ng-include needs to know which object in list of data in the parent, it needs to use to display.
Basically, in my ng-repeat, I would like to use the $index and pass it to the controller included in the ng-include. But I cannot do it! If I use ng-init, that code inside ng-init will be executed on the parent scope, ie. my original PageCtrl.
How can I, without the use of directives, pass information to the controller so that it knows which of the data-objects in its parent it should use?
Here is the code that loops over the data in MainCtrl:
<div ng-repeat="element in elements" >
<ng-include src=" GetTemplateFromElement(element.type) " ng-init=" SetElementNo($index); "></ng-include>
</div>
In the snippet, I call GetTemplateFromElement on the MainCtrl which returns the view to include. In the included view I refer which controller should do the work. I try to use $index to tell the included controller which index in the data it should use. But ofcourse the code is executed in MainCtrl scope. Example of a view:
<div ng-controller="ElementDocumentCtrl">
<div ng-bind-html-unsafe="element.document_content"></div>
</div>
In the snippet, "element.document_content" is on the scope of ElementDocumentCtrl, which pulls the data from its parent, PageCtrl.
How can I tell the directives included which index in the data-list in PageCtrl (it's parent controller) it should pick up?
Please don't tell me I need to make them all directives :)
Thanks, guys.
Maybe Im not understanding your question completely, but from the docs, $index, $first, $middle and $last are all exposed on the local scope of the ng-repeat children.
Ive put in a plunker to demonstrate this. The ChildCtrl accesses the $index from the parent to get the index of which element in the parent it is accessing.
Related
I am trying to understand a working code. It can build a very simple json data by adding name:value pairs one by one with GUI; by a custom directive and its link function, it builds a html template as the right hand of the image below:
What puzzles me is ng-model="$parent.keyName" in the highlighted part, as well as $parent.valueType, ng-model="$parent.valueName" in other part.
1) What does the $parent refer to (in the code or in the example of the above image)?
2) Is there a way to show the value of $parent or $parent.keyName in the console or by adding something (e.g., alert) in the program?
1) $parent refers to the parent scope (of any given scope). All scopes have a parent apart from $rootScope which is the top level scope. They can be created by any angular ng-* directive, including but not limited to ng-controller.
Generally speaking, it's considered bad practice to use $parent because it refers to the immediate parent scope which is subject to change. If the scope hierarchy does change (which it could do by adding a ng-* directive to a html element held in a custom directive template for example) then the hierarchy can be broken and $parent won't refer to the same scope that it once did.
2) Yes you can. In Chrome developer tools, if you Right Click > Inspect Element (as you have in the screen shot), you select the element. Then if you leave that element highlighted and go to the console tab and type:
angular.element($0).scope()
That returns the scope that the selected element resides in. Then if you type:
angular.element($0).scope().$parent()
That returns the parent scope of the scope that the selected element resides in. And for what it's worth you can also do:
angular.element($0).scope().$parent().$parent()
and keep going up the scope hierarchy.
Also check out the AngularJS Batarang chrome extension which allows you to look through the scopes in the Chrome Developer Tools.
What does this $parent refer to?
Parent refers to the scope of your parent controller. The image in your question doesn't give a clear picture so I will add an example for it.
<div ng-controller="EditorController">
<div ng-controller="ChildEditorController">
....
</div>
</div>
Assume you have a property called editorsList (array) in your EditorController (which is the parent controller here), you can do something like
<div ng-controller="EditorController">
<div ng-controller="ChildEditorController">
Editors Count: {{$parent.editorsList.length}}
</div>
</div>
So you can access the scope of your parent with the $parent.
I am completely new to AngularJS. In the code I am supposed to add a feature to I can see $scope.$parent I know about $scope. I also know that when I see a $ it means it is built-in angular. So I searched for it in Angular web site but
I did not have any luck finding anything about $Parent as a built-in service or factory or directive, etc...
Can anybody help me understand what it means. Also how I can get to an answer in their documentation when I run into something new?
The documentation for $parent is sparse, but you can find it referenced here at the very bottom of the page.
$scope.$parent refers to the $scope of the parent element. E.g. if you have an element with a controller nested within another element with it's own controller:
<div ng-controller="parentController">
... something in the parent element
<div ng-controller="childController">
... something in the child element
</div>
</div>
You can access variables attached to the parentController from the childController using $scope.$parent. and use them in the child element.
In angular, your scopes are all chained together. So, you can reference the scope "above" your immediate scope with $parent.
It's useful, for example, if you are working with a directive (or if you have a controller inside of another).
This is going to sound complicated but, i hope someone here is more experienced than me and can sort through what follows without much difficulty.
To keep this in perspective this is all related to a pagination section like so: There's a controller that pulls some initial data objects from a test page via an ajax request. Those data objects pertain to each "puppy block" - they fill the the "puppy-block" template, of the puppy block directive, with the correct data.
The blocks are displayed using an ng-repeat (repeating for the number of data objects pulled) - this represents a page.
The pagination is independent and just modifies the controller data via different ajax requests.
I have this here ng-repeat:
<div class="puppiesContainer" ng-repeat="p in puppies track by $index">
<puppy-block></puppy-block>
</div>
It's purpose is to repeat a directive a number of times
The <puppy-block></puppy-block> directive template is this:
<div class="puppyA" preview-pup>
<div class="clearfix puppyCover" dataPreview="{{p.dataPreview}}">
<a ng-href="{{p.link}}"><img ng-src="{{previewData[currentPosition]}}" /></a>
</div>
</div>
As you can see, there is another directive called preview-pup on every element.
The code for that directive is this:
obApp.directive('previewPup', ['$timeout',function($timeout){
return {
restrict: 'A',
link: function(scope, el, attr){
//some code that needs to run often
}
}
}]);
My pagination directive changes the data of the puppy-block directives when moving between different pages, however i also need to trigger the link function of the preview-pup directive, inside each puppy-block directive, when the change happens. Both the pagination directive and the ng-repeat directive have a common controller from which they draw data (modify data).
My problem is that i have no idea how to manually trigger a directive's link function on an ng-click, for instance. How may i do that?
Alright, found a solution:
Inject $routeScope into your controller and the directive you want to trigger a change in.
Use that to notify the child directive of a change in the parent controller. For more details - in case anyone stumbles upon this question looking for something similar - Angular.js trigger another directive
I had this same issue. Removing the "track by $index" from the ng-repeat fixed the it for me. Unfortunately I don't know why yet.
Please help me understand scopes in AngularJS.
If I associate a controller within a directive (as opposed to within html), is it supposed to have any impact on the scope associated with the directive ?
How can I use ng-repeat after scope isolation ?
For e.g. here is an example: http://plnkr.co/edit/0flo5mru61r9h3H8kiW5?p=preview
ex1. If I comment out (div ng-controller="Ctrl")[line 40, 43] and instead uncomment (// controller: 'Ctrl')[line 35] within the directive, why aren't the same scopes/hierarchy created (as viewed in Batarang).
ex2. How can I run ng-repeat for instructorList and profList (separately) without changing the current controller and only playing around with the scope ?
I am not sure how to inspect plunkers in batarang, but.
If you do this, you're instantiating the controller twice: once on each directive element. Each time you instantiate it, you're creating a new scope. As such, you have two separate sibling scopes. You can see just from looking at the html that the heirarchy won't be the same as if you had them both within the same element that has its own scope. In the latter case, changes made by child element 1 would affect the same scope used by child element two.
It's not very clear what you mean here. ng-repeat should be done in html. You could put it in the template like this:
template: '<label ng-repeat="person in teacherList">{{person.id}}<input ng-model="person.name"><br></label>'
See this
I have a directive that is repeated by an ng-repeat.
<div ng-repeat="p in people">
<p>{{p.name.first}}</p>
<slider-box
title-text="{{p.name.first}}"
body-text="Some body text"
img-src="{{p.photo}}"
more-link="#"></slider-box>
</div>
</div>
If I put a <p>{{p.name.first}}</p> before the directive, the p shows off a first name, but the slider-box doesn't seem to have access to p and therefore comes up blank as there's no data being given to it.
It probably isn't an async issue, as there are boxes being created, so angular knows that there is something to ng-repeat , and the <p> is getting filled in.
I've made an an example site here that shows an example of the directive with dummy data (just strings) and then the repeated ones are below that.
A very similar question has been asked here but no code examples were posted and the trail seems to have gone dead.
You should pass the attributes into the scope directly in the directive declaration.
In your directive declaration, instead of just having scope: {} , have something like scope:{ imgSrc:"#" }. It will pass the value of the attribute directly inside the isolated scope of your directive.
Take a look at this short tutorial for a better explanation.