<div ng-app="myapp">
<div ng-controller="Ctrl">
<table ng-grid >
<tr ng-repeat="todo in todos">
<td >{{todo.name}}</td>
<td >{{todo.estimate | number}}</td>
<td width="50">{{todo.done }}</td>
<td title="Create At">{{todo.created_at | date}}</td>
</tr>
</table>
</div>
</div>
And the javascript code is in http://jsfiddle.net/dalcib/J3fjc/ . I am new to AngularJS, I can understand the above html. Would someone please explain me what's really done there in the javascript?
It's one of the answers for How to do paging in AngularJS?.
From and Angular perspective, this is probably the most interesting javascript line:
angular.module('ngGrid', ['ngSkip']).directive('ngGrid', function() {
The line is doing two things. First defining an Angular module, and second, defining a new directive inside that module (named ngGrid). (As a side note, there is another very big project named ngGrid, and this does not seem to be related).
You'll see that inside the directive, an object is being built up and returned (direc). This defines the configuration of the directive. Once you read the Angular Directive documentation, the structure of the code should start to make sense.
I must say, you've picked a pretty sketchy example to start to understand. Perhaps, it would be better to start with the Angular Tutorial and build up from there.
A quick definition from the docs of what a directive is:
At a high level, directives are markers on a DOM element (such as an
attribute, element name, or CSS class) that tell AngularJS's HTML
compiler ($compile) to attach a specified behavior to that DOM element
or even transform the DOM element and its children.
Angular comes with a set of these directives built-in, like ngBind,
ngModel, and ngView. Much like you create controllers and services,
you can create your own directives for Angular to use. When Angular
bootstraps your application, the HTML compiler traverses the DOM
matching directives against the DOM elements.
Related
HTML
<table ng-show="ecu.dtcs">
<tbody>
<tr>
<td colspan="4">
<uib-accordion close-others="true">
<uib-accordion-group ng-repeat="dtc in dtcList track by $index">
...
</uib-accordion-group>
</uib-accordion>
</td>
</tr>
</tbody>
</table>
<uib-pagination
total-items="{{ totalItems }}"
ng-model="{{ currentPage }}"
items-per-page="{{ itemsPerPage }}"
boundary-link-numbers="true"
ng-change="setPagingData(currentPage)">
</uib-pagination>
JS (directive)
link: function (scope) {
scope.showEcuDetails = function (ecu) {
// For pagination
scope.itemsPerPage = 20;
scope.totalItems = ecu.dtcs.length;
scope.currentPage = 1;
scope.setPagingData = function(currentPage) {
var start = (currentPage - 1) * scope.itemsPerPage,
end = currentPage * scope.itemsPerPage;
scope.dtcList = ecu.dtcs.slice(start, end);
};
scope.setPagingData(scope.currentPage);
};
}
ecu.dtcs: Holds all the data that I want
dtcList: Holds the sliced list each 20 elements
I have used the Angular-Bootstrap documentation and have also referenced this source (except have used ng-change to alter the list instead of a $watch on the scope)
I have debugged the application thoroughly and I can see that dtcList is becoming populated wiht the first 20 elements. However, going into the HTML, there is nothing displayed
I have also tried to write a .filter (like is shown here) but because the variables are being set in the scope of the directive and not a controller, my filter, cannot see the variables
N.B: For the pagination settings, to reference the scope variables (i.e. totalItems), I have used Angular expressions like displayed in this question and also basic strings as in the documentation (i.e. "totalItems")
I think the concepts and the way I have it written at the moment should work, it's just the HTML cannot see dtcList for some reason
EDIT
It may help to know that this is in an angular-ui-bootstrap modal. Below the function call to setPagingData(), I have this:
$uibModal.open({
templateUrl: "ecuDialog.html",
size: "lg",
windowClass: "modalDialogs networkTest__largeContentDialog",
scope: scope
});
The templateUrl is that of which I've written in the HTML section of this question. It crossed my mind whether this was the issue but my colleagues have assured me that it would not impact the result in any way.
EDIT 2
Unfortunately, 1 of our colleagues who specialises in AngularJS has viewed the code along with the documentation and cannot see any errors within it. Could it be an Angular bug or is it the combination of multiple elements from angular-ui-bootstrap that it doesn't like?
Things I am combining are:
ui-modal
ui-accordion
ui-pagination
Solution:
My code was correct. My colleague had an attempts at it and just took the code I had written into another directive. We were both unsure why this was the case, maybe Angular doesn't like overcrowded directives?
I'm using twitter bootstrap with a popover and got a AngularJS scoped variable to appear correctly. The below works.
(data-content="{{notifications[0].user}} shared {{notifications[0].user_two}}'s records")
When I add the following
(data-content="<b>{{notifications[0].user}} shared {{notifications[0].user_two}}'s records</b>")
No errors show up, but all of the {{}} no longer render.
So I tried this as a test of sorts
(data-content="<div ng-repeat='item in notifications'>test {{item}} <br/><hr/></div>")
Much like the last example, I see the "test" but not the {{item}}. And the "test" only show s up once, even though the notifications had three elements. When I look at the DOM there's this
<div class="popover-content">
<div ng-repeat="item in notifications">you <br><hr></div>
</div>
I've also tried just creating a directive to iterate through the array and make the output I want, but my attempt to set data-content equal to a directive have been failures. The examples I've found elsewhere I'm confident would work, but I just wanted to confirm before I begin implementing something like this (http://tech.pro/tutorial/1360/bootstrap-popover-using-angularjs-compile-service) or (Html file as content in Bootstrap popover in AngularJS directive) that I'm not missing a straightforward fix to the problem I outlined above that would not require me creating a directive.
Edit:
Plunkr Url http://plnkr.co/edit/VZwax4X6WUxSpUTYUqIA?p=preview
html might be breaking it, try marking it as trusted html using $sce
How do you use $sce.trustAsHtml(string) to replicate ng-bind-html-unsafe in Angular 1.2+
$scope.html = '<ul><li>render me please</li></ul>';
$scope.trustedHtml = $sce.trustAsHtml($scope.html);
<button ... data-content="trustedHtml" ...> </button>
I would like to apologize that I couldn't provide any code snippet regarding this question, I am a newbie about AngularJS.
<div ng-repeat="item in list" ng-view></div>
Using the code above, would it be possible to render different template which would be dependent on item.type property. I was expecting a result like this:
item.type == "image" returning: <div><img src="'IMAGE_URI'"></div>
item.type == "text" returning: <div><p>TEXT</p></div>
As of now I have create a template html for the enumeration of item.type. Is this concern possible using AngularJS? I've recently learned that ng-view accompannied with ng-route.
I think one way you can do it is to use 'ng-if' to conditionally include html:
<div ng-repeat="item in list">
<div ng-if="item.type == 'image'><img src="'IMAGE_URI'"></div>
<div ng-if="item.type == 'text'><div><p>TEXT</p></div>
</div>
You can have only one ng-view,
take a look at this answer.
from the documentation for ng-view:
ngView is a directive that complements
the $route service by including the rendered
template of the current route into the main
layout (index.html) file.
Every time the current route changes,
the included view changes with it according
to the configuration of the $route service.
Requires the ngRoute module to be installed.
What you're looking for is ng-include, combined with ng-switch,
take a look at this answer on how to combine the two.
ng-include creates a new child scope, which in turn inherits from the controller.
have a look at this answer for more information about the topic.
Any Angular.js savvy person probably knows about this ...
Angular.js Root Error
My question is why and how do i get around this. When using tables it is not always possible to group the contents of your directive into a single parent element. So how do I get around this. I know ng-repeat does replace single elements with multiple, with out a parent wrapper, so it must be possible. What's the simplest way?
-- UPDATE --
Have ...
<td class="text-right">{{dsfgsdf.sdfgdsf.dsfg}}</td>
<td class="text-center">dsfgsdfg</td>
<td class="text-right">1500.00</td>
<td class="text-right">0.00</td>
<td class="text-right">2.51</td>
<td class="text-right">1502.51</td>
<td class="text-right">0.00</td>
<td class="text-center">-</td>
<td class="text-right">-1502.51</td>
<td class="text-right">-1502.51</td>
<td class="text-center">11/01/2013</td>
<td class="text-center">{{sdfg.sdfg}}</td>
<td class="text-center">{{sdfg.sdfg}} - {{dfg.sdfg}}</td>
<td class="text-left">sdfgdsfg</td>
Want to add a directive ...
<td class="text-right">{{dsfgsdf.sdfgdsf.dsfg}}</td>
<td detailsDirective></td>
<td class="text-center">{{sdfg.sdfg}}</td>
<td class="text-center">{{sdfg.sdfg}} - {{dfg.sdfg}}</td>
<td class="text-left">sdfgdsfg</td>
To answer the general question of why angular directive templates are restricted to one root array, I'll refer to this text in the link to the error:
When a directive is declared with template (or templateUrl) and
replace mode on, the template must have exactly one root element. That
is, the text of the template property or the content referenced by the
templateUrl must be contained within a single html element. For
example, <p>blah <em>blah</em> blah</p> instead of simply blah
<em>blah</em> blah. Otherwise, the replacement operation would result
in a single element (the directive) being replaced with multiple
elements or nodes, which is unsupported and not commonly needed in
practice.
Angular, in it's compile/link phases, needs to assign a hierarchical scope tree that corresponds to the DOM tree. So, angular needs a single DOM element to hang a new scope for the directive off of. That is essentially a limitation with how angular works. Therefore, the comment above that anything else is unsupported.
The single-root rule shouldn't make problems. If you don't want a wrapping element (span, for example) inside your TD, you can use "replace:true" with your detailsDirective
directive('detailsDirective', function() {
return {
replace: true,
template: '<td></td>', // wrapper
Also, See the transclude option, it can resolve your problem as well.
Otherwise, post here your directive's code.
So here is my question:
I have the following:
<li bindonce ng-repeat="value in Types" ng-include="'views/repeaters/types.html'"></li>
and I was wondering if this is the correct way to use the bindonce so that ng-repeat will not have a $watch? Should I also put it before the ng-include as well as so:
<li bindonce ng-repeat="value in Types" bindonce ng-include="'views/repeaters/types.html'"></li>
This way, the ng-include will not have a $watch created for it.
How about using bindonce for ng-class, ng-click - is it possible to do bo-click, and bo-class ? Thanks!
Regarding bo-click, I don't think it's possible, yet. But you can use bo-class if you need it. You can have a look at the full list of available directives within bindonce here.
Also, bindonce is the main directive. That means you just have to use it once and inside the wrapper/root element, you use the bo-* directives according to your needs.
Finally, there is no way currently to remove the watcher on ng-repeat. And if bindonce was in fact able to it, you would have to use something called bo-repeat or so. It's actually the same for all the directive brought by bindonce. You generally have to replace you ng-* directives with bo-* equivalent directives.