ButtonLink: a link that looks like a button.

I can’t find the thread anymore, but a few weeks ago, I asked how to make a link that looks like a button.

Today, I made a small component that works. It’s probably possible thanks to the Vaadin 6.1 button changes (div instead of input).

/** Label that looks like a button, and has a link to an URL 
 * Tested with Reindeer only.
 * 
 * @author John Rizzo
 */
@SuppressWarnings("serial")
public class ButtonLink extends Label {
	
	/** Constructor
	 * 
	 * @param caption  text on the button
	 * @param externalResource  where link goes
	 * @param width	added to the constructor to make you remember that you don't specify a width the button does not appear (it's 0px wide)
	 */
	public ButtonLink(String caption, ExternalResource externalResource, String width) {
		super(
			"<a href='"+externalResource.getURL()+"'>" +
			  // The following lines are copy pasted from rendered Vaadin v6.1 buttons.
				"<div class='v-button' tabindex='0'>" +
					"<span class='v-button-wrap'>" +
						"<span class='v-button-caption'>"+
							caption +
						"</span>"+
					"</span>"+
				"</div>"+
			"</a>",
        Label.CONTENT_XHTML);
		setWidth(width);
	}
}

Wow! This was interesting way of doing it. Even though the pattern of generating HTML on server side is somewhat agains’t “puristic Vaadin style”, this pattern of extending Label could be applied to solve a wide variety of “decorative” problems is KISS manner.

I found this post from John and it was exactly what I was looking for! That is, making a button go to an external HREF (in my case, a mailto: URL).

What I found was a little broken though was the ‘width’ parameter/attribute. Even when I passed in an empty string for the width parameter, the button still rendered and only was as wide as it needed to display the text on the button.

What I found was that the setWidth(width); call at the bottom of super() call did not have any effect.

What I did to fix this issue is alter the css. I changed line 19 in the code snippet below

<div class='v-button' tabindex='0'>

to this…

<div class='v-button' tabindex='0' style='width: "+width+";'>

Not sure if this is the recommended way of doing this but it seemed to resolve the issue and the the width passed into the constructor is now making the button honor the width specified.

What I’m struggling with now is the placement of the button, it seems to always be LEFT justified even though I use the following method on the layout I’m using to RIGHT justify it:


VerticalLayout buttons = new VerticalLayout();
ButtonLink support = new ButtonLink("Support", new ExternalResource("mailto:support@abc.com"), "100px");
buttons.addComponent(support);
buttons.setComponentAlignment(support, Alignment.BOTTOM_RIGHT);

Please see the attached screenshot for my debugging through Firefox/Firebug.

Please let me know if you have any suggestions and what I might be doing wrong!

Thanks!
11207.png

Ok, I was able to fix the issue I was struggling with here by tweaking the CSS a bit more.

I added an inline style (I know this might be frowned upon) to the tag, more specifically an ‘float’ style.

Here’s the line:

<a href='"+externalResource.getURL()+"' style='text-decoration: none; float: "+align+";'>

And here’s the entire class with my updates. You’ll notice I added an additional String parameter to the constructor in order to indicate alignment.


public class ButtonLink extends Label {

    /**
     * Constructor
     *
     * @param caption  text on the button
     * @param externalResource  where link goes
     * @param width    added to the constructor to make you remember that you don't specify a width the button does not appear (it's 0px wide)
     */
    public ButtonLink(String caption, ExternalResource externalResource, String width, String align) {
        super(
            "<a href='"+externalResource.getURL()+"' style='text-decoration: none; float: "+align+";'>" +
              // The following lines are copy pasted from rendered Vaadin v6.1 buttons.
                "<div class='v-button' tabindex='0' style='width: "+width+";'>" +
                    "<span class='v-button-wrap'>" +
                        "<span class='v-button-caption'>"+
                            caption +
                        "</span>"+
                    "</span>"+
                "</div>"+
            "</a>",
        Label.CONTENT_XHTML);
    }
}

Hi,

You stumbled on a very common gotcha with the width variable and alignment issue: Vaadin Labels are by default 100% wide, so they always occupy the whole space reserved by the containing layout. That will in effect prevent any horizontal alignment for the Label, since it is always as wide as the slot it occupies.

And since you’re “button” is just some HTML inside the Label, that button won’t align properly either. It just sits nicely inside the Label’s DIV element, always on the left.

There’s basically no problem in your solution, “it-just-works”, I might say. But here’s how I’d do it:

Leave the ‘width’ and ‘align’ parameters out of the constructor, they’re not needed. In the constructor of the ButtonLink, set the width of the Label to undefined, in effect allowing the parent layout to align it properly, just use layout.setComponentAlignment(buttonLink, “right”).

Then for the actual width, just set the A element to display:block, in effect making it 100% wide of the parent element (which is the Label’s DIV element). Then set the width of the v-button element to 100%, and it should work.
After that, calling ButtonLink.setWidth should have get you the result you want.

public class ButtonLink extends Label {
    public ButtonLink(String caption, ExternalResource externalResource) {
        super(
            "<a href='"+externalResource.getURL()+"' style='text-decoration: [b]
display: block;
[/b]'>" +
                // The following lines are copy pasted from rendered Vaadin v6.1 buttons.
                "<div class='v-button' tabindex='0' [b]
style='width: 100%;'
[/b]>" +
                  "<span class='v-button-wrap'>" +
                    "<span class='v-button-caption'>"+
                      caption +
                    "</span>"+
                  "</span>"+
                "</div>"+
              "</a>",
              Label.CONTENT_XHTML);
        [b]
super.setWidth(null);
[/b]
    }
}

A word of warning: didn’t test this at all, so there might be something I missed, and it doesn’t even work this way :slight_smile:

Hi Joonas,

Although this implementation has accomplished a link-that-looks-like-a-button, I am interested of a different solution that do not use stylesheets. For the reason of reducing complexity in the server java code. Do you have any idea how this could be implemented quickly without using stylesheets and without creating a new client widgetset? I’m guessing there could be another way like handling button presses and redirecting the user to an external resource.

What about this then:


public class LinkButton extends Button {
    private String url;

    public LinkButton(String url, String caption) {
        super(caption);
        this.url = url;

        setImmediate(true);
        addListener(new Button.ClickListener() {
            LinkButton.this.getWindow().open(new ExternalResource(LinkButton.this.url), "_blank");
        });
    }
}

This should work, it generates a button, but acts as a link would do…

you’re right. It does the job and I cannot find anything easier.