rjaros / kvision

Object oriented web framework for Kotlin/JS
https://kvision.io
MIT License
1.23k stars 65 forks source link

Tabulator vertical scrolling issue #503

Closed chavu closed 8 months ago

chavu commented 10 months ago

When scrolling vertically on Tabulator with many rows, it keeps jumping to the top. I can't reach the bottom rows. This is happening with or without using pagination.

rjaros commented 10 months ago

Could you provide some example? I'm using tabulator in many projects and haven't encountered such issue. I can simply add some rows to the showcase example https://rjaros.github.io/kvision-examples/showcase/#/tabulator (with pagination) or the addressbook example https://rjaros.github.io/kvision-examples/addressbook-tabulator/ (without pagination) and the scrolling works fine for me in both cases (tested on Firefox and Chrome).

chavu commented 10 months ago

I have managed to resolve the issue by setting the renderVertical parameter of the TabularOptions() as below.

tabulator(
      state.testCaseSectionCollection,
      options = TabulatorOptions(
              renderVertical = RenderType.BASIC,
              height = "700",
              layout = Layout.FITCOLUMNS,
              ...

      )
)

I should mention that my table has cascaded tables using rowFormater. I also had set the height of the out table and the minHeight of the inner tables. The only issue remaining now is that when I modify a record at the bottom (i.e changing redux state), the table scrolls to the top, which is not what I want.

rjaros commented 10 months ago

What do you use to update the tabulator data? You should use repaceData() method. This is used by KVision Tabulator component when subscribing to ObservableList and it works correctly: https://github.com/rjaros/kvision/blob/master/kvision-modules/kvision-tabulator/src/jsMain/kotlin/io/kvision/tabulator/Tabulator.kt#L141-L145

chavu commented 10 months ago

I bind an outer div to the Redux store then assign the state variable containing the records collection to the tabulator as shown the skeletal code below

@OptIn(ExperimentalSerializationApi::class)
fun Container.testingView() {
    val appScope = CoroutineScope(window.asCoroutineDispatcher())
    div().bind(UatManager.uatStore) { state ->
//        ... 
        tabulator(
            data = state.testCaseSectionCollection,
            options = TabulatorOptions(
                renderVertical = RenderType.BASIC,
                layout = Layout.FITCOLUMNS,
                columns = listOf(
                    ColumnDefinition("Name", TestCaseSection::name.name, headerSort = false,),
//                    ...
                ),
            )
        )
//        ...
    }
}
rjaros commented 10 months ago

Unfortunately this way you are destroying and recreating the Tabulator component on every state change. That's why you loose tabulator scroll position (and probably other state as well). In my projects I generally move tabulator component outside of general state binding (the .bind method) and just use it's own state binding functionality. It would be something like this:

div().bind(store) { state ->
 // ... other components before tabulator
}

tabulator(store, { state -> state.collection }, options = ...)

div().bind(store) { state ->
// .. other components after tabulator
} 
chavu commented 10 months ago

I'm trying to implement your suggestion above. I want to access a state variable inside a formatterComponentFunction of a column but I'm getting error "Unresolved reference: state".

rjaros commented 10 months ago

Perhaps it will be enough to use store.getState() ? But for more dynamic state you can probably bind() to the store variable inside formatterComponentFunction.