views:

220

answers:

4

Hi All,

I'm looking for a way to append elements with javascript using javascript. Basically I have two lists of items. One has a list of items with an "ADD" button (using "link_to_remote") and the other has a list of items with a "REMOVE" button (using "link_to_remote"). When I click the "ADD" it immediately places the item into the other list. However, I need to be able to have the newly inserted item perform the reverse action for "REMOVE".

I see no way (besides, perhaps creating a partial to render a non-object) to dynamically generate dynamic items of this nature.

Any ideas?

Best.

A: 

you might be looking for some javascript templating solution. Check this link out...

http://www.hokstad.com/mini-reviews-of-19-ruby-template-engines.html

Hope this answers your question.

koss
A: 

WARNING: hacky solution.

I have a select list that I need to dynamically add and remove elements from. Both are AJAX calls.

The controller method renders a partial that contains Javascript to add and/or remove the items from the select list. The partial, which is a plain old erb file like any other partial, inserts the appropriate DOM identifiers (which are generated from the object IDs of the objects in the list).

I looked at a few Javascript templating solutions, but none of them were flexible enough. In the end it was easier to generate the Javascript myself.

Sarah Mei
Yeah, that's what I'm currently doing. It seems to work ok, I just wish I could figure out a way to bring it back from a partial. The proper syntax for using helper methods in controllers isn't intuitive (if at all possible) to me. Thanks.
humble_coder
+1  A: 

Have you checked out jQuery? It is a popular JavaScript library. It can do exactly what you described with ease. I've used it for years and it's never let me down.

This page of the documentation shows the append() method. You can do stuff like...

$("span").appendTo("#foo");

The $("span") part is finding an element (or elements) of the DOM, then the appendTo("#foo") part is appending it to another element of the DOM.

You can also append arbitrary snippets of HTML. If needed, such a snippet could be retrieved via an AJAX request. jQuery has really simple and reliable AJAX support.

With jQuery, the basic concept is that you bind JavaScript methods to DOM elements in a separate .js file, rather than using HTML "on_this" or "on_that" attibutes. So if you used jQuery for this situation, you wouldn't think in terms of generating JS code through templates. The add() and remove() functions would be in your .js file ready to go and you would bind and unbind them to DOM elements as needed. For example, when you added an li to the list, you'd unbind your add() function from the li and bind the remove() function to it.

Ethan
A: 

This can be fairly easy. There are a bunch of things doing this for you (check out jquery).

I handcoded something a while ago (sorry for the poorly written code). It adds and remove tracks from a playlist

controller:

def add_track
    unless session[:admin_playlist_tracks].include?(params[:recording_id])
      session[:admin_playlist_tracks] << params[:recording_id]
    end
    render :partial => "all_tracks"
  end

  def remove_track
    session[:admin_playlist_tracks].delete_if {|x| x.to_s == params[:recording_id].to_s }
    render :partial => "all_tracks"
  end

container:

<div id="artist_recordings" class="autocomplete_search"></div>

Adding stuff:

<%= link_to_remote  "Add", 
           :url => {:controller => :playlists, :action => :add_track, :recording_id => recording.id}, 
           :update =>"all_tracks",
           :complete => visual_effect(:highlight, 'all_tracks') %>

Displaying / removing stuff:

<%session[:admin_playlist_tracks].each do |recording_id|%>
     <div style="margin-bottom:4px;">
      [<%=link_to_remote "Remove", 
            :url => {:controller => :playlists, :action => :remove_track, :recording_id => recording_id}, 
            :update =>"all_tracks"%>]
      <%recording = Recording.find_by_id(recording_id)%>      
      <%=recording.song.title%> <br />
      by  <%=recording.artist.full_name%> (<%=recording.release_year%>)
     </div>     
    <%end%>

This worked with me because I could use session variable. But be careful! In some cases where a user will have various windows with the same form, this will surely break since there will be concurrent access on the session variable.

There are some parts missing because I'm doing some autocomplete on this as well, but I hope this will help you get the big idea.

marcgg
Thanks for all that, but I'm trying to use Rails and Rails Helpers only for this. If there is no way of doing that then I'll go the JS route. Currently I'm simply using partials to handle everything but I'd like to be able to do it from the "render :update" section. Thanks again.
humble_coder