angular-ui / ui-scroll

Unlimited bidirectional scrolling over a limited element buffer for AngularJS applications
http://angular-ui.github.io/ui-scroll/demo/
MIT License
326 stars 107 forks source link

Many ng-scroll on the page with different datasources #251

Closed villian closed 5 months ago

villian commented 3 years ago

Hello,

Thanks for a great package.

I'm struggling with making many ng-scoll items on the page, they are actually in ng-repeat and have different datasources

Datasources are the problem, how to make dynamic datasets and wrap in datasources? How can I pass params from angular view from rendering to the datasource to provide data?

villian commented 3 years ago

so I need something like this - https://plnkr.co/edit/JjAiw3zvG4uIWGNjLUU7?preview

but with dynamic datasource for each ng-scroll

dhilt commented 3 years ago

@villian If you need 2 different Datasources for two different views, you may just define 2 ds objects:

<tr ui-scroll="item in datasource" adapter="adapter">
...
<tr ui-scroll="item in datasource2" adapter="adapter2">
$scope.datasource = { get: /* implementation of ds1 */ };
$scope.datasource2 = { get: /* implementation of ds2 */  };

But if you need to have multiple datasources under a single umbrella, the following approach might be useful. Basically, if you can guarantee indexes consistency across the datasources, you may provide the replacement of the datasource.get method body in runtime:

let myDynamicDatasource = (i, c, s) => s([]); // stub ds.get

$scope.datasource = {
  get: (index, count, success) =>
    myDynamicDatasource(index, count, success)
};

// data is new array of items we want to loop through with ui-scroll
$scope.onDatasourceChanged = (data) =>
  myDynamicDatasource = (index, count, success) =>
    success(data.slice(index, index + count));

But if each ds has its own indexes flow not correlating with others, then I would advise to clean up the internal state via Adapter.reload API:

$scope.onDatasourceChanged = (data, indexToReload) => {
  myDynamicDatasource = (index, count, success) =>
    success(data.slice(index, index + count));
  $scope.adapter.reload(indexToReload);
}
villian commented 3 years ago

Thanks, for the response! This is what we have:

<li ng-repeat="product in products">
<ul ng-if="items[product.id]">
<li ui-scroll="item in datasource">
</li>
</ul>

I have to pass productId into datasource somehow and datasource should be unique for

do we need an array with all items and then manage it via indexes? any idea?

dhilt commented 3 years ago

@villian Well I think I got the issue. Basically, datasource is an object with "get" field which should exist on $scope during render, and if you know the products array length, you may arrange appropriate number of datasources pushed in a single map-object with keys corresponded to the list of product ids:

<li ng-repeat="product in products">
  <ul ng-if="items[product.id]">
    <li ui-scroll="item in datasources[product.id]">
    </li>
  </ul>
</li>

Below is the draft implementation of the datasource-product map.

const getDataByProduct = (product, index, count, callback) => {
  // the logic of this method might be dynamic/async
  // anyway here you have all the data to provide appropriate potion of data
  const data = $scope.items[product.id] || [];
  callback(data.slice(index, index + count));
};

const createDatasource = (product) => ({
  get: (index, count, success) =>
    getDataByProduct(product, index, count, success)
});

$scope.datasources = $scope.products.reduce((acc, product) => ({
  ...acc,
  [product.id]: createDatasource(product)
}), {});