Skip to content
This repository has been archived by the owner on Apr 6, 2022. It is now read-only.

Add lazy loading #131

Merged
merged 89 commits into from
Oct 12, 2018
Merged

Add lazy loading #131

merged 89 commits into from
Oct 12, 2018

Conversation

pekam
Copy link
Contributor

@pekam pekam commented Oct 2, 2018

  • Items are loaded lazily one page at a time as the user scrolls down the overlay
  • Added ItemFilter API for defining custom server-side filtering function
    • This is different from V8 CaptionFilter, to allow filtering based on other properties than just the caption/label. It is useful especially when using more properties in the renderer.
  • When the size of the data set is less than pageSize, and the user has not defined a server-side filter function, the filtering will happen in the client-side, providing smoother user experience and reducing network traffic
  • Server-side filtering is debounced by 500ms to avoid sending requests and triggering server-side filtering all the time as the user types into the field
  • Default pageSize is 50
  • Breaking changes:
    • setFilteredItems and getFilteredItems API removed
      • Use ItemFilter instead to implement custom filtering
    • setNullRepresentation and getNullRepresentation API removed
      • DataProvider doesn't allow null items in the data
      • It makes null value ambiguous: Should setValue(null) clear the value or the select the null item?
    • Calling setValue with an item which is not included in the data set doesn't throw an exception anymore
      • With large data sets, or a callback data provider connected to a database, it's not feasible to figure out whether an item is included

Resolves tickets #72 #17


This change is Reviewable

*
* @return the data provider used by this ComboBox
*/
public DataProvider<T, ?> getDataProvider() {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL Remove usage of generic wildcard type. rule


private void initConnector() {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Move this method into the anonymous class declared at line 170. rule

@@ -107,39 +135,107 @@ public void remove() {
}
}

private class RefreshJob implements SerializableConsumer<UI> {
private final class UpdateQueue implements Update {
private List<Runnable> queue = new ArrayList<>();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRITICAL Make "queue" transient or serializable. rule

@vaadin-bot
Copy link

SonarQube analysis reported 4 issues

  • CRITICAL 2 critical
  • MINOR 2 minor

Watch the comments in this conversation to review them.

import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.dependency.HtmlImport;
import com.vaadin.flow.component.HasStyle;
import com.vaadin.flow.component.HasValue;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MINOR Remove this unused import 'com.vaadin.flow.component.HasValue'. rule

Fixes a bug: Otherwise when using server-side filtering, when you change
the filter from empty to something else and back to empty within the
debounce timeout, the overlay remains empty as the DataCommunicator thinks it
doesn't need to send data.
Copy link
Contributor

@gilberto-torrezan gilberto-torrezan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 3 of 18 files at r1, 17 of 22 files at r2, 3 of 3 files at r3.
Reviewable status: 20 of 23 files reviewed, 16 unresolved discussions (waiting on @gilberto-torrezan, @vaadin-bot, and @pekam)

a discussion (no related file):
There's a potential mismatch between the client-side filtering and the server-side one, if the browser has a different locale than the server (see the example with the i letter in Turkish). It doesn't need to be taken care of right now, but it's something to consider for next versions.



src/main/java/com/vaadin/flow/component/combobox/ComboBox.java, line 209 at r3 (raw file):

    };

    private Boolean forceServerSideFiltering;

I got that you wanted to have 3 states in a single variable, but the null case is hard to understand (and thus, maintain). I suggest using two booleans instead, or an enum with 3 values, with clear names on what each one represents.


src/main/java/com/vaadin/flow/component/combobox/ComboBox.java, line 231 at r3 (raw file):

        setItemValuePath("key");
        setItemIdPath("key");
        setPageSize(pageSize);

In Grid we had to support a public setPageSize method, because when using the component with @Id, only the empty constructor is invoked. You probably need to do that here as well, or mark somehow to be implemented in a future alpha.


src/main/java/com/vaadin/flow/component/combobox/ComboBox.java, line 306 at r3 (raw file):

        if (value != null && getKeyMapper().has(value)) {
            value = getKeyMapper().get(getKeyMapper().key(value));

You can optimize this to only call the getKeyMapper once.


src/main/java/com/vaadin/flow/component/combobox/ComboBox.java, line 312 at r3 (raw file):

        // item is not yet loaded
        JsonObject json = Json.createObject();
        json.put("key", getKeyMapper().key(value));

If the value is null, something crazy would happen here.... or would it?


src/main/java/com/vaadin/flow/component/combobox/ComboBox.java, line 846 at r3 (raw file):

        }
        runBeforeClientResponse(ui -> ui.getPage().executeJavaScript(
                "if($0.$connector) $0.$connector.reset();", getElement()));

Is there a situation where the $connector is undefined for the combo-box instrumented by the server?


src/main/resources/META-INF/resources/frontend/comboBoxConnector.js, line 68 at r3 (raw file):

      }

      const firstPage = index / comboBox.pageSize;

It's not nice to have two variables with the same name in different scopes. Weird things can happen when the code gets refactored. I suggest changing the name of this one to something else.


src/main/resources/META-INF/resources/frontend/comboBoxConnector.js, line 102 at r3 (raw file):

// Should be done by clearCache()

And why is not? Now that you control client and server-side, those things should work together.

if it's not possible to do it now for whatever reason, create a TODO here with the ticket number.


src/test/java/com/vaadin/flow/component/combobox/ComboBoxElementUpdated.java, line 25 at r3 (raw file):

 * @author Vaadin Ltd
 */
public class ComboBoxElementUpdated extends ComboBoxElement {

Why not updating the ComboBoxElement itself?

Copy link
Contributor

@gilberto-torrezan gilberto-torrezan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 3 of 3 files at r4.
Reviewable status: all files reviewed, 16 unresolved discussions (waiting on @gilberto-torrezan, @vaadin-bot, and @pekam)

Copy link
Contributor Author

@pekam pekam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: all files reviewed, 16 unresolved discussions (waiting on @gilberto-torrezan, @vaadin-bot, and @pekam)

a discussion (no related file):

Previously, gilberto-torrezan (Gilberto Torrezan) wrote…

There's a potential mismatch between the client-side filtering and the server-side one, if the browser has a different locale than the server (see the example with the i letter in Turkish). It doesn't need to be taken care of right now, but it's something to consider for next versions.

Yes. The reason why I left it out from the client-side is that the web component itself doesn't care about locales with the default filtering.

Maybe I should not use locale in the server either, to make it match with the client filtering, or what do you think?



src/main/java/com/vaadin/flow/component/combobox/ComboBox.java, line 306 at r3 (raw file):

Previously, gilberto-torrezan (Gilberto Torrezan) wrote…
        if (value != null && getKeyMapper().has(value)) {
            value = getKeyMapper().get(getKeyMapper().key(value));

You can optimize this to only call the getKeyMapper once.

Done.


src/main/java/com/vaadin/flow/component/combobox/ComboBox.java, line 312 at r3 (raw file):

Previously, gilberto-torrezan (Gilberto Torrezan) wrote…

If the value is null, something crazy would happen here.... or would it?

We have at least ClearValueIT testing that you can use setValue(null)


src/main/java/com/vaadin/flow/component/combobox/ComboBox.java, line 846 at r3 (raw file):

Previously, gilberto-torrezan (Gilberto Torrezan) wrote…

Is there a situation where the $connector is undefined for the combo-box instrumented by the server?

When the component is first attached, this is executed before connector's initLazy.
Of course this call is not required at all at that point, but it comes from setDataProvider and setRenderer.


src/main/resources/META-INF/resources/frontend/comboBoxConnector.js, line 68 at r3 (raw file):

Previously, gilberto-torrezan (Gilberto Torrezan) wrote…

It's not nice to have two variables with the same name in different scopes. Weird things can happen when the code gets refactored. I suggest changing the name of this one to something else.

Nice catch, I didn't notice at all.
Done.


src/main/resources/META-INF/resources/frontend/comboBoxConnector.js, line 102 at r3 (raw file):

Previously, gilberto-torrezan (Gilberto Torrezan) wrote…

// Should be done by clearCache()

And why is not? Now that you control client and server-side, those things should work together.

if it's not possible to do it now for whatever reason, create a TODO here with the ticket number.

This is a bug which I found in the web component, and it was already fixed but not released yet.
I asked Vladimir and he promised to release a new alpha soon.

Copy link
Contributor

@gilberto-torrezan gilberto-torrezan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 2 of 2 files at r5.
Reviewable status: all files reviewed, 11 unresolved discussions (waiting on @gilberto-torrezan, @vaadin-bot, and @pekam)

a discussion (no related file):

Previously, pekam (Pekka Maanpää) wrote…

Yes. The reason why I left it out from the client-side is that the web component itself doesn't care about locales with the default filtering.

Maybe I should not use locale in the server either, to make it match with the client filtering, or what do you think?

The locale support is yet a different beast on all of this. IMO there should be a way to get the locale used by the browser and send it to the server, and then the server would use that as the default, but let's no design this here. I suggest creating a ticket for it.



src/main/java/com/vaadin/flow/component/combobox/ComboBox.java, line 846 at r3 (raw file):

Previously, pekam (Pekka Maanpää) wrote…

When the component is first attached, this is executed before connector's initLazy.
Of course this call is not required at all at that point, but it comes from setDataProvider and setRenderer.

I suggest adding that as a comment in the code, for maintenability purposes.

Copy link
Contributor Author

@pekam pekam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 19 of 23 files reviewed, 11 unresolved discussions (waiting on @gilberto-torrezan, @vaadin-bot, and @pekam)


src/main/java/com/vaadin/flow/component/combobox/ComboBox.java, line 231 at r3 (raw file):

Previously, gilberto-torrezan (Gilberto Torrezan) wrote…

In Grid we had to support a public setPageSize method, because when using the component with @Id, only the empty constructor is invoked. You probably need to do that here as well, or mark somehow to be implemented in a future alpha.

Done.

Copy link
Contributor Author

@pekam pekam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: 19 of 23 files reviewed, 10 unresolved discussions (waiting on @gilberto-torrezan, @vaadin-bot, and @pekam)

a discussion (no related file):

Previously, gilberto-torrezan (Gilberto Torrezan) wrote…

The locale support is yet a different beast on all of this. IMO there should be a way to get the locale used by the browser and send it to the server, and then the server would use that as the default, but let's no design this here. I suggest creating a ticket for it.

https://github.com/vaadin/vaadin-combo-box-flow/issues/138



src/main/java/com/vaadin/flow/component/combobox/ComboBox.java, line 209 at r3 (raw file):

Previously, gilberto-torrezan (Gilberto Torrezan) wrote…

I got that you wanted to have 3 states in a single variable, but the null case is hard to understand (and thus, maintain). I suggest using two booleans instead, or an enum with 3 values, with clear names on what each one represents.

Done.
I couldn't come up with any nicer-sounding enum, and I think using two booleans would be too messy.
If you have better naming suggestions, feel free to share them.


src/main/java/com/vaadin/flow/component/combobox/ComboBox.java, line 846 at r3 (raw file):

Previously, gilberto-torrezan (Gilberto Torrezan) wrote…

I suggest adding that as a comment in the code, for maintenability purposes.

Done.

Copy link
Contributor

@gilberto-torrezan gilberto-torrezan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

Reviewed 4 of 4 files at r6.
Reviewable status: all files reviewed, 5 unresolved discussions (waiting on @vaadin-bot and @pekam)

Copy link
Contributor Author

@pekam pekam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: all files reviewed, 5 unresolved discussions (waiting on @vaadin-bot and @pekam)


src/test/java/com/vaadin/flow/component/combobox/ComboBoxElementUpdated.java, line 25 at r3 (raw file):

Previously, gilberto-torrezan (Gilberto Torrezan) wrote…

Why not updating the ComboBoxElement itself?

Because it is still in a different repository and I don't want to wait for a new release of it.

I will create a ticket for TB once this is in, so I can link to this file.

Copy link
Contributor

@gilberto-torrezan gilberto-torrezan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewable status: all files reviewed, 4 unresolved discussions (waiting on @vaadin-bot)

Copy link
Contributor Author

@pekam pekam left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dismissed @vaadin-bot from 4 discussions.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved

@pekam pekam merged commit c17fcfe into master Oct 12, 2018
@pekam pekam deleted the lazy-loading branch October 12, 2018 13:47
@pekam pekam added this to the 2.0.0.alpha1 milestone Oct 15, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants