Skip to content

Instantly share code, notes, and snippets.

@Mohamed-Ali-SMA
Last active February 14, 2022 07:51
Show Gist options
  • Save Mohamed-Ali-SMA/b72ef2b6d21881581cc9e443b516e2b9 to your computer and use it in GitHub Desktop.
Save Mohamed-Ali-SMA/b72ef2b6d21881581cc9e443b516e2b9 to your computer and use it in GitHub Desktop.
Virtual DOM - Handled wih Page Size
import Component from '@ember/component';
import layout from '../templates/components/virtual-element';
import { set } from '@ember/object'; // No I18N
export default Component.extend({
layout,
tagName: 'li',
attributeBindings: ['style'],
style: '',
definedStyle: "border: solid 0.1px lightgrey;",
didReceiveAttrs(){
this._super(...arguments);
set(this, 'style', this.definedStyle+('height:')+this.virtualElementHeight+'px;');
}
});
import Controller from '@ember/controller';
import $ from 'jquery';
import { A } from '@ember/array';
import object, { action, set } from '@ember/object';
export default Controller.extend({
totalCount: 1000,
listItems: A(),
showList: false,
scrollBinded: false,
scrolledPos: '',
virtualElementHeight: 0,
virtualElementBottomHeight: 0,
parentElement: null,
getScreenHeight() {
let height = 0;
if (document.documentElement && document.documentElement.clientHeight) { // Explorer 6 Strict Mode
height = document.documentElement.clientHeight;
} else if (document.body) { // other Explorers
height = document.body.clientHeight;
}
return height;
},
bindScroll(selector, namespace, scroll_function) {
let onScroll;
set(this, 'scrollBinded', true);
onScroll = function(event) {
return scroll_function(event);
};
let eventName = namespace ? 'scroll.' + namespace : 'scroll';
setTimeout(function(){
$(selector).on(eventName, onScroll)
},200);
},
unbindScroll(selector, namespace) {
set(this, 'scrollBinded', false);
let eventName = namespace ? 'scroll.' + namespace : 'scroll';
$(selector).off(eventName);
},
toggleItems: action(function(hiddenListIndices, status, toggleItemLimit, toggleElementAtScrollPos){
let self = this,
startIndex = hiddenListIndices,
endIndex = hiddenListIndices,
listItems = self.listItems,
parentScrollHeight = self.parentElement[0].scrollHeight,
perEleHeight = (parentScrollHeight / listItems.length);
if (!status) {
startIndex = hiddenListIndices-toggleItemLimit;
} else {
endIndex += toggleItemLimit;
}
if (startIndex >= 0) {
for(let i=startIndex; i<endIndex; i++){
set(listItems[i], 'canShowItem', status);
}
setTimeout(function(){
if (!status) {
let visibleItemsCount = listItems.filterBy('canShowItem', true).length,
lastVisibleItemIndex = endIndex + visibleItemsCount;
for(let j=lastVisibleItemIndex; j<lastVisibleItemIndex + toggleItemLimit; j++){
if (listItems[j]){
set(listItems[j], 'canShowItem', 'aaa');
} else {
break;
}
}
}
},300);
}
if(hiddenListIndices >= 0){
if (!status){console.log('============. '+endIndex);
set(self, 'virtualElementHeight', (endIndex*perEleHeight));
} else {
let defaultHeight = Number(self.virtualElementHeight);
set(self, 'virtualElementHeight', (defaultHeight - ((endIndex - startIndex)*perEleHeight)));
}
if (!status){
let defaultHeight = Number(self.virtualElementBottomHeight);
set(self, 'virtualElementBottomHeight', (defaultHeight - (toggleItemLimit*perEleHeight)));
}
}
}),
actions:{
toggleList(enablePaginate){
let self = this,
listItems = self.listItems;
if(!this.scrollBinded){
self.bindScroll('.list-wrapper', null, function(scollListElement){
scollListElement = $(scollListElement.target)[0];
set(self, 'scrolledPos', scollListElement.scrollTop);
});
}
if (this.showList){
self.unbindScroll('.list-wrapper', null);
set(this, 'scrollBinded', false);
} else {
let self = this,
listItems = A(),
perEleHeight = 0,
visibleItemsCount = 0,
parentScrollHeight = 0;
for (let i=0; i<self.totalCount; i++){
listItems.pushObject(object.create({'name': i+1, 'canShowItem': true}));
}
setTimeout(function(){
set(self, 'parentElement', $('.list-wrapper'));
parentScrollHeight = self.parentElement[0].scrollHeight;
perEleHeight = (parentScrollHeight / listItems.length);
set(self, 'perEleHeight', perEleHeight);
self.listItems.setEach('canShowItem', false);
for (let i=0; i<100; i++){
set(self.listItems[i], 'canShowItem', true);
}
visibleItemsCount = listItems.filterBy('canShowItem', true).length;
set(self, 'virtualElementBottomHeight', ((listItems.length - visibleItemsCount)*perEleHeight));
},200);
set(self, 'listItems', listItems);
}
set(this, 'showList', !this.showList);
}
}
});
import Modifier from 'ember-modifier';
import { action, set } from '@ember/object';
export default class virtualDomElement extends Modifier {
virtualElementCount = 0;
prevScrolledPos = 0;
prevScrolledCount = 1;
didReceiveArguments(){
let self = this,
toggleItemLimit = 30,
additionalLimit = 0,
ParentEleScrollHeight = 0,
ParentEleOffsetHeight = 0,
toggleElementAtScrollPos = 0,
[scrolledPos, parentElement, getScreenHeight, perEleHeight] = self.args.positional,
virtualElementCount = self.virtualElementCount;
if (parentElement && parentElement.length){
ParentEleScrollHeight = parentElement[0].scrollHeight;
ParentEleOffsetHeight = parentElement[0].offsetHeight;
}
toggleElementAtScrollPos = (perEleHeight*toggleItemLimit);
if (scrolledPos < 10){
set(self, 'prevScrolledPos', 0);
set(self, 'prevScrolledCount', 1);
set(self, 'virtualElementCount', 0);
}
if(scrolledPos){
if(scrolledPos <= self.prevScrolledPos){
if ((toggleElementAtScrollPos*(self.prevScrolledCount-1)) >= scrolledPos - additionalLimit){
console.log(virtualElementCount, 'Prev');
virtualElementCount = virtualElementCount - toggleItemLimit;
this.args.named.callback(virtualElementCount, true, toggleItemLimit, toggleElementAtScrollPos);
set(self, 'prevScrolledPos', (toggleElementAtScrollPos*self.prevScrolledCount)+additionalLimit);
set(self, 'prevScrolledCount', self.prevScrolledCount-1);
}
} else {
if ((toggleElementAtScrollPos*self.prevScrolledCount) <= scrolledPos - additionalLimit){
virtualElementCount = virtualElementCount + toggleItemLimit
this.args.named.callback(virtualElementCount, false, toggleItemLimit, toggleElementAtScrollPos);
set(self, 'prevScrolledPos', (toggleElementAtScrollPos*self.prevScrolledCount)+additionalLimit);
set(self, 'prevScrolledCount', self.prevScrolledCount+1);
console.log(virtualElementCount, 'Reached');
}
}
set(self, 'virtualElementCount', virtualElementCount);
}
};
_willDestroy(){
let self = this;
set(self, 'prevScrolledPos', 0);
set(self, 'prevScrolledCount', 1);
set(self, 'virtualElementCount', 0);
self.args.named.callback(0, true, 30, 1200);
}
};
<h2><u>Virtual DOM {{virtualElementHeight}}</u></h2>
{{outlet}}
<br>
{{add virtualElementBottomHeight virtualElementHeight}}
:: Total items : {{input value=totalCount}} &nbsp;
<button {{action 'toggleList' true}}>
{{#if showList}}
Hide
{{else}}
Show
{{/if}} list
</button>
{{virtualElementBottomHeight}}
<br><br>
{{#if showList}}
<div class='list-wrapper' style='max-height:430px;overflow-y:auto;border:ridge 1px;background:aliceblue;'>
<ul style="list-style-type: none;margin:0;" {{virtual-dom-element scrolledPos parentElement getScreenHeight perEleHeight callback=toggleItems}}>
{{virtual-element class='def-list-item' virtualElementHeight=virtualElementHeight}}
{{#each listItems as |item index|}}
{{#if item.canShowItem}}
<li class='list-item {{item.name}}' style="border: solid 0.1px lightgrey;padding: 10px;">
<center>
<b> {{item.name}} :: {{index}} </b>
</center>
</li>
{{/if}}
{{/each}}
{{virtual-element class='def-list-item' virtualElementHeight=virtualElementBottomHeight}}
</ul>
</div>
{{/if}}
{
"version": "0.17.1",
"EmberENV": {
"FEATURES": {},
"_TEMPLATE_ONLY_GLIMMER_COMPONENTS": false,
"_APPLICATION_TEMPLATE_WRAPPER": true,
"_JQUERY_INTEGRATION": true
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.js",
"ember": "3.18.1",
"ember-template-compiler": "3.18.1",
"ember-testing": "3.18.1"
},
"addons": {
"@glimmer/component": "1.0.0",
"ember-modifier": "1.0.5",
"ember-math-helpers": "2.18.1"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment