How to build nested menu "trees" in HAML

I am trying to create a simple nested html menu using HAML and do not know how to do this by inserting elements with the right indentation , or the general best way to build nested trees. I would like to be able to do something similar, but infinitely deep:

- categories.each_key do |category| %li.cat-item{:id => "category-#{category}"} %a{:href => "/category/#{category}", :title => "#{category.titleize}"} = category.titleize 

It seems to me that I could do this quite easily without resorting to manually writing tags in html, but I'm not the best with recursion. Here is the code I just came up with:

View Assistant

 def menu_tag_builder(array, &block) return "" if array.nil? result = "<ul>\n" array.each do |node| result += "<li" attributes = {} if block_given? text = yield(attributes, node) else text = node["title"] end attributes.each { |k,v| result += " #{k.to_s}='#{v.to_s}'"} result += ">\n" result += text result += menu_tag_builder(node["children"], &block) result += "</li>\n" end result += "</ul>" result end def menu_tag(array, &block) haml_concat(menu_tag_builder(array, &block)) end 

View

 # index.haml, where config(:menu) converts the yaml below # to an array of objects, where object[:children] is a nested array - menu_tag(config(:menu)) do |attributes, node| - attributes[:class] = "one two" - node["title"] 

YAML example defining a menu

 menu: - title: "Home" path: "/home" - title: "About Us" path: "/about" children: - title: "Our Story" path: "/about/our-story" 

Any ideas how to do this, the output is as follows:

 <ul> <li class='one two'> Home </li> <li class='one two'> About Us </li> </ul> 

... not this way:

 <ul> <li class='one two'> Home</li> <li class='one two'> About Us</li> </ul> 

... and therefore he is rightly taken away all over the world.

Thanks for the help, Spear

+4
source share
4 answers

Haml's beautiful indentation trick created by Ruby's code is haml_tag helper . Here's how I would convert your menu_tag method to using haml_tag :

 def menu_tag(array, &block) return unless array haml_tag :ul do array.each do |node| attributes = {} if block_given? text = yield(attributes, node) else text = node["title"] end haml_tag :li, text, attributes menu_tag_builder(node["children"], &block) end end end 
+5
source

How about something line by line:

 def nested_list(list) return unless list haml_tag :ul do list.each do |item| haml_tag :li do haml_concat link_to item["title"], item["path"] if item["children"] nested_list item["children"] end end end end end 
+3
source

An amazing hint @shingara set me in the right direction :). This works great:

 def menu_tag(array, &block) return "" if array.nil? haml_tag :ui do array.each do |node| attributes = {} if block_given? text = yield(attributes, node) else text = node[:title] end haml_tag :li, attributes do haml_concat text menu_tag_builder(node[:children], &block) end end end end 

If someone can do this even shorter or simplify the configuration of attributes on nested nodes, I will mark this as correct instead.

Greetings.

0
source

This is because you are submitting your HTML code by your assistant. Indentation becomes with HAML. You can create some HAML in your helper.

-2
source

Source: https://habr.com/ru/post/1303765/


All Articles