new component for infinite scroll vnAutoPaging

This commit is contained in:
Daniel Herrero 2018-04-30 13:57:10 +02:00
parent aa1797d137
commit a7e5f1a623
14 changed files with 220 additions and 18 deletions

View File

@ -14,11 +14,11 @@
<vn-horizontal
class="list list-element text-center"
pad-small-bottom
ng-repeat="greuge in index.model.instances track by greuge.id">
<vn-one pad-medium-h>{{::greuge.shipped | date:'dd/MM/yyyy HH:mm' }}</vn-one>
<vn-two pad-medium-h>{{::greuge.description}}</vn-two>
<vn-one pad-medium-h>{{::greuge.amount | number:2}} €</vn-one>
<vn-one pad-medium-h>{{::greuge.greugeType.name}}</vn-one>
ng-repeat="greuge in $ctrl.instances track by $index">
<vn-one pad-medium-h>{{greuge.shipped | date:'dd/MM/yyyy HH:mm' }}</vn-one>
<vn-two pad-medium-h>{{greuge.description}}</vn-two>
<vn-one pad-medium-h>{{greuge.amount | number:2}} €</vn-one>
<vn-one pad-medium-h>{{greuge.greugeType.name}}</vn-one>
</vn-horizontal>
</vn-one>
<vn-one class="text-center pad-small-v" ng-if="index.model.count === 0" translate>No results</vn-one>
@ -28,7 +28,8 @@
<vn-one pad-medium-h ng-if="index.model.count > 0">{{edit.model.sumAmount | number:2}} €</vn-one>
<vn-one pad-medium-h></vn-one>
</vn-horizontal>
<vn-paging margin-large-top vn-one index="index" total="index.model.count"></vn-paging>
<!--<vn-paging margin-large-top vn-one index="index" total="index.model.count"></vn-paging>-->
<vn-auto-paging margin-large-top vn-one index="index" total="index.model.count" items="$ctrl.instances"></vn-auto-paging>
</vn-vertical>
</vn-card>
</vn-vertical>

View File

@ -0,0 +1,7 @@
<vn-horizontal margin-medium-top>
<vn-one></vn-one>
<vn-auto>
<vn-spinner enable="$ctrl.watchScroll"></vn-spinner>
</vn-auto>
<vn-one></vn-one>
</vn-horizontal>

View File

@ -0,0 +1,118 @@
import ngModule from '../../module';
import getWatchers from '../../lib/get-watchers';
class AutoPaging {
constructor($http, $window, $element, $timeout, vnApp, $translate) {
this.$http = $http;
this.$window = $window;
this.$element = $element;
this.$timeout = $timeout;
this.vnApp = vnApp;
this.$translate = $translate;
this.numPerPage = null;
this.maxItems = 0;
this.watchScroll = false;
this.waitingNewPage = false;
this.handlerScroll = this.onScroll.bind(this);
}
get numPages() {
return this.numPerPage ? Math.ceil(this.maxItems / this.numPerPage) : 0;
}
loadNewPage() {
this.index.filter.page++;
this.waitingNewPage = true;
this.index.accept().then(res => {
this.$timeout(() => {
res.instances.forEach(item => {
this.items.push(item);
});
this.checkWatchers();
});
if (this.index.filter.page == this.numPages) {
this.cancelScroll();
}
this.waitingNewPage = false;
});
}
checkPosition() {
let element = this.$element[0].querySelector('vn-spinner');
let position = element.getBoundingClientRect();
if (this.currentPage < this.numPages && position.y < document.body.offsetHeight + 150 && !this.waitingNewPage) {
this.loadNewPage();
}
}
onScroll() {
this.checkPosition();
}
startScroll() {
this.watchScroll = true;
this.checkPosition();
angular.element(this.$window).bind("wheel", this.handlerScroll);
}
cancelScroll() {
this.watchScroll = false;
angular.element(this.$window).unbind("wheel", this.handlerScroll);
}
checkScroll() {
if (this.numPages > this.currentPage && !this.watchScroll) {
this.startScroll();
} else if (this.numPages <= this.currentPage && this.watchScroll) {
this.cancelScroll();
}
}
checkWatchers() {
let watchers = getWatchers();
if (watchers > 3000 && this.watchScroll) {
this.cancelScroll();
this.vnApp.showMessage(
this.$translate.instant('Auto-scroll interrupted, please adjust the search')
);
}
}
$onChanges(changes) {
if (!this.index) return;
this.numPerPage = this.index.filter.size;
this.currentPage = this.index.filter.page;
this.currentInstances = this.items;
if (changes.total)
this.maxItems = changes.total.currentValue;
this.checkScroll();
}
$postLink() {
this.checkScroll();
}
$doCheck() {
if (this.index && this.index.filter && this.index.filter.page && this.index.filter.page != this.currentPage) {
this.currentPage = this.index.filter.page;
this.checkScroll();
}
}
}
AutoPaging.$inject = ['$http', '$window', '$element', '$timeout', 'vnApp', '$translate'];
ngModule.component('vnAutoPaging', {
template: require('./auto-paging.html'),
bindings: {
index: '<',
total: '<',
items: '<'
},
controller: AutoPaging
});

View File

@ -0,0 +1,61 @@
import './auto-paging.js';
import template from './auto-paging.html';
describe('Component vnAutoPaging', () => {
let $http;
let $window;
let $element;
let $timeout;
let controller;
beforeEach(() => {
angular.mock.module('client');
});
beforeEach(angular.mock.inject((_$componentController_, _$httpBackend_, _$window_, _$timeout_) => {
$http = _$httpBackend_;
$window = _$window_;
$timeout = _$timeout_;
$element = angular.element(`<div>${template}</div>`);
controller = _$componentController_('vnAutoPaging', {$http, $window, $element, $timeout});
}));
describe('onChanges: actions when index object changes', () => {
beforeEach(() => {
controller.index = {
filter: {
size: 5,
page: 1
}
};
controller.items = [1, 2, 3, 4, 5];
});
it('call startScroll() if there are pages to load', () => {
let changes = {
total: {
currentValue: 20
}
};
spyOn(controller, 'startScroll');
controller.$onChanges(changes);
expect(controller.startScroll).toHaveBeenCalled();
});
it('call stopScroll() if there are not pages to load', () => {
let changes = {
total: {
currentValue: 5
}
};
controller.watchScroll = true;
spyOn(controller, 'cancelScroll');
controller.$onChanges(changes);
expect(controller.cancelScroll).toHaveBeenCalled();
});
});
});

View File

@ -31,3 +31,4 @@ import './switch/switch';
import './float-button/float-button';
import './step-control/step-control';
import './label-value/label-value';
import './auto-paging/auto-paging';

View File

@ -9,6 +9,7 @@ export default class FilterList {
this.waitingMgCrud = 0;
this.modelId = $state.params.id;
this.instances = [];
}
onOrder(field, order) {
this.filter(`${field} ${order}`);
@ -27,7 +28,9 @@ export default class FilterList {
this.$.index.filter.order = order;
}
this.$.index.accept();
this.$.index.accept().then(res => {
this.instances = res.instances;
});
} else if (!this.modelId || !this.modelName) {
throw new Error('Error: model not found');
} else if (this.waitingMgCrud > 3) {

View File

@ -12,3 +12,4 @@ import './copy';
import './equals';
import './modified';
import './key-codes';
import './get-watchers';

View File

@ -10,4 +10,5 @@ No more results: No more results
Hide: Hide
Next: Next
Finalize: Finalize
Previous: Back
Previous: Back
Auto-scroll interrupted, please adjust the search: Auto-scroll interrupted, please adjust the search

View File

@ -10,4 +10,5 @@ No more results: No hay más resultados
Hide: Ocultar
Next: Siguiente
Finalize: Finalizar
Previous: Anterior
Previous: Anterior
Auto-scroll interrupted, please adjust the search: Auto-scroll interrumpido, por favor ajusta la búsqueda

View File

@ -15,11 +15,12 @@
</vn-card>
<vn-card margin-medium-top>
<vn-item-product
ng-repeat="item in index.model.instances"
ng-repeat="item in $ctrl.items track by $index"
item="item">
</vn-item-product>
</vn-card>
<vn-paging index="index" total="index.model.count"></vn-paging>
<!-- <vn-paging index="index" total="index.model.count"></vn-paging> -->
<vn-auto-paging index="index" total="index.model.count" items="$ctrl.items"></vn-auto-paging>
</div>
</div>
<a ui-sref="item.create" vn-bind="+" fixed-bottom-right>

View File

@ -9,9 +9,12 @@ class ItemList {
this.$scope = $scope;
this.model = {};
this.itemSelected = null;
this.items = [];
}
search(index) {
index.accept();
index.accept().then(res => {
this.items = res.instances;
});
}
cloneItem(item) {
this.itemSelected = item;

View File

@ -16,8 +16,12 @@ describe('ticket', () => {
$componentController = _$componentController_;
$httpBackend = _$httpBackend_;
$scope = $rootScope.$new();
$scope.index = {model: {instances: [{id: 1}, {id: 2}]}, accept: () => {}};
$state = _$state_;
$scope.index = {model: {instances: [{id: 1}, {id: 2}]}, accept: () => {
return {
then: () => {}
};
}};
$state = _$state_;
$state.params.id = 101;
controller = $componentController('vnTicketVolume', {$scope: $scope}, {$httpBackend: $httpBackend}, {$state: $state});
}));

View File

@ -6,9 +6,9 @@ module.exports = Self => {
where: {
clientFk: params.clientFk
},
skip: (params.page - 1) * params.size,
limit: params.size,
order: params.order || 'shipped DESC',
skip: (params.page - 1) * parseInt(params.size),
limit: parseInt(params.size),
order: `${params.order}, id ASC` || 'shipped DESC',
include: {
relation: "greugeType",
scope: {

View File

@ -6,7 +6,7 @@ module.exports = Self => {
where: {},
skip: (params.page - 1) * params.size,
limit: params.size,
order: params.order || 'name, relevancy DESC',
order: params.order || 'name ASC', // name, relevancy DESC
include: {
relation: 'itemType',
scope: {