2
votes

I'm trying to generate the following code with HAML within a .each loop. Depending on the true/false condition within the loop, it should either create a new div1 with a div2 or append div2 within the previous div1. This is a simplification of the logic:

Desired output:

if true, append `div2` within `div1`, 

    <div class="div1">    #added by true condition
      div1 text
      <div class="div2">  #added by true condition
        div2 text
      </div>
      <div class="div2">  #added by false condition
        div2 text
      </div>
      <div class="div2">  #added by false condition
        div2 text
      </div>
    </div>

else, create a new `div1` and add `div2` within it

    <div class="div1">    #added by true condition
      div1 text
      <div class="div2">  #added by true condition
        div2 text
      </div>
    </div>
    <div class="div1">    #new div1, added by true condition
      div1 text
      <div class="div2">  #added by true condition
        div2 text
      </div>
    </div>

Effectively, I'm trying to do this

  //within a loop logic
    - if condition == true
      .div1
        div1 text
    -# in all conditions
        .div2
          div2 text

This is my HAML logic, I was using tab_up but I don't think that's the correct HAML method:

  //within a loop logic
    - if condition == true
      .div1
        div1 text
    - tab_up(2)  #trying to indent the HAML, not just the HTML output
    .div2
       div2 text
1
What do you mean by “generated programmatically”? In order for div2 to be inside div1 it needs to be more indented in the Haml source than div1. tab_up just controls the output appearance, it doesn’t effect the structure. You need to provide an example of what you’re trying to do. - matt
The question isn't clear. The solution you ruled out is obviously the right one. - Marcelo De Polli
Thanks matt & depa, I've tried to clear this up some more. - netwire

1 Answers

0
votes

The way to do things like this in Haml is to organise your data before tying to convert it to HTML. The methods of Enumerable can help here.

The way you’ve described the problem, splitting your enumerable with slice_before looks like the most direct solution – you want to open a new div1 before every item where the condition is true (here I’m assuming that the condition depends on the item). Possibly something like this:

- items.slice_before {|item| determine_condition(item) }.each do |div1_block|
  .div1
    div1 text
    - div1_block.each do |item|
      .div2
        div2 text

Depending on what you’re actually trying to do, there may be a better way to organise your data – the way it is described here suggests you are looking at it at a lower level than needed because you are already thinking in terms of iterating and creating the HTML as you go.

The basic idea would be to get an array (or Enumerator) of arrays, with each inner array representing the contents of a div1. The Haml then falls out pretty easily. chunk, each_slice and group_by are some Enumerable methods that might be worth looking at.