How to implement a custom renderer in Vaadin 8.1?

Hi,

I migrated my Vaadin 7 Code to Vaadin 8.1.Before I used a list with a custom renderer to show images and strings in one column. For my custom renderer I extended AbstractRenderer without any client implementation and it worked well.
Now I migrated the table to a Vaadin 8.1 grid and the renderer extends the new AbstractRenderer. But it does not work. When I start the application I get a lot of errors on the client side: no column for index…
I think it is because I have no client side connector for my renderer. Is there another way to implement the renderer without client connector? In Vaadin 7 it was no problem.

Thanks, Philipp

The idea behind the Table → Grid replacement was that Table was rendered as a component-rich container, making the rendering of Tables with many elements problematic. Therefore, the idea behind Grid was that cells are provided with client-side renderers instead, making the whole thing much more lightweight.

However, if you want quick compatibility with Vaadin 7 and don’t want to program client renderers, there is a new renderer in Vaadin 8.1 specifically that does what you want - it’s called ComponentRenderer.

Thanks, after reorganisation of my code I was able to use the
ComponentRenderer
. But now I have a new problem. Not in every row in my compnent renderered column there is a component. It should be empty.So the value provider in such cases returns
null
. But that produces a
NullPointerException
in the
ComponentRenderer
:

@Override public JsonValue encode(Component value) { // value is null -> NullPointerException return Json.create(value.getConnectorId()); } Is it a bug in the vaadin framework? Did I something wrong? What can I do? I could generate an empty
label
instead of
null
, I could extend the
ComponentRenderer
. But I think this two possibilities could only work as a workaround, or?

Thanks, Philipp

As a Workaround I extended the
ComponentRenderer
:

private static final class NullableComponentRenderer
extends ComponentRenderer
{
    @Override
    public JsonValue encode(
           final Component pValue )
    {
        if ( pValue == null ) {
            return null;
        }

        return super.encode( pValue );
    }
}

Hi Philipp,

Good catch with the null components, I made a quick fix to the Framework to allow this feature a bit better. The approach you have actualy causes some exceptions in the client-side and might lead to unstable rendering result. See
https://github.com/vaadin/framework/pull/9692
for a more complete solution.

Did you still have some issues with custom renderers? I’m interested in the renderer you mentioned in the opening post. Is it available somewhere for me to take a look at it?

Hi,

thanks for the hint according client side exceptions. I haven’t yet started my app in debug mode so I had no knowledge about it.
With my new solution I tried to avoid a custom renderer because I do not want to write the client side. Because not of the coding, it is only the handling with client side code, widgetset compiling and so on. Our project structure is a little bit complicated. We have our own framework to capsulate all vaadin stuff and so on. And there are some main projects, that depends on all other projects. If I have a custom rendererer, I have to place it in its own addon project, build a jar ou of it and all main projects have to reference the lib, otherwise WidgetsetCompilation and that stuff does not work. Or are there some changes in handling addon projects if you have a multi project workspace? For me, it would be great if you don’t have to build the addon libs, instead of you could refer to the eclipse (addon) projects with client side code directly. But that is offtopic.
Back to the custom renderer. I try to make a draft of it (code is written on the fly, must not be completely correct), because it is not so easy to extract it out of the existing code. The Idea was, and how it was realized in Vaadin 7, there is a HandlerInterface with a methode, that returns a string or icon and has the row data as parameter:

public interface StringIconHandler<Data> { Object getStringOrIcon( Data data ); } My renderer is added to a generated column, that belongs to a table of type Data, that knows a concrete handler and gets the row data in the
encode()
-method:

public class MyRenderer<Data>
extends AbstractRenderer
{
    private final StringIconHandler<Data> vHandler;

    public MyRenderer(
            final StringIconHandler<Data> pHandler )
    {
        vHandler = pHandler;
    }

    public JSONValue encode(
            final Data pData )
    {
        final Object iconString = vHandler.getStringOrIcon( pData );
        if ( String.class.isAssignableFrom( iconString ) )
        {
            return super.encode( (String)iconString, String.class );
        }
        if ( Icon.class.isAssignableFrom( iconString ) )
        {
            final Image image = fetchRessourceAndCreateImage( (Icon)iconString );
            return super.encode( image, Image.class );
        }
        return null;
    }
    ...
}

The new implementation looks a bit different. Now the value provider for the generated column returns the component instead of the row data, as it was before, so I can use the standard
ComponentRenderer
(except null).

Thanks, Philipp (I will be on holiday for the next 2 1/2 weeks)