apotomo icon indicating copy to clipboard operation
apotomo copied to clipboard

widget_div does not guarantee that HTML IDs are unique

Open cameel opened this issue 12 years ago • 6 comments

Let's assume that we have the following widgets:

class AWidget < Apotomo::Widget
  has_widgets do |root|
    root << widget(:b, :b1)
    root << widget(:b, :b2)
  end
  ...
end
class BWidget < Apotomo::Widget
  has_widgets do |root|
    root << widget(:c)
  end
  ...
end
class CWidget < Apotomo::Widget
  ...
end

Now I want to render_widget :a. Assuming that each of these classes has a single display action that renders only a widget_div, I get the following HTML structure:

#a
    #b1
        #c
    #b2
        #c

HTML IDs must be unique but this structure contains two DIVs with id c.

Why not make widget names hierarchical so that we could get the following instead?

#a
    #a_b1
        #a_b1_c
    #a_b2
        #a_b2_c

This will change HTML IDs and therefore can break CSS for some people so there should be a configuration option bring back the old behavior.

cameel avatar Sep 28 '11 09:09 cameel

With 1.2, you should be able to use root and parent in has_widgets blocks to retrieve the ancestor chain.

apotonick avatar Oct 12 '11 20:10 apotonick

Yes, this was already possible in 1.1.4. I am doing

has_widgets do |root|
  root << widget(:a_widget, root.name.to_s + "_a_widget_instance")
end

This makes the code less readable though. Whenever I render a widget I have to do

render_widget controller.name.to_s + "_a_widget_instance"

I think the default behavior is dangerous because many users are not aware of this problem. Simply rendering two instances of a widget that contains a nested widget silently breaks your HTML IDs.

cameel avatar Oct 12 '11 21:10 cameel

We could also enforce making ids unique when creating the widgets? If you compute an id dependent on the widget's position in the tree, you're also creating undesired side effects, I bet.

apotonick avatar Oct 12 '11 21:10 apotonick

If you mean requiring user to always provide unique ID then no, its not possible. In BWidget you only name the nested CWidget once, but there may be multiple instances of it (that require different names) if BWidget is instantiated multiple times.

If you mean making it unique by appending something random to it or (like in my example in the original post) constructing it from the names of all widgets on the path to the root then yes, it's exactly what is needed here.

Something that gives the same effects as my workaround is enough. Just hide the controller.name.to_s + "_" part inside render_widget() and widget_div() and root.name.to_s + "_" in widget() so that the user can refer to the widget is he does now.

cameel avatar Oct 12 '11 22:10 cameel

https://github.com/apotonick/apotomo/blob/master/lib/apotomo/rails/view_helper.rb

you can set the css element id yourself:

def widget_div(options={}, &block)
  options.reverse_merge!(:id => widget_id)

e.g.

widget_div(:id => 'something-unique') do

bf4 avatar Sep 12 '12 20:09 bf4

@camel Do you have a complete code example that would achieve what you are describing here? Perhaps the options argument to widget_div could take a unique: true option to use such a strategy?

kristianmandrup avatar Nov 22 '12 09:11 kristianmandrup