0

UPDATE: The below code does not work the way I wanted to, like as I mention below, it should show five items at a time when the user clicks on the button.

I'm trying to use javascript slice method (please suggest if this is not the right way to use), the array list show five array item at a time and I have created the codepen example to show what I'm trying to do

Let's assume I have 20 records, if the user click on first time, I should be getting 1-5 array items if the user click on second time, I should be getting 5-10 .....so on and so forth.

https://codepen.io/TLJens/pen/NPZyYR

The code here:

$('#loading').hide();

var counts = 0;
var displayCount = 5;
var starting = 0;
var data = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];

function slicemydata(sstart, totalsize, eend) {  
    var items = []; debugger;
    if (totalsize <= data.length) {
        if (eend == 0) {
          items = data.slice(sstart,totalsize);
        } else { 
          if (sstart > eend) {
            eend = data.length;
          }
          items = data.slice(sstart, eend);
          sstart =  displayCount + 5;
        }
    }
    console.log(items);
  $('.js-lazy-load-data').append(items);
}

$('.js-lazy-load').click(function () {
 
  counts++;
  slicemydata(starting,data.length,displayCount);
 
    $('.js-lazy-load').fadeOut();
  
    // Minor timeout before showing loader
   // setTimeout(function () {
   //     $('#loading').fadeIn();
   // }, 400); 
  
    // Simulate server call by showing loading gif  
    // for 2.5 seconds before displaying results
    //setTimeout(function () {
    //    $('#loading').fadeOut();
    //}, 2600); 
  
    // Display results after 3 seconds
    setTimeout(function () {
        //$('.js-lazy-load-data').append(data);
        $('.js-lazy-load').show();
    }, 1000);  
});
6
  • I'm trying to figure out what exactly you're asking here. Is something not working as you'd expect? Are you getting an error? What do you need help with? Commented Apr 20, 2022 at 16:58
  • updated little bit more hope this is clear Commented Apr 20, 2022 at 17:03
  • You say you want to "Show 5 items at a time", but the example appends 5 items to the existing list. Are you wanting to only show 5 at a time like pagination, or are you wanting to append 5 more items to the existing list every time the "more" button is pressed? Commented Apr 20, 2022 at 17:04
  • it should not append rather it should show the new 5 items and I forgot to comment that line, so it's like pagination or you can say lazy loading Commented Apr 20, 2022 at 17:08
  • Ah, okay. Understood. I'll write up a solution based on what you have Commented Apr 20, 2022 at 17:14

3 Answers 3

2

This might be a use case for Generators and generator functions; the OP's task at least makes a good practical exercise ...

function* createChunkGenerator(
  itemList, chunkSize = 1, chunkCount = 0
) {
  // sanitize and decouple (shallow copy) the passed
  // array reference, thus one can `splice` the list
  // without mutating the original array.
  itemList = Array.from(itemList ?? []);
  chunkSize = Math.max(chunkSize, 1);

  while (itemList.length >= 1) {
    ++chunkCount;

    yield {
      chunkCount,
      itemList: itemList.splice(0, chunkSize),
    };
  }
}


let chunkGenerator = createChunkGenerator(
  [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], 5
);
let chunks;

console.log('...automatically tiggered `next` based iteration...');

while (chunks = chunkGenerator.next().value) {
  const { chunkCount, itemList } = chunks;

  console.log({ chunkCount, itemList });
}


chunkGenerator = createChunkGenerator(
  [1, 2, 3, 4, 5, 6, 7, 8], 6
);
console.log('...explicitly (e.g. event) triggered `next` based iteration...');
console.log(
  chunkGenerator.next()
);
console.log(
  chunkGenerator.next()
);
console.log(
  chunkGenerator.next()
);
console.log(
  chunkGenerator.next()
);
.as-console-wrapper { min-height: 100%!important; top: 0; }

The below DOM / DOM event implementation demonstrates the handy usage of a generator based paginator/pagination.

function* createChunkGenerator(
  itemList, chunkSize = 1, chunkCount = 0
) {
  // sanitize and decouple (shallow copy) the passed
  // array reference, thus one can `splice` the list
  // without mutating the original array.
  itemList = Array.from(itemList ?? []);
  chunkSize = Math.max(chunkSize, 1);

  while (itemList.length >= 1) {
    ++chunkCount;

    yield {
      chunkCount,
      itemList: itemList.splice(0, chunkSize),
    };
  }
}

function handleCreateLoadItemsFromBoundData({ currentTarget }) {
  const { generator: chunkGenerator, elmOutput } = this;
  const chunks = chunkGenerator.next().value ?? null;
  
  if (chunks !== null) {
    const { chunkCount: loadCount, itemList: loadItems } = chunks;

    elmOutput.value =
      `... loadCount: ${ loadCount }, loadItems: ${ loadItems } ...`;
  } else {
    elmOutput.value =
      '... no more load items ...';

    currentTarget.disabled = true;
  }
}
document
  .querySelector('button')
  .addEventListener(
    'click',
    handleCreateLoadItemsFromBoundData.bind({
      generator: createChunkGenerator(
        [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13], 5
      ),
      elmOutput: document.querySelector('output'),
    })
  );
<button>load items</button>
=>
<output>...</output>

Sign up to request clarification or add additional context in comments.

5 Comments

Hi Peter, I'm trying to implement lazy loading not pagination
@ThreeOneThree ... Good, and it doesn't even change the above approach/implementation since the task stays the same ... slicing/splicing the specified nth items from an array at time. A configurable generator is not the worst solution to it. Thus the only thing left for me was to change/adapt the wording.
yes, I understand, so I change the array to array object and the code does not work, I see that createPaginator expecting an array [] so I changed to {}, anything else I need to modify?
I don't know what ... "so I change the array to array object" ... actually means. Since the OP's main tasks is ... slicing array list five elements at a time ... the generator function createChunkGenerator expects two parameters being passed, 1st the array (it doesn't matter what the array contains) one wants to slice / splice / get chunks from, 2nd the (optional) chunk size value which preferably should be grater than or equal to 1.
Thanks for patience with me and I'm not going to ask another question instead I will create a new one, so you don't get annoy with me :)
1

Here's how I would approach it.

  1. Pass in the data and the element that needs to be updated to a function.

  2. That function initialises the index, and returns a new function that acts as the handler for the listener.

  3. Within the body of that function you do the work of writing the new HTML using the sliced data, and then updating the element.

const data = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16];

// Cache the elements
const div = document.querySelector('div');
const button = document.querySelector('button');

// Call `slicer` with the data, and the element to be updated.
// `slicer`returns a new function that is assigned to the listener
button.addEventListener('click', slicer(data, div), false);

// `slicer` accepts some data, and the 
// element to be updated
function slicer(data, div) {

  // Initialises the `index` which is
  // scoped to the returning function. No
  // need for global variables!
  let index = 0;

  // Returns a function that keeps a record
  // of index so it can update it
  return function () {

    if (index < data.length) {
      
      // `slice` the data from the current
      // index, `map` over that array to create
      // some HTML, and then join it up
      const html = data
        .slice(index, index + 5)
        .map(el => `<span>${el}</span>`)
        .join(', ');

      // Add that to the element that needs updating
      div.innerHTML = `<div>${html}</div>`;
      
      // Finally increase the index
      index += 5;
    
    } else {
    
      console.log('No more data');
    
    }
      
  }

}
<button>Click me!</button>
<div></div>

Additional documentation

2 Comments

I think based on the comments, the OP just wants to paginate the data not append the data to an existing list
Cheers @mhodges. Easy enough to fix.
0

So I think if all you're wanting to do is paginate the data, you can do it much simpler by just keeping track of the current "pageIndex" you're on and how long each "page" is. That way, your start position in the array is just pageIndex * pageSize and your end position in the array is just start + pageSize. Then all you have to do to get the next or previous page is just increment/decrement your page index accordingly. I'll leave the exercise of displaying the data to you since that's not relevant to what you needed help with. Hope this helps!

let data = [1,2,3,4,5,6,7,8,9,10,11,12,13];
let currentPage = 0;
let pageSize = 5;
function getPage(data, pageSize, pageIndex) {
  let start = pageSize * pageIndex;
  return data.slice(start, start + pageSize) 
}

console.log(getPage(data, pageSize, currentPage));
currentPage++;
console.log(getPage(data, pageSize, currentPage));
currentPage++;
console.log(getPage(data, pageSize, currentPage));
currentPage++;
console.log(getPage(data, pageSize, currentPage));
currentPage++;

1 Comment

thank you so much, let me play with it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.