Losing my mind with Ajax link_to_remote


#1

I’m playing around with Rails, and I can’t get this to work. I just
can’t seem to wrap my brain around it. I’m having some trouble doing an
Ajax navigation column. Here’s what I have:

view layout:

<%= render(:partial => "navigation", :collection => @categories) %>

My _navigation.rhtml partial looks like:
<% if @params[:id].to_i == navigation.parentid.to_i %>
<%= link_to_remote navigation.name, :url => {:controller => “listing”,
:action => “browse”, :id => navigation.id, :update => “navigation”} %>


<% end %>

And my browse method is:
def browse
if @params[:id]
@item_pages, @items = paginate(:items, :per_page => 10,
:conditions => [“category_id = ?”, params[:id].to_i])
else
@item_pages, @items = paginate(:items, :per_page => 10)
end
end

Now, the basic premise is that the page should first look something
like:
[Main page]
cat1
cat2 stuff_from_all_categories
cat3

[After clicking on cat1]
cat1a
cat1b stuff_from_cat1_only
cat1c
cat1d

What do I need to do to get from main page to the cat1 page using Ajax
to update that category list? If I change the link_to_remote in my
partial to link_to I get my categories listed properly. However, I’m
changing pages each time and I’d love to not…

Thanks!


#2

Si Wi wrote:

<% if @params[:id].to_i == navigation.parentid.to_i %>
<%= link_to_remote navigation.name, :url => {:controller => “listing”,
:action => “browse”, :id => navigation.id, :update => “navigation”} %>


<% end %>

Maybe it’s just me, but isn’t you missing the navigation element?
AFAIK the :update parameter points to e.g. a div with id “navigation”.

[SNIP]

Greetings,
Gitte W.


#3

What do I need to do to get from main page to the cat1 page using Ajax
to update that category list? If I change the link_to_remote in my
partial to link_to I get my categories listed properly. However, I’m
changing pages each time and I’d love to not…

Is your browse method rendering a partial without a layout to display
the content on the side? Are you sure it’s not returning an error?

-Ben


#4

Benjamin S. wrote:

What do I need to do to get from main page to the cat1 page using Ajax
to update that category list? If I change the link_to_remote in my
partial to link_to I get my categories listed properly. However, I’m
changing pages each time and I’d love to not…

Is your browse method rendering a partial without a layout to display
the content on the side? Are you sure it’s not returning an error?

-Ben

I’m not sure if I’m completely follow your question (I’m finding lately
that I’m pretty dense :O), but in my browse.rhtml I have

<%= render(:partial => "navigation", :collection => @categories) %>

and my _navigation.rhtml is listed in my first post.

If I change the link_to_remote action to something like
def printit
p @params
end

I see the @params hash in my webrick output. Even without changing
that, I can see the call to /listing/browse/4?update=navigation in my
webrick output.

It seems like the action is working, but I must be missing something in
how to update the display of the categories themselves…

Any general advice on how best to accomplish this would be appreciated
as well as any troubleshooting on my current instantiation…

Thanks!


#5

My _navigation.rhtml partial looks like:
<% if @params[:id].to_i == navigation.parentid.to_i %>
<%= link_to_remote navigation.name, :url => {:controller =>
“listing”,
:action => “browse”, :id => navigation.id, :update =>
“navigation”} %>


<% end %>

Oh! You have :update in the URL params. Use this:

<%= link_to_remote navigation.name, :url => {:controller =>
“listing”,
:action => “browse”, :id => navigation.id}, :update =>
“navigation” %>

-Ben


#6

Tom F. wrote:

Once you apply all the other changes suggested here, you will need to
also
fix your browse.rhtml to be this (a single line):

<%= render(:partial => “navigation”, :collection => @categories) %>

The Update function changes everything inside the ‘navigation’ tag, it
does
not replace the tag itself, so your response to the update can’t include
the

element.

As a debugging note, you can see the parameters passed to your Rails
app,
and the URL, in the development.log file, so you don’t need to change
code
to see what is going on with your requests. Weirdly, these two items
are at
different ends of the log entry (the parameters at the beginning and the
URL
at the end)

Benjamin,
Thanks for catching that! I can’t try it out right now, but I’m sure
that must be it.

Tom,
So, really what I ultimately want to happen is for the navigation to be
updated with the subcategories, and also to have the contents of the
page change to reflect only items in the category that was clicked. So,
if my browse.rhtml should only be that 1 line, how do I accomplish that?

Thanks a lot for all of your help.


#7

Once you apply all the other changes suggested here, you will need to
also
fix your browse.rhtml to be this (a single line):

<%= render(:partial => “navigation”, :collection => @categories) %>

The Update function changes everything inside the ‘navigation’ tag, it
does
not replace the tag itself, so your response to the update can’t include
the

element.

As a debugging note, you can see the parameters passed to your Rails
app,
and the URL, in the development.log file, so you don’t need to change
code
to see what is going on with your requests. Weirdly, these two items
are at
different ends of the log entry (the parameters at the beginning and the
URL
at the end)


#8

Tom F. wrote:

Once you apply all the other changes suggested here, you will need to
also
fix your browse.rhtml to be this (a single line):

<%= render(:partial => “navigation”, :collection => @categories) %>

The Update function changes everything inside the ‘navigation’ tag, it
does
not replace the tag itself, so your response to the update can’t include
the

element.

As a debugging note, you can see the parameters passed to your Rails
app,
and the URL, in the development.log file, so you don’t need to change
code
to see what is going on with your requests. Weirdly, these two items
are at
different ends of the log entry (the parameters at the beginning and the
URL
at the end)

Ok, so I’m getting a page within the page… even after trying the
browse.rhtml change.

Any thoughts? I feel like part of my problem is that, when you click a
link in the navigation, I want the list of categories to change as well
as the page content, so I’m pretty confused about how to go about
achieving that. Sorry for the dumb questions…


#9

I believe you need to turn the layout off in the controller:

render( :layout => false )

I’m new to this stuff too, so that’s just a best guess.

Michael T.


#10

Ok, so I’m getting a page within the page… even after trying the
browse.rhtml change.

Is the full-page URL browse? If it is, you need to split off this
method to not use a layout. You can use the :except directive to
layout; see “Conditional layouts” at http://api.rubyonrails.com/
classes/ActionController/Layout/ClassMethods.html.

Any thoughts? I feel like part of my problem is that, when you
click a
link in the navigation, I want the list of categories to change as
well
as the page content, so I’m pretty confused about how to go about
achieving that. Sorry for the dumb questions…

Do you mean you want to update two different parts of the page? If
you’re willing to live on Edge Rails (or use the RJS plugin for Rails
1.0), you can use RJS templates to update multiple parts of a parts.
Alternatively, you can generate the JavaScript to update the proper
DOM nodes and build your own Ajax request that evaluates the returned
script; see update_element_function at http://api.rubyonrails.com/
classes/ActionView/Helpers/JavaScriptHelper.html#M000437.

-Ben


#11

The standard Rails Ajax replace system doesn’t work so well for updating
more than one thing on the page.

If you want to update two things on the page, the easiest way is with an
RJS
template to generate the Ajax response. RJS templates are in Edge rails
and
there is a plugin for Rails 1.0 that provides the same functionality.

Your RJS template (browse.rjs) would look like this:

# Update the Navigation
page.replace_html 'navigation', render(:partial => "navigation",

:collection => @categories)
# Update the Content Area
page.replace_html ‘content_area’, render(:partial => “content”, …)

You would need to change the link_to_remote call to remove the :update
=>
‘navigation’ piece, as this is needed with this new code.


#12

Benjamin S. wrote:

Ok, so I’m getting a page within the page… even after trying the
browse.rhtml change.

Is the full-page URL browse? If it is, you need to split off this
method to not use a layout. You can use the :except directive to
layout; see “Conditional layouts” at http://api.rubyonrails.com/
classes/ActionController/Layout/ClassMethods.html.

Any thoughts? I feel like part of my problem is that, when you
click a
link in the navigation, I want the list of categories to change as
well
as the page content, so I’m pretty confused about how to go about
achieving that. Sorry for the dumb questions…

Do you mean you want to update two different parts of the page? If
you’re willing to live on Edge Rails (or use the RJS plugin for Rails
1.0), you can use RJS templates to update multiple parts of a parts.
Alternatively, you can generate the JavaScript to update the proper
DOM nodes and build your own Ajax request that evaluates the returned
script; see update_element_function at http://api.rubyonrails.com/
classes/ActionView/Helpers/JavaScriptHelper.html#M000437.

-Ben

The :except symbol was exactly what I needed. I actually managed to
find it just before reading this post while watching the Ajax movie
linked from the JavaScriptHelper API docs. It works great now!

Incidentally, I just love watching those movies – I learn so much.
Anyone have any links to some other really good ones? I just pause the
thing and stare at all of the code (I assume that’s David, so I trust
that it’s good stuff :O)

Yes, I do want to update 2 different parts, the navigation menu and the
actual page content. Thanks a bunch for the pointers, I’ll take a good
look at those.

Thanks everyone for your help, I can go to sleep feeling like I’ve
accomplished something now!