100

In my Rails template, I'd like to accomplish final HTML to this effect using HAML:

I will first <a href="http://example.com">link somewhere</a>, then render this half of the sentence if a condition is met

The template that comes close:

I will first
= link_to 'link somewhere', 'http://example.com'
- if @condition
  , then render this half of the sentence if a condition is met

You may, however, note that this produces a space between the link and the comma. Is there any practical way to avoid this whitespace? I know there's syntax to remove whitespace around tags, but can this same syntax be applied to just text? I really don't like the solution of extra markup to accomplish this.

Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
Matchu
  • 83,922
  • 18
  • 153
  • 160

13 Answers13

215

A better way to do this has been introduced via Haml's helpers:

surround

= surround '(', ')' do
  %a{:href => "food"} chicken
Produces:
(<a href='food'>chicken</a>)

succeed:

click
= succeed '.' do
  %a{:href=>"thing"} here
Produces:
click
<a href='thing'>here</a>.

precede:

= precede '*' do
  %span.small Not really
Produces:
*<span class='small'>Not really</span>

To answer the original question:

I will first
= succeed ',' do
  = link_to 'link somewhere', 'http://example.com'
- if @condition
  then render this half of the sentence if a condition is met
Produces:
I will first
<a href="http://example.com">link somewhere</a>,
then render this half of the sentence if a condition is met
Alexis
  • 4,317
  • 1
  • 25
  • 34
Ryenski
  • 9,582
  • 3
  • 43
  • 47
  • 1
    Nice timing, I just found out about these by reading Haml's source. Apparently they've been around for a while. Odd that they don't document them in the main reference page... – Groxx Jun 10 '11 at 23:51
  • 1
    Can you expand your answer and show to express the OP's example using these helpers (presumably `succeed` specifically)? To me it still seems non-obvious and a little ugly: https://gist.github.com/1665374 – John Jan 23 '12 at 20:27
  • 16
    I feel like I am missing something (while looking on upvotes count), but the *succeed* variant isn't equivalent to the original one, because trailing comma will be rendered even if `@condition == false`, which is more ugly than space before this comma. – Nash Bridges Jun 29 '12 at 06:36
  • 2
    I managed to get the correct result by using precede, rather than succeed. Cheers! – Cam Oct 20 '14 at 02:05
40

You can also do this using Haml's "trim whitespace" modifier. Inserting > after a Haml declaration will prevent whitespace from being added around it:

I will first
%a{:href => 'http://example.com'}> link somewhere
- if @condition
  , then render this half of the sentence if a condition is met

produces:

I will first<a href='http://example.com'>link somewhere</a>, then render this half of the sentence if a condition is met

However, as you can see, the > modifier also strips the whitespace in front of the link, removing the desired space between the words and the link. I haven't figured a pretty way around this yet, except to add &nbsp; to the end of "I will first", like so:

I will first&nbsp;
%a{:href => 'http://example.com'}> link somewhere
- if @condition
  , then render this half of the sentence if a condition is met

Which finally produces the desired output without lots of hard-to-read interpolation:

I will first&nbsp;<span><a href="http://example.com">link somewhere</a></span>, then render this half of the sentence if a condition is met
Ryenski
  • 9,582
  • 3
  • 43
  • 47
  • 1
    Forgot to mention that I got this from the Haml cheat sheet, which is very helpful: http://cheat.errtheblog.com/s/haml/ – Ryenski Oct 07 '09 at 11:35
  • 3
    It works with tags but not expressions; in your example you've changed his expression to a tag. I have the same issue and unfortunately this is not a solution. – Teflon Ted Oct 22 '09 at 13:39
  • 1
    I would remark that ` ` have a special meaning to it, it's not an ordinary whitespace - it's non-breaking whitespace, which means that during word-wrapping browser would do everything to keep words tied with ` ` together and this is not always what you want. – Andrew Feb 03 '13 at 19:44
  • 1
    In addition to Andrew's comment, use ` ` instead of ` ` for just a plain whitespace. – Daniel A. R. Werner Apr 10 '16 at 20:31
12

Alright, here's the solution I'm settling on:

Helper

def one_line(&block)
  haml_concat capture_haml(&block).gsub("\n", '').gsub('\\n', "\n")
end

View

I will first
- one_line do
  = link_to 'link somewhere', 'http://example.com'
  - if @condition
    , then render this half of the sentence
    \\n
    if a condition is met

That way, whitespace is excluded by default, but I can still explicitly include it with a "\n" line. (It needs the double-backslash because otherwise HAML interprets it as an actual newline.) Let me know if there's a better option out there!

Matchu
  • 83,922
  • 18
  • 153
  • 160
  • Note to world: I eventually wised up and moved these to helpers :P – Matchu Jan 29 '10 at 18:16
  • Another note to world: these days, I use Groxx's solution :) – Matchu Jul 14 '11 at 17:26
  • This is very helpful when it comes to haml that generates a text file! In my case I had one line where part of it was decided by an "if", which I couldn't fix with mysamillidea's solution because it doesn't get rid of newlines, it just moves the comma before the newline. (Though I agree that for the answer to the original question mysmallidea's is the best.) – cesoid Jul 13 '15 at 15:53
6

You can use the 'aligator syntax' of HAML

Whitespace Removal: > and <

and < give you more control over the whitespace near a tag. > will remove all whitespace surrounding a tag, while < will remove all whitespace immediately within a tag. You can think of them as alligators eating the whitespace: > faces out of the tag and eats the whitespace on the outside, and < faces into the tag and eats the whitespace on the inside. They’re placed at the end of a tag definition, after class, id, and attribute declarations but before / or =.

http://haml.info/docs/yardoc/file.REFERENCE.html#whitespace_removal__and_

Yo Ludke
  • 2,149
  • 2
  • 23
  • 38
5

Once approach I've taken to this sort of thing is to use string interpolation:

I will first #{link_to 'Link somewhere'}#{', then render this half of the sentence if a condition is met' if condition}

I don't like the look of the literal string in the interpolation, but I've used it with previously declared strings or dynamically generated strings before.

Chuck
  • 234,037
  • 30
  • 302
  • 389
  • Mhm. That's my general approach to things like that, but I had never thought of using the conditional in there. It's a shame that the actual template I was using turned out to be a bit more complex than just a second half of a sentence... but that's definitely worth remembering - thanks! – Matchu Aug 21 '09 at 23:19
5

You can do this to keep the leading space:

%a{:href => 'http://example.com'}>= ' link somewhere'

The space is in the quotes.

Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
thethinman
  • 322
  • 1
  • 6
3

Although not well documented, this is cleanly achieved using HAML whitespace preservation (>) combined with an ASCII space (& #32;), and not with helpers:

%a{:href=>'/home'}> Home link
,&#32; 
%a{:href=>'/page'} Next link

This will produce what you want:

<a href='/home'>Anchor text</a>,&#32;
<a href='/page'>More text</a>

But I agree, HAML needs to come up with a better way of doing this, as it does add unnecessary ASCII characters to the page (but it's still more efficient than using helpers).

ojak
  • 41
  • 2
1

There's the angle bracket "whitespace munching" syntax, otherwise write a helper method for it.

Andrew Vit
  • 18,961
  • 6
  • 77
  • 84
  • How exactly would a helper for that work? Meh, I'll see what I can come up with... – Matchu Aug 21 '09 at 11:50
  • As for whitespace munching, I can't work out how to make that syntax work if it's not on some sort of tag definition. Am I just doing it wrong, or does that syntax not work without a tag? – Matchu Aug 21 '09 at 11:51
1

Yet another option that I've used in the past:

- if @condition
  %span> , then some more text after the link.
colllin
  • 9,442
  • 9
  • 49
  • 65
1

I came across a similar problem and found this so I thought I would post another solution which doesn't require a helper method. Use Ruby interpolation #{} to wrap the link and if statements:

I will first 
#{link_to 'link somewhere', 'http://example.com'}#{if true : ", then render this half of the sentence if a condition is met" end}

This works in 3.0.18, it may also work in earlier releases.

biscuits
  • 72
  • 3
  • Granted, Haml isn't designed for content. This isn't content that we're talking about there, though. It's a template. The author of that blog post is referring to things like writing a full static webpage in Haml, which isn't what I'm doing. The code snippet I provided is pretty much the full `.haml` file — the fact that it includes a link and a comma doesn't really indicate anything either way. – Matchu Sep 18 '10 at 22:04
  • 1
    Ah, I see. I've edited my answer, leaving the solution to stand on its own. – biscuits Sep 19 '10 at 04:57
  • While this may work I think it makes for hard to read markup. Instead just use the HAML whitespace modifiers < and > as other people have mentioned which keeps your HAML clean and readable. – ToddH Mar 19 '11 at 00:19
0

You could also always do:

= link_to url_path do 
  = ["part_1", "part_2"].join(", ")
bcackerman
  • 1,486
  • 2
  • 22
  • 36
0

The solution that I got working is:

I will first
= link_to 'link somewhere', 'http://example.com'
- if @condition
  = ", then render this half of the sentence if a condition is met"

You can use =, though = is used to output the result of Rails code, but here it will server the purpose.

Arslan Ali
  • 17,418
  • 8
  • 58
  • 76
0

The preserve function worked for me

.white-space-pre= preserve "TEXT"

gtournie
  • 4,143
  • 1
  • 21
  • 22