AngularJS - ng-repeat show header just once - javascript

I have 2 lists (persons and animals) that I'm displaying with ng-repeat. I want to show these two lists in one table with a heading.
Here is an example how I want to show the data.
I already tried it with ng-show="$first", but that is not the result I want to achieve.
<thead>
<tr>
<th>ID</th>
<th>BIRTHDAY</th>
<th>NAME</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="ps in $ctrl.persons" ng-if="$ctrl.valuePersons == true">
<th ng-show="$first">PERSONS</th>
<td>{{ ps.id }}</td>
<td>{{ ps.birthday | date: 'dd.MM.yyyy'}}</td>
<td>{{ ps.name }}</td>
</tr>
<tr ng-repeat="an in $ctrl.animals" ng-if="$ctrl.valueAnimals == true">
<th ng-show="$first">ANIMALS</th>
<td>{{ an.id }}</td>
<td>{{ an.birthday | date: 'dd.MM.yyyy'}}</td>
<td>{{ an.name }}</td>
</tr>
<tbody>

This will work, as per the documentation for ng-repeat.
...
<tr ng-repeat-start="ps in $ctrl.persons" ng-if="$ctrl.valuePersons == true && $first">
<th>PERSONS</th>
<td></td>
<td></td>
</tr>
<tr ng-repeat-end ng-if="$ctrl.valuePersons == true && !$first">
<td>{{ ps.id }}</td>
<td>{{ ps.birthday | date: 'dd.MM.yyyy'}}</td>
<td>{{ ps.name }}</td>
</tr>
...

This is long but can help you...
<table>
<tr>
<th>ID</th>
<th>BirthDay</th>
<th>NAME</th>
</tr>
<tr>
<td>Persons</td>
<td></td>
<td></td>
</tr>
<tr ng-repeat="ps in $ctrl.persons">
<td>{{ps.id}}<td/>
<td>{{ps.bday}}<td/>
<td>{{ps.name}}<td/>
</tr>
<tr>
<td>Animals</td>
<td></td>
<td></td>
</tr>
<tr ng-repeat="ps in $ctrl.animals">
<td>{{ps.id}}<td/>
<td>{{ps.bday}}<td/>
<td>{{ps.name}}<td/>
</tr>
</table>

var app = angular.module("Profile", [] );
app.controller("ProfileCtrl", function($scope) {
$scope.items = [{'title':'PERSON','data':[{'birth_day':'1/1/2011','name':'a1'},{'birth_day':'1/1/2011','name':'a2'},{'birth_day':'1/1/2011','name':'a3'}]},{'title':'ANIMALS','data':[{'birth_day':'1/1/2011','name':'a1'},{'birth_day':'1/1/2011','name':'a2'},{'birth_day':'1/1/2011','name':'a3'}]}]
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="Profile" ng-controller="ProfileCtrl">
<table class="table" border="1">
<thead>
<tr>
<th>ID</th>
<th>BIRTHDAY</th>
<th>Name</thu>
</tr>
</thead>
<tbody>
<tr ng-repeat-start="item in items" ng-init="main_ind= $index">
<td colspan="3">{{item['title']}}</td>
</tr>
<tr ng-repeat-end ng-repeat="val in item['data']">
<td>{{$index+1}}</td>
<td>{{val['birth_day']}}</td>
<td>{{val['name']}}</td>
</tr>
</tbody>
</table>
</body>

Related

problem with vue draggable width in table?

I'm using vuedraggable inside a Bulma table, but it creates a styling problem:
It's not a problem of the Bulma table. I used this in my own table, and the same issue occurs.
Here is my code:
<table class="table is-fullwidth is-bordered">
<thead>
<tr>
<th></th>
<th>Name</th>
<th>brand</th>
<th>Date Created</th>
<th colspan="2">Actions</th>
</tr>
</thead>
<tfoot>
<tr>
<th></th>
<th>Name</th>
<th>brand</th>
<th>Date Created</th>
<th colspan="2">Actions</th>
</tr>
</tfoot>
<tbody>
<tr>
<td colspan="5" v-if="featureds.length == 0">0 Models Found</td>
</tr>
<draggable v-model="furds" :options="{group:'furds'}" #start="drag=true" #end="drag=false" #change="onChnage">
<tr class="dragndrop" v-for="featured in furds">
<td class="drag-icon"><i class="fa fa-arrows"></i></td>
<td>{{ featured.name }}</td>
<td>{{ featured.brand.name }}</td>
<td>{{ featured.created_at | moment("MMMM Do, YYYY") }}</td>
<td><a :href="`/manage/featured/${featured.id}`">View</a></td>
<td><a :href="`/manage/featured/${featured.id}/edit`">Edit</a></td>
</tr>
</draggable>
</tbody>
</table>
Instead of wrapping tr with draggable,pass tbody as draggable element.
<draggable element="tbody" v-model="furds">
See the link for better understanding:
https://jsfiddle.net/dede89/L54yu3L9/ (Example with table) (found in vue draggable official doc)
[[Update: full code(based on question)]]
<table class="table is-fullwidth is-bordered">
<thead>
<tr>
<th></th>
<th>Name</th>
<th>brand</th>
<th>Date Created</th>
<th colspan="2">Actions</th>
</tr>
</thead>
<tfoot>
<tr>
<th></th>
<th>Name</th>
<th>brand</th>
<th>Date Created</th>
<th colspan="2">Actions</th>
</tr>
</tfoot>
<draggable element="tbody" v-model="furds"> <!-- change here -->
<tr>
<td colspan="5" v-if="featureds.length == 0">0 Models Found</td>
</tr>
<tr class="dragndrop" v-for="featured in furds">
<td class="drag-icon"><i class="fa fa-arrows"></i></td>
<td>{{ featured.name }}</td>
<td>{{ featured.brand.name }}</td>
<td>{{ featured.created_at | moment("MMMM Do, YYYY") }}</td>
<td><a :href="`/manage/featured/${featured.id}`">View</a></td>
<td><a :href="`/manage/featured/${featured.id}/edit`">Edit</a></td>
</tr>
</draggable>
</table>
<script>
import draggable from "vuedraggable";
export default {
components: {
draggable
},
...
}
</script>
The styling issue occurs because vuedraggable uses a <div> as its root element by default, and that <div> (along with its contents) is stuffed into the first column of the table.
Solution: vuedraggable allows changing its root element with the tag property, so you could set it to tbody, replacing the existing <tbody> in the <table>:
<table>
<!-- FROM THIS: -->
<!--
<tbody> 👈
<draggable> 👈
<tr v-for="featured in furds">
...
</tr>
</draggable>
</tbody>
-->
<!-- TO THIS: -->
<draggable tag="tbody">
<tr v-for="featured in furds">
...
</tr>
</draggable>
<table>

$watch in filtering date

So I find this filter here in SO and this filter doesn't have a $watch.
filter.js
.filter('myfilter', function ($filter, moment) {
return function (items, from, to) {
return $filter('filter')(items, 'name', function (v) {
var date = moment(v);
return date >= moment(from) && date <= moment(to);
});
};
})
table.html
<table class="table table-bordered table-sm">
<thead class="">
<tr>
<th>DAY</th>
<th>TIME IN</th>
<th>TIME OUT</th>
<th>DETAILS</th>
<th>TOTAL HOURS</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="attendance in displayedCollection | myfilter: startDate: endDate">
<td>{{ attendance.day | date: 'EEEE, MMM d'}}</td>
<td>{{ attendance.timeIn | date:'h:mm a' }}</td>
<td>{{ attendance.timeOut | date:'h:mm a'}}</td>
<td class="text-capitalize">
<i class="fa fa-map-marker" aria-hidden="true"></i> {{ attendance.details }}</td>
<td>{{ attendance.totalHrs | date:'hh:mm'}} </td>
</tr>
</tbody>
<tfoot>
<tr>
<td>
<strong>Total</strong>
</td>
<td></td>
<td></td>
<td></td>
<td>
<strong>{{ vm.attendance.total }}</strong>
</td>
</tr>
</tfoot>
</table>
How do I watch the filter because displayedCollection.length is not changing?

How to show inline details for html table with a toggle button using typescript

I need to create a toggle button for my table (to show/hide) more details of selected row.
Given this is my table:
<table>
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
</tr>
<tr *ngFor='let c of companies'>
<td><button id="{{c.companyId}}" (click)="showDetail()">Details</button> </td>
<td>{{ c.company}}</td>
<td>{{ c.contact}}</td>
<td>{{ c.country }}</td>
</tr>
</table>
When I click on "Details" button, need to show details inline in the table. This is kind of master detail grid approach in Kendo Grid. Any better approach using Angular2 & typescript to show details in easy way?
A small change from birwin's answer, as you cannot use template here without a directive, so use ng-container instead.
<ng-container *ngFor='let c of companies'>
<tr>
<td><button id="{{c.companyId}}" (click)="c.details = !c.details">Details</button> </td>
<td>{{ c.company}}</td>
<td>{{ c.contact}}</td>
<td>{{ c.country }}</td>
</tr>
<tr *ngIf="c.details">
<td>Details</td>
</tr>
</ng-container>
Demo
You could try something like this:
<table>
<tr>
<th>Company</th>
<th>Contact</th>
<th>Country</th>
</tr>
<ng-container *ngFor='let c of companies'>
<tr>
<td><button id="{{c.companyId}}" (click)="c.details = !c.details">Details</button> </td>
<td>{{ c.company}}</td>
<td>{{ c.contact}}</td>
<td>{{ c.country }}</td>
</tr>
<tr *ngIf="c.details">
<td>Details go here</td>
<td>More details</td>
<td>More details</td>
</tr>
</ng-container>
</table>

Add multi-row items to a table with a directive

This is my model:
$scope.orders = [
{
id: 234324,
created: '2015-05-01T13:53:25.366Z',
orderedBy: 'John Smith',
items: [
{
itemNumber: '225-3',
count: 3,
state: 'Sent'
},
{
itemNumber: '3423-1',
count: 1,
state: 'Waiting from supplier'
}
]
},
{
id: 423423,
created: '2015-06-01T13:53:25.366Z',
orderedBy: 'Eva Andersson',
items: [
{
itemNumber: '423-3',
count: 1,
state: 'Sent'
},
{
itemNumber: '234-3',
count: 3,
state: 'Sent'
}
]
}
]
Its a list with orders where each order has an array with items.
I want to show this in table.
I tried do nest ng-repeats but it proved to be difficult with the static html syntax of a table. I think I manually have to add the subelements somehow. I'm not really sure how.
JsFiddle: http://jsfiddle.net/hadey1cf/4/
Any ideas?
You can have multiple tbody so it's easy to do:
JSFiddle
<tbody ng-repeat="order in orders">
<tr class="active">
<td><b>{{order.id}}</b></td>
<td><b>{{order.orderedBy}}</b></td>
<td>{{order.created | date:'yyyy-MM-dd'}}</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr ng-repeat="item in order.items">
<td></td>
<td></td>
<td></td>
<td>{{item.itemNumber}}</td>
<td>{{item.count}}</td>
<td><span class="label label-success label">{{item.state}}</span></td>
</tr>
</tbody>
Why don't you use nested repeats? Do your first repeat on the tbody and inside it repeat over the rows for the items:
http://jsfiddle.net/mcgraphix/kfnvLts0/1/
<table class="table">
<thead>
<tr>
<th>Order Id</th>
<th>Orderd By</th>
<th>Created</th>
<th>Item id</th>
<th>Count</th>
<th>State</th>
</tr>
</thead>
<tbody ng-repeat="order in orders">
<tr class="active">
<td><b>{{order.id}}</b></td>
<td><b>{{order.orderedBy}}</b></td>
<td>{{order.date | date:'yyyy-MM-dd'}}</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr ng-repeat="item in order.items">
<td></td>
<td></td>
<td></td>
<td>{{item.itemNumber}}</td>
<td>{{item.count}}</td>
<td><span class="label label-success label">{{item.state}}</span></td>
</tr>
</tbody>
</table>
An alternative approach if you for some reason don't want more than one tbody in your table is to use the ng-repeat-start and ng-repeat-end directives as shown here:
<table class="table">
<thead>
<tr>
<th>Order Id</th>
<th>Orderd By</th>
<th>Created</th>
<th>Item id</th>
<th>Count</th>
<th>State</th>
</tr>
</thead>
<tbody>
<!-- repeat will start with this but won't end with the closing tr tag
Instead it will end at the ng-repeat-end directives closing tag. see below-->
<tr class="active" ng-repeat-start="order in orders">
<td><b>{{order.id}}</b></td>
<td><b>{{order.orderedBy}}</b></td>
<td>{{order.date | date:'yyyy-MM-dd'}}</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr ng-repeat="item in order.items">
<td></td>
<td></td>
<td></td>
<td>{{item.itemNumber}}</td>
<td>{{item.count}}</td>
<td><span class="label label-success label">{{item.state}}</span></td>
</tr>
<!-- the outer repeat will end when this tag is closed. I'm seeting "display:none" so that it doesn't show a gap in your table -->
<tr ng-repeat-end><td colspan="6" style="display:none"></td></tr>
</tbody>
</table>
I think my first answer is a better way to go though since logically you have groups of content in your table which is what tbody is for. It is valid html to have more than one as the HTML DTD states:
<!ELEMENT table
(caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))>
However, it is good to understand how the ng-repeat-start and ng-repeat-end works as there are many cases where this is useful.
You can use the ng-repeat-start and ng-repeat-end directive.
You can find more information about it here
Please see working example
<script type="text/ng-template" id="orders.tmpl.html">
<h2 class="page-header">Orders-directive</h2>
<table class="table">
<thead>
<tr>
<th>Order Id</th>
<th>Orderd By</th>
<th>Created</th>
<th>Item id</th>
<th>Count</th>
<th>State</th>
</tr>
</thead>
<tbody>
<tr class="active" ng-repeat-start="order in orders">
<td><b>{{order.id}}</b></td>
<td><b>{{order.orderedBy}}</b></td>
<td>{{order.date | date:'yyyy-MM-dd'}}</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr ng-repeat-end="" ng-repeat="item in order.items">
<td></td>
<td></td>
<td></td>
<td>{{ item.itemNumber }}</td>
<td>{{ item.count }}</td>
<td><span class="label" data-ng-class="{'label-success':item.state=='Sent', 'label-primary':item.state=='Waiting from supplier'}">{{ item.state }}</span></td>
</tr>
</tbody>
{{content}}
</script>

Collapse groups

Helo,
i have a table with groupsand i want to know how i can collapse categories in my table
Plunker
My HTML:
<table border=1>
<thead>
<tr>
<th>Name</th>
<th>Gender</th>
</tr>
</thead>
<tbody ng-repeat="group in groups">
<tr>
<td style=" background-color: #006DCC;color: white;" colspan="2">{{group.name}}</td>
</tr>
<tr ng-repeat="member in group.members">
<td>{{ member.name }}</td>
<td>{{ member.age }}</td>
</tr>
</tbody>
</table>
Just wire in a variable to toggle it with ng-hide:
<tr>
<td style=" background-color: #006DCC;color: white;" colspan="2" data-ng-click="hideGroup = !hideGroup">{{group.name}}</td>
</tr>
<tr ng-repeat="member in group.members" data-ng-hide="hideGroup">
<td>{{ member.name }}</td>
<td>{{ member.age }}</td>
</tr>
Updated plunker: http://plnkr.co/edit/ABJ9It8qSqkPGzpYNyMp?p=preview

Categories