0

Scroll Listbox (or Grid) with MVVM model to bottom

asked 2023-03-21 05:20:36 +0800

holos gravatar image holos
41 6

I need to scroll a listbox (or a grid) always to the bottom as it is a live log data output which should always show the most recent entry.

It looks like (example):

  <listbox id="list" hflex="1" model="@load(vm.notifications)"
    emptyMessage="${labels.noNotifications}">
    <listhead>
      <listheader label="${labels.notificationTimestamp}" sort="auto(timestamp)" />
      <listheader label="${labels.id}" sort="auto(id)" />
      <listheader label="${labels.notificationEvent}" sort="auto(event)" />
      <listheader label="${labels.notificationPayload}" />
    </listhead>
    <template name="model">
      <listitem>
        <listcell label="@load(each.timestamp)  @converter('date')" />
        <listcell label="@load(each.event)" />
        <listcell label="@load(each.id)" />
        <listcell label="@load(each.payload)" />
      </listitem>
    </template>
  </listbox>

Now I know that I should be able to scroll to the bottom using

Clients.scrollIntoView(listitem);

But in the ViewModel I got stuck

@Wire
Listbox list;
...

@AfterCompose
public void afterCompose(@ContextParam(ContextType.VIEW) Component view) {
    Selectors.wireComponents(view, this, false);
    /* >>>>>  how to get the component "listitem" for the last row here? <<<<<< */
    Clients.scrollIntoView(listitem);
}

Note: You could argue that there is no list item yet as I am still in after compose.

I also tried to retrieve call the listitem on any event when the list was definitely filled. No success:

list.getItems()

is always empty and

list.getItemAtIndex(0)

is always null!

delete flag offensive retag edit

1 Answer

Sort by ยป oldest newest most voted
0

answered 2023-03-22 16:36:59 +0800

MDuchemin gravatar image MDuchemin
2560 1 6
ZK Team

Hey there,

First regarding the use @wire and @afterCompose in viewModel, just note that they break the MVVM pattern. ZK provide these options because sometime there is no other choice than breaking the pattern. If possible, I recommend trying to avoid these.

Regarding why scrolling from VM is not working here: @afterCompose will register a callback during the afterCompose step of the underlying bindcomposer.

https://zkfiddle.org/sample/2cdadkk/9-scroll-to-item-in-mvvm-using-selection

The AfterCompose step occurs before the binder initializes all of the @init, @load and @bind bindings with their values, which means that at this point, there is no model actually attached to the Listbox, and there is no listitems created.

An alternative way to implement scroll would be to use model selection instead. Model selection will scroll model-bound components when set.

However, this also cannot be done until the items are rendered. Luckily, there is a MVVM friendly to obtain a timing at which item rendering is done, and therefore scrolling is queueable by setting model selection.

<listbox id="lb" model="@init(vm.model)" onAfterRender="@command('scroll')" height="500px"/>

The onAfterRender event is returned once the Listbox has initialized and rendered the listitems. By using this event as a command trigger, we can execute a VM command and update the model selection. Updating selection automatically scroll to the item position.

Runnable sample: https://zkfiddle.org/sample/2cdadkk/9-scroll-to-item-in-mvvm-using-selection

link publish delete flag offensive edit

Comments

Thanks! This helps a lot. Interestingly, even if you recommend NOT to use @wire and @afterCompose in viewModel this is exactly what you use in your fiddle.

holos ( 2023-04-03 19:34:40 +0800 )edit

You'll notice that @Wire and @AfterCompose are only used to output a log, in order to demonstrate the timing of the event ;) the actual scrolling happens in the "scroll" command, which is triggered by onAfterRender="@command('scroll')"

MDuchemin ( 2023-04-10 15:50:25 +0800 )edit

I kept it in there from the initial code to show in which order these systems execute, but you can remove both the listbox and the afterCompose method, and it will work the same

MDuchemin ( 2023-04-10 15:51:12 +0800 )edit
Your answer
Please start posting your answer anonymously - your answer will be saved within the current session and published after you log in or create a new account. Please try to give a substantial answer, for discussions, please use comments and please do remember to vote (after you log in)!

[hide preview]

Question tools

Follow
1 follower

RSS

Stats

Asked: 2023-03-21 05:20:36 +0800

Seen: 10 times

Last updated: Mar 22 '23

Support Options
  • Email Support
  • Training
  • Consulting
  • Outsourcing
Learn More