Insert Page Break after n number of rows - angularjs

I am using html2pdf to export html to pdf in AngularJS the issue I have is that I need to insert a page break after n number of rows.. BDW I am using dir-paginate...
Here is my code:
<tr data-index="{{$index}}"
dir-paginate="(ikey,iitem) in products | itemsPerPage:10">`
I tried different solutions but nothing works
I have to insert a div with class="html2pdf__page-break and repeat the header for example every 10 rows.

Simply take the rest of the division and check if it is a multiplier of 10, like so:
<div ng-repeat="item in items track by $index">
<div ng-if="$index % 10 == 0">
<!-- do something every 10 items -->
</div>
<div ng-if="$index % 10 != 0">
<!-- else do another something -->
</div>
<div>
<!-- do something everytime -->
</div>
</div>
You could do it using a function of something like that to keep it cleaner, but the ideia is the same.
Adapt it to your code, or add a codepen/jsfidle so we could help you better.
Happy coding :)

Related

How to create complex table which contains lots of data and supports expanding rows & fixed column using react-virtualized?

I'm creating excel-like table using react.
And there have some essential features.
Support update feature for the cells including child row's cells.
If head row's data can represents all of it's children's data and itself, it's cell will be merged into single cell and show in single cell.
Support row expanding feature :: When user click row, it expand and show it's children's data which has same columns with parent. (Like each row represents some aggregation of data, and with clicking row, user can see sub-data.
Should guarantee proper performance for more than 30000 rows with 100 columns including images.
Should support filter & sort & search & hide column(s).
Should provide data at single page (It means it need to be infinite-scroll, not pagenation)
Should have sticky table header
Should user can fix some of columns to left side for providing easier way to see data with horizontal scrolling.
I succeed on 1,2,3,4,5,6,7 (Most of them) by react-virtualized. But it become a problem when regarding '8'-Fixing column.
I checked internet and found that react-virtualized is the only way to archive it.
Basic idea of this is quite simple. I use List for rendering each row by user's scrolling(Virtualization), AutoSizer and CellMeasurer(Cache) for implementing dynamic height rows(Expanding rows). And least of codes for implementing TableHeader and cell updating, sort, filter features.
But it became a problem when I need to implement column fix. react-virtualized seems it dose not allow customization for it's feature (Seems really static for their functionalities.)
At first, I considered create two table and position it horizontally so that left table act like fixed column, right table is horizontally scrollable by sharing CellMeasurerCache for dynamic height row. But I found this article https://stackoverflow.com/questions/45682063/react-virtualized-share-cellmeasurercache-for-multiple-grids which says that CellMeasurerCache is not sharable by more than one List.
Also I considered that using other components react-virtualized support. But there are Pros and Cons for each components and I need to give up one of above requirements.
Can you provide me a idea for implementing all above requirements?
I want to share my code but it is quite big (About more than 1000lines for single table -- abstract table which is not hard coded for single purpose) If you want to see, I'll send you in anyway.
But I can provide basic HTML markups -- which is 8 is not implemented. and proven to be usable disregarding some bugs and errors.
This is not real HTML, I omit some of markups.
(All data is not calculated at table, all of them are fetched from other servers.)
<div class="table">
<!--Head part-->
<div class="headers">
<div class="header" style="display: sticky; top: 0">
<div class="upper">Name</div>
<div class="bottom">
<button class="sort" style="background-image: url(sort_asc.png)"></button>
<button class="filter" style="background-image: url(btn_filter.png)"></button>
</div>
</div>
<div class="header" style="display: sticky; top: 0">
<div class="upper">Price</div>
<div class="bottom">
<button class="sort" style="background-image: url(sort_asc.png)"></button>
<button class="filter" style="background-image: url(btn_filter.png)"></button>
</div>
</div>
<div class="header" style="display: sticky; top: 0">
<div class="upper">Gross</div>
<div class="bottom">
<button class="sort" style="background-image: url(sort_asc.png)"></button>
<button class="filter" style="background-image: url(btn_filter.png)"></button>
</div>
</div>
</div>
<!--Content part-->
<div class="row"/> <!-- This is expanded row -->
<div class="column" style="display:flex;flex-direction:column; height:120px;"/>
<div class="headCell" style="height:120px">ChicagoCompany</div> <!-- This is merged cell -->
<div>
<div class="column" style="display:flex;flex-direction:column; height:120px;"/>
<div class="headCell" style="height:40px">215</div> <!-- Display average value of child -->
<div class="cell" style="height:40px">230</div>
<div class="cell" style="height:40px">200</div>
<div>
<div class="column" style="display:flex;flex-direction:column; height:120px;"/>
<div class="headCell"style="height:120px">440</div> <!-- This is merged cell -->
<div>
</div>
<div class="row"/> <!-- This is not expanded row -->
<div class="column" style="display:flex;flex-direction:columnheight:40px"/>
<div class="headCell"style="height:40px">Seattle Corp</div> <!-- This is merged cell -->
<div>
<div class="column" style="display:flex;flex-direction:columnheight:40px"/>
<div class="headCell"style="height:40px">130</div> <!-- Display average value of child -->
<div>
<div class="column" style="display:flex;flex-direction:columnheight:40px"/>
<div class="headCell"style="height:40px">440</div> <!-- This is merged cell -->
<div>
</div>
</div>
What I considered above about append two table horizontally is like above
<div class="tableSet"><div class="fixedTable">...</div><div class="flexibleTable">...</div></div>
(Put two "table" together horizontally)
I tried to set sticky to all class <column>, but it dose not work as I expected. (It is not the same-level properties as you know.)
I think I can bypass restriction on CellMeaurerCache so that it can be shared in both table. But I have no idea for that. Can you give me a advice?
Is there any way to bypass restriction and implement all requirements? Or Is there any library or component or way to achieve it's goal even if it need to be re-build from the scratch?
Yes. It looks like that I want to Excel on webpage.

When does duplicate digest computations warrant redesign in AngularJS?

I have been working with AngularJS for a while now and this is one subject I still am not sure about. Let me start with an example. In my site I have a table with data. I want to be able to search/sort/filter this data in a number of ways. We have a search box that utilizes the built in "filter" filter to search the data. We also have a number of other filters that allows the user to check checkboxes and get different views (think Amazon).
The issue is because things like pagination need to know about these filters and must apply its computations based off the filtered view of data, not the original data set.
Doing so makes our HTML look like this:
<div class="row paginationInfo clearfix">
<div class="col-xs-3 showResultsWrap">
<span data-name="summary"><b>{{ getPageStart2((model.IndividualMailboxes.filtered | pipe:model.IndividualMailboxes.filters.functions:model.IndividualMailboxes.filters.values), model.IndividualMailboxes.currentPage, model.IndividualMailboxes.resultsPerPage) }} - {{ getPageEnd2((model.IndividualMailboxes.filtered | pipe:model.IndividualMailboxes.filters.functions:model.IndividualMailboxes.filters.values), model.IndividualMailboxes.currentPage, model.IndividualMailboxes.resultsPerPage) }}</b> of <b>{{ (model.IndividualMailboxes.filtered | pipe:model.IndividualMailboxes.filters.functions:model.IndividualMailboxes.filters.values).length }}</b></span>
</div>
<div class="col-xs-6 text-xs-center">
<div max-size="5" boundary-links="true" first-text="«" last-text="»" previous-text="‹" next-text="›" uib-pagination ng-show="(model.IndividualMailboxes.filtered | pipe:model.IndividualMailboxes.filters.functions:model.IndividualMailboxes.filters.values).length > 10" total-items="(model.IndividualMailboxes.filtered | pipe:model.IndividualMailboxes.filters.functions:model.IndividualMailboxes.filters.values).length" ng-model="model.IndividualMailboxes.currentPage" items-per-page="model.IndividualMailboxes.resultsPerPage" class="pagination-md"></div>
</div>
<div class="col-xs-3 resultsPerPageWrap form-inline text-xs-right">
<span>View</span>
<select sk-id-gen="resultsPerPage" name="ResultsPerPage" class="form-control m-l-1" ng-model="model.IndividualMailboxes.resultsPerPage" ng-options="val as val for val in [10, 20, 50, 100]">
</select>
</div>
</div>
The important thing to notice here is how many times we have to do (hereIsMyArray | pipe:param1:param2).length over and over again for the pagination to work.
So correct me if I am wrong, but I believe every digest cycle we are running these pipes/filters 5+ times. This is probably OK with a small dataSet, but if I start having to filter 10,000 items then I'm sure I will see performance issues.
It would be much more efficient if we only had to do the pipe/filtering 1 time and each of these HTML components could just use that single instance of the filtered data set.
The issue with not doing it directly in the HTML is you no longer have automatic watches setup to see when data changes and updates the view.
If any of my statements are wrong please let me know. I am curious if anyone has had this issue before and has a solution?
Thanks

Angular 2 - *ngFor : Is there a way to use an alternative end condition?

I come here because after many hours googling, I didn't find a way to use an alternative stop condition for the loops made with the built-in directive : *ngFor.
Actually any *ngFor finish the loop with this condition : index < array.length. I want to know if there is a way to end a loop with another condition like : i < myVariable.
If you wonder why I want to do that, it's because I'm working on a picture gallery working this way :
<div *ngFor="let pic of pics; let i = index">
<div *ngIf="whichRowType(i) == 3">
<small>pic[whichIndex(i)].id</small>
<small>pic[currentIndex + 1].id</small>
<small>pic[currentIndex + 2].id</small>
</div>
<div *ngIf="whichRowType(i) == 2">
<small>pic[whichIndex(i)].id</small>
<small>pic[currentIndex + 1].id</small>
</div>
<div *ngIf="whichRowType(i) == 1">
<small>pic[whichIndex(i)].id</small>
</div>
</div>
In this example, I create a row each 3 pics. I have three types of rows :
- Display one pic,
- Display two pics,
- Display three pics.
The problem is, the index of my first picture on each row is always inferior to the index used to display the row. So if I want to be able to display all my pictures, I have to be able to change my ending condition of my *ngFor.
Thank you very much for your help!
*ngFor provides a last value:
<div *ngFor="let pic of pics; let i = index; let last=last">
<div *ngIf="last">
...
</div>
</div>
See also Implementing ngClassEven ngClassOdd for angular 2
I finally solved my issue an ugly but working way...
Instead of writing another end condition I did make a loop with an array of length that is calculated by a function. I read my other array (the one with my pics) in that loop.
Angular should really make something for that!
Thank you for your help guys!
Example of how to solve it :
<div *ngFor="let galleryIndex of galleryIndexes; let i = index">
<div *ngIf="whichRowType(galleryIndex) == 3">
<small>pics[setCurrentIndex(galleryIndex)].id</small>
<small>pics[currentIndex + 1].id</small>
<small>pics[currentIndex + 2].id</small>
</div>
<div *ngIf="whichRowType(galleryIndex) == 2">
<small>pics[setCurrentIndex(galleryIndex)].id</small>
<small>pics[currentIndex + 1].id</small>
</div>
<div *ngIf="whichRowType(galleryIndex) == 1">
<small>pics[setCurrentIndex(galleryIndex)].id</small>
</div>
</div>

Angularjs & Bootstrap - ng-repeat list filling

Actually, I have an array of cars with several information. I want to display the data as following:
I am using ng-repeat with % operator to determine the position, but the problem is that $index % 4 == 0 is also true for $index % 2 == 0 if for example $index is 8 or 16..
How can i solve this?
If you are using bootstrap you just need to use bootstrap smartly to have this kind of view
This is how you can do it:
<div class="row">
<div class="col-md-3" data-ng-repeat="car in cars">
{{ car.name }}
</div>
<div>

AngularJS how to dynamically split list in multiple columns

I have a number of li items which I want evenly distributed across 3 different columns. So I need the 1st third of the list items to be shown in the first ul, the next third in the 2nd ul etc.
Right know my approach is somewhat static:
<ul class="small-12 medium-4 columns">
<li ng-repeat="skill in skills.development | slice:0:10">
{{ skill.name }}
</li>
</ul>
<ul class="small-12 medium-4 columns">
<li ng-repeat="skill in skills.development | slice:10:21">
{{ skill.name }}
</li>
</ul>
<ul class="small-12 medium-4 columns">
<li ng-repeat="skill in skills.development | slice:21:32">
{{ skill.name }}
</li>
</ul>
I create the 3 rows in my template and then I created a custom filter that slices the list so I can obtain the first 11 elements, the next 11 elements and so forth. Problem is that the number of rows in each ul is not assigned dynamically like so:
Math.ceil(skills.development.length / 3)
So if I have more elements I will have to manually change the number of rows. Filtering is an issue as well. Imagine that I search for a word with 5 matches in first column and one in the 2nd column. Then I would have completely uneven column sizes. The length should be recalculated dynamically when I filter the list.
Ideally not only the number of rows in a column is calculated dynamically, but also the number of columns. So if there are more than say 15 elements it should render three columns, but if there is only 10 elements 2 columns will look better (as there is only 5 elements in each). And if there are less than 5 elements only one column will be rendered.
I figured that I should either try to solve it in the view or make some sort of helper function similar to the custom filter function I already wrote. But how might I do that?
Create a columns array with start and end values for each column and use a nested repeater to loop through all the data and render properly.
<ul ng-repeat="column in columns" class="small-12 medium-4 columns">
<li ng-repeat="skill in skills | slice:column.start:column.end">
{{ skill }}
</li>
</ul>
Full plnkr here: http://plnkr.co/edit/AMWLvB045UJmNamp8vdz?p=preview

Resources