AngularJS merge directives - angularjs

I hate it when I repeat code. So I want to know if there is a better way of doing this.
I have 2 directives, they are very simple and very similar.
The 2 directives look like this:
.directive('pkFilterProducts', function () {
return {
restrict: 'A',
templateUrl: 'assets/templates/directives/pkFilterProducts.html',
scope: {
products: '=pkFilterProducts',
filters: '='
}
}
})
.directive('pkStateProducts', function () {
return {
restrict: 'A',
templateUrl: 'assets/templates/directives/pkStateProducts.html',
scope: {
products: '=pkStateProducts',
states: '='
}
}
})
The only difference is one accepts filters and the other accepts states.
The templates are very similar too:
<div class="col-md-6">
<h3>Excluded ({{ excluded.length }})</h3>
<div class="table-responsive" ng-show="excluded.length">
<table class="table table-hover">
<thead>
<tr>
<th class="image-column"></th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="product in products | exclude: filters as excluded">
<td><img class="img-responsive" ng-src="{{ product.image }}" /></td>
<td>{{ product.shortTitle }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-md-6">
<h3>Included ({{ included.length }})</h3>
<div class="table-responsive" ng-show="included.length">
<table class="table table-hover">
<thead>
<tr>
<th class="image-column"></th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="product in products | include: filters as included">
<td><img class="img-responsive" ng-src="{{ product.image }}" /></td>
<td>{{ product.shortTitle }}</td>
</tr>
</tbody>
</table>
</div>
</div>
and
<div class="col-md-6">
<h3>Excluded ({{ excluded.length }})</h3>
<div class="table-responsive" ng-show="excluded.length">
<table class="table table-hover">
<thead>
<tr>
<th class="image-column"></th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="product in products | statesExclude: states as excluded">
<td><img class="img-responsive" ng-src="{{ product.image }}" /></td>
<td>{{ product.shortTitle }}</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-md-6">
<h3>Included ({{ included.length }})</h3>
<div class="table-responsive" ng-show="included.length">
<table class="table table-hover">
<thead>
<tr>
<th class="image-column"></th>
<th>Title</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="product in products | statesInclude: states as included">
<td><img class="img-responsive" ng-src="{{ product.image }}" /></td>
<td>{{ product.shortTitle }}</td>
</tr>
</tbody>
</table>
</div>
</div>
again, the only different is the ng-repeat filter. Instead of using include or exclude it uses statesInclude and statesExclude.
Is there a way I can combine these too? Maybe use a variable for the filter?

It might sound a bit too hacky but I'd join the two ng-repeats on a single template and use ng-ifs to make them check for which is valid/should run. Example:
<tr ng-if="states"
ng-repeat="product in products | statesInclude: states as included">
<td><img class="img-responsive" ng-src="{{ product.image }}" /></td>
<td>{{ product.shortTitle }}</td>
</tr>
<tr ng-if="filters"
ng-repeat="product in products | include: filters as included">
<td><img class="img-responsive" ng-src="{{ product.image }}" /></td>
<td>{{ product.shortTitle }}</td>
</tr>
You could then perhaps use a single directive declaration:
.directive('pkProducts', function () {
return {
restrict: 'A',
templateUrl: 'assets/templates/directives/pkProducts.html',
scope: {
products: '=pkFilterProducts',
filters: '=',
states: '='
}
}
})

I agree with wdanda.
Another solution would be to pass an boolean to your filter. Depending on the boolean you need to make it behave different.
See this for reference.

Related

Assign value after ng-if

I'm trying to do a table with ng-repeat. This is my code
<table class="tab2" >
<thead>
<tr>
<th>Currency: USD '000s</th>
<th ng-repeat="s in periodosCF">{{s.periodo | date:"yyyy"}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="n in nombreFilasCF" class="{{n.fondo}}">
<td style="width: 32%;"><div class="bordeTab">
<div class="{{n.color}}First" >
{{n.nombre}}
</div> <br>
</div>
</td>
<td ng-repeat="dato in datosCF" ng-if="n.nombre == dato.nombre">
<div class="{{n.color}}" >
{{dato.valor}}
</div><br>
</td>
</tr>
</tbody>
</table>
Once it enter to this ng-repeat="dato in datosCF", I do and if to print a value, but if the if returns me false I need to print this "-".
It sounds like you want to include all rows, but the content of the row is different based on some condition. If that's the case, you can try moving the conditional logic into the body of your <td> element, and having two divs with contradictory ng-if expressions:
<table class="tab2" >
<thead>
<tr>
<th>Currency: USD '000s</th>
<th ng-repeat="s in periodosCF">{{s.periodo | date:"yyyy"}}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="n in nombreFilasCF" ng-class="n.fondo">
<td style="width: 32%;"><div class="bordeTab">
<div ng-class="n.color + 'First'">
{{n.nombre}}
</div> <br>
</div>
</td>
<td ng-repeat="dato in datosCF">
<div ng-if="n.nombre === dato.nombre" ng-class="n.color">
{{dato.valor}}
</div>
<div ng-if="n.nombre !== dato.nombre">
-
</div><br>
</td>
</tr>
</tbody>
</table>
I also changed your interpolated class attributes to ng-class.

How can I can make ng-repeat as group?

Here Is my code.
<div class="panel-body">
<div class="row">
<div class="col-lg-12">
<div class="table-responsive">
<div id="exportable">
<table class="table table-striped table-bordered table-hover dataTable" id="example">
<thead>
<tr>
<th style="background-color: #f5f5f5;">Device Number</th>
<th style="background-color: #f5f5f5;">Name</th>
<th style="background-color: #f5f5f5;">MobileNumber</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="obj in SubscriptionList">
<td>
<button ng-if="obj.expanded" ng-click="obj.expanded = false">-</button>
<button ng-if="!obj.expanded" ng-click="obj.expanded = true">+</button>
</td>
<td>{{ obj.DEVICENUMBER}}</td>
<td>{{ obj.NAME}}</td>
<td>{{ obj.MOBILENUMBER}}</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- /.table-responsive -->
</div>
</div>
<!-- /.row -->
Result Is Coming like
Name Mobile Device
A 112 Nokia
A 112 Samsung
B 111 Videocon
B 111 LG
I want There is an expand button on Name,when I expand below all the details will show
You could use ng-repeat-start and ng-repeat-end and add an additional tr to your table with an ng-if. That way when you click on the button there will be an extra row just under the one which holds the button.
<div class="row">
<div class="col-lg-12">
<div class="table-responsive">
<div id="exportable">
<table class="table table-striped table-bordered table-hover dataTable" id="example">
<thead>
<tr>
<th style="background-color: #f5f5f5;">Device Number</th>
<th style="background-color: #f5f5f5;">Name</th>
<th style="background-color: #f5f5f5;">MobileNumber</th>
</tr>
</thead>
<tbody>
<tr ng-repeat-start="obj in SubscriptionList">
<td>
<button ng-if="obj.expanded" ng-click="obj.expanded = false">-</button>
<button ng-if="!obj.expanded" ng-click="obj.expanded = true">+</button>
</td>
<td>{{ obj.DEVICENUMBER }}</td>
<td>{{ obj.NAME }}</td>
<td>{{ obj.MOBILENUMBER }}</td>
</tr>
<tr ng-repeat-end ng-if="obj.expanded">
<td colspan="4">expanded</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>

Use directive in ng-repeat of a table

I want to create a customized row with two rows. One visible and another one collapsed.
This is my table:
<table class="table table-bordered panel panel-default centered">
<thead class="panel-heading">
<tr>
<td>..</td>
<td>..</td>
<td>.. GENERALE</td>
<td>..</td>
</tr>
</thead>
<tbody>
<table-row ng-repeat="(sottotarget,pubblicazione) in gestTrt.treat.pubblicazioni" sottotarget="sottotarget"></table-row>
</tbody>
</table>
My directive is:
<tr>
<td>
<div class="collapse navbar-collapse">
<a ng-click="tableRow.rowVar = !tableRow.rowVar" role="button"><span class="glyphicon glyphicon-plus-sign"></span></a>
</div>
</td>
<td>{{tableRow.sottotarget}}</td>
<td></td>
<td></td>
</tr>
<tr class="collapsed" ng-class="{'collapse' : !tableRow.rowVar}"><td><div>Should be collapsed</div></td></tr>
With the js code:
export function tableRow(): angular.IDirective {
return {
restrict: 'E',
scope: {
sottotarget: '=sottotarget'
},
templateUrl: '...',
controller: TableRowController,
controllerAs: 'tableRow',
bindToController: true
};
}
export class TableRowController {
public rowVar = false;
}
But in my page I visualize the two directives and then the empty table.
<div ng-app="" ng-controller="customersCtrl">
<table>
<tr ng-repeat="x in names">
<td>{{ x.Name }}</td>
<td>{{ x.Country }}</td>
</tr>
</table>
</div>
I resolved using
<tbody ng-repeat="(sottotarget,pubblicazione) in gestTrt.treat.pubblicazioni">
<tr>
<td>
<div class="collapse navbar-collapse" ng-init="collapsed = true">
<a ng-click="collapsed = !collapsed" role="button"><span class="glyphicon glyphicon-plus-sign"></span></a>
</div>
</td>
<td>{{tableRow.sottotarget}}</td>
<td></td>
<td></td>
</tr>
<tr class="collapsed" ng-class="{'collapse' : collapsed}">
<td colspan="4"><div>Should be collapsed</div></td>
</tr>
</tbody>

Multiple Filtered Counts with Angular

I have a list of users for each of my stores [model.stores.users] in JSON object and currently show the number of users against each store by accessing store.users.length
Now I want two extra counts, these counts are just based on the number of users with a simple boolean filter.
Count of Active Users is where user.is_user_active = true
Count of Pending Users is where user.is_user_active = false
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th class="hidden">ID</th>
<th>Name</th>
<th>Users</th>
</tr>
</thead>
<tbody class="tbl-jobs-data" ng-repeat="item in model.stores">
<tr data-toggle="collapse" class="accordion-toggle" data-target="#store_user{{$index}}">
<td class="hidden">{{item.id}}</td>
<td class="">{{item.name}}</td>
<td class="user-count">{{item.users.length}}</td>
</tr>
<tr ng-if="item.users.length > 0">
<td colspan="100" class="hiddenRow">
<div class="accordian-body collapse" id="store_user{{$index}}">
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>State</th>
<th>Is Active</th>
<th>Last Login</th>
</tr>
</thead>
<tbody class="tbl-search-data">
<tr ng-repeat="app in item.users">
<td>{{app.id}}</td>
<td>{{app.name}}</td>
<td>{{app.state}}</td>
<td>{{app.is_user_active}}</td>
<td>{{app.last_login}}</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
</div>
Just use filter, eg
<td class="active_user_count">
{{ (item.users | filter : { is_user_active: true }).length }}
</td>
<td class="pending_user_count">
{{ (item.users | filter : { is_user_active: false }).length }}
</td>
I hope I've got the syntax right, the Angular docs are down at the moment >:(

AngularJS ng-include finished

I'm loading a large amount of data using ng-include.
I'd like to know if there is a way to know when a template is "rendered", because sometimes it seems like it's been "frozen", because I want to do a "loading screen" or something.
Thx.
Here's the code
controller code:
$scope.layout = {
current: 'single-table.html'
};
$scope.layout.get = function() {
return $scope.layout.current;
};
templates:
main.html
<div class="btn-group">
<button ng-click="layout.current = 'single-table.html'">Single</button>
<button ng-click="layout.current = 'multiple-table.html'">Multiple</button>
</div>
<div ng-include="layout.get()"></div>
single-table.html
<table class="table table-bordered">
<thead>
<th ng-repeat="column in columns">{{ column.title }}</th>
</thead>
<tbody>
<tr ng-repeat="record in records">
<td ng-repeat="field in record.fields"
ng-controller="FieldController"
ng-class="getClass()">
{{ field.display }}
</td>
</tr>
</tbody>
</table>
multiple-table.html
<table class="table table-bordered" ng-repeat="record in records">
<tbody>
<tr ng-repeat="field in record.fields">
<th>{{ columns[$index].title }}</th>
<td ng-controller="FieldController" ng-class="getClass()">
{{ field.display }}
</td>
</tr>
</tbody>
</table>
EDIT
I'm using version 1.2.0
One solution (probably not the best) is doing this (no ng-include)
<table class="table table-bordered" ng-show="layout.current == 'single-table.html'">
<thead>
<th ng-repeat="column in columns">{{ column.title }}</th>
</thead>
<tbody>
<tr ng-repeat="record in records">
<td ng-repeat="field in record.fields"
ng-controller="FieldController"
ng-class="getClass()">
<span lud-run="{{ field.ng_directive }}"></span>
</td>
</tr>
</tbody>
</table>
<table class="table table-bordered" ng-repeat="record in records" ng-show="layout.current == 'multiple-table.html'">
<tbody>
<tr ng-repeat="field in record.fields">
<th>{{ columns[$index].title }}</th>
<td ng-controller="FieldController" ng-class="getClass()">
<span lud-run="{{ field.ng_directive }}"></span>
</td>
</tr>
</tbody>
</table>
I have only 20 records, but (is not in the code), each cells loads a custom directive depends on the data type (string, date, datetime, image...). This "solution" I think runs the same data twice (ng-show, not ng-if), but when a switch the layout mode there is no "lag".
You can use the onload hook on ng-include to update a variable when the include has finished rendering. If you set it to true on clicking your button, then revert it back to false in onload, you should be able to leverage it to temporarily display a loading screen.

Resources