# Ajax partial need unique ids?

**URL:** <https://www.ruby-forum.com/t/ajax-partial-need-unique-ids/158628>\
**Category:** Rails\
**Created:** [January 26, 2009, 2:44am UTC](https://www.ruby-forum.com/t/ajax-partial-need-unique-ids/158628 "2009-01-26T02:44:01Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![david](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/aeb1de/32.png) [@david](https://www.ruby-forum.com/u/david)\
**Post date:** [January 26, 2009, 2:44am UTC](https://www.ruby-forum.com/t/ajax-partial-need-unique-ids/158628/1 "2009-01-26T02:44:01Z")

</div>

Im not sure about the best way to go about dealing with the following  
situation. I have a number of popups that each contain a link “add  
time” which ajaxes and renders a partial:

page.replace\_html “add\_appt\_#{params[:day]}”, :partial =\> ‘add\_appt’

and within this partial a javascript function is called which  
populates an element with id “start\_time”. The problem that I am  
facing is that if I click and close the partial without replacing the  
new partial, the javascript function finds the first element in the  
DOM with id “start\_time” and it doesnt work. My question is would it  
be better to rename all the start\_time elements so that they are all  
unique? or would it be better to somehow replace the html upon the  
closing of the popup? or is there an even better solution that I  
havent yet considered?

---

<div class="post-metadata">

**Author:** ![david](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/aeb1de/32.png) [@david](https://www.ruby-forum.com/u/david)\
**Post date:** [January 26, 2009, 4:07am UTC](https://www.ruby-forum.com/t/ajax-partial-need-unique-ids/158628/2 "2009-01-26T04:07:45Z")

</div>

David wrote:

> DOM with id “start\_time” and it doesnt work. My question is would it  
> be better to rename all the start\_time elements so that they are all  
> unique? or would it be better to somehow replace the html upon the  
> closing of the popup? or is there an even better solution that I  
> havent yet considered?

You should generally get in the habit of uniquifying all HTML IDs. This  
is  
partly because it’s The Law (y’heah, right!), and partly so when you  
actually  
need them

Your ID should be “start\_time\_\<%= @record.id %\>”, because your database  
IDs are  
generally unique to the system.

Further, the View Tests on your partial, and on your ajax handler,  
should expect  
unique IDs. As a big digression, here’s how we do that at work. (If  
this code  
had used the @record.id trick, it would appear in the assertions!):

```
def test_render_skim_panel_cc
  site_list = sites(:doctors_site, :lawyers_site)

  render :partial => 'skim_panel',
          :locals => { :@sites => site_list,
                       :@payment_method => 'cc' }

  assert_xpath :select, :cc_skim_selection do
    site.skims.visible('cc').each do |skim|
      option = assert_xpath(:option, :value => skim.id)
      assert{ option.text == skim.name }
    end
    site.skims.visible('ach').each do |skim|
      deny_xpath :"option[@value = '#{skim.id}']"
    end
  end
end

```

(Parenthetically, can Merb’s fixtures return a list of records from one  
sites()  
call like that?)

The test renders the partial that displays a panel containing a   
list of  
skims (aka “special offers”). The panel contains only Credit Card  
offers, no ACH  
(Checking) offers. The first assert\_xpath() call discovers the   
list  
with the correct name. The subsequent assertions must pass inside this  
list -  
another option in another panel cannot cause a false positive.

The internal assert\_xpath() finds each CC skim in our model, and matches  
its  
name. I could have written assert\_xpath(“option[ @id = ‘#{skim.id}’ and  
@value =  
‘#{skim.name}’ ]”), but running this XPath as a Ruby DSL saves a lot of  
ugly  
string-mashing code.

Further, I can’t tell from the have\_xpath() documentation if you can  
nest the  
XPaths, or if you can use the returned node, like have\_xpath().text. I  
am aware  
of XPath functions such as contains(), but it seems that more complex  
sub-assertions, in the Ruby code, are impossible.

The last assertion denies that the wrong skims appeared in the list.  
There are  
also lower-level tests on the model things that the partial calls, and  
there are  
higher level tests on the entire page containing this partial. Any port  
in a storm!

This test covers one of the Ajax handlers. It returns JavaScript that  
pushes the  
‘skim\_panel’ partial into the correct container:

```
def test_populate_empty_skim_list
  site_list = sites(:doctors_site, :lawyers_site)
  site_list.map(&:skims).map(&:destroy_all)
  xhr :post, :xhr_populate_skims, :sites => site_list

  assert_js_replace_html :skim_panel_cc do
    assert_xpath :select, :cc_skim_selection do
      deny_xpath '*'
    end
  end
end

```

assert\_js\_replace\_html() lexes the returned JavaScript, and finds the  
Replace.element(‘skim\_panel\_cc’) call. Then it finds the string payload  
inside  
that, evaluates this as XHTML, and preps that to work with  
assert\_xpath().

The assert\_xpath() call detects the , and  
the  
nested deny\_xpath() simply determines that it is empty.

The point of all this lexing and nesting is to pinpoint the regions that  
need  
test, and exclude the ones that don’t. If that deny\_xpath failed, its  
diagnostic  
would not report the entire page. It would only report the contents of  
the  
 tag around the assertion.

assert\_js\_replace\_html() works a lot like the ARTS assert\_rjs() call,  
but that  
only uses regular expressions. I told my colleague to use the latter  
this week,  
and he immediately discovered that a call like assert\_rjs :replace\_html,  
‘skim\_panel\_cc’, /\<select id=.ach\_skim\_selection/ could get fooled by  
an  
‘ach\_skim\_selection’ from the next Replace.element() call! Our Ajax is  
delightfully complex, so we don’t need this kind of noise at test time.

Testing like this helps us make Ajax abuse competitive with a desktop  
environment, such as forms developed with C#.

–  
Phlip

---

<div class="post-metadata">

**Author:** ![david](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/aeb1de/32.png) [@david](https://www.ruby-forum.com/u/david)\
**Post date:** [January 26, 2009, 6:41pm UTC](https://www.ruby-forum.com/t/ajax-partial-need-unique-ids/158628/3 "2009-01-26T18:41:08Z")

</div>

Phlip wrote:

> You should generally get in the habit of uniquifying all HTML IDs. This  
> is  
> partly because it’s The Law (y’heah, right!), and partly so when you  
> actually  
> need them  
> Well maybe it’s not “The Law” as you say, but it certainly is illegal  
> within the context of the standard. Pages with duplicate id attributes  
> will not validate:

## Excerpt from the W3C HTML 4.01 documentation:

## id = name [CS] This attribute assigns a name to an element. This name must be unique in a document.
