Task D: A Dash Of Ajax #3

I still get the flicker as if the tr element is showing with the code suggestion below if I use grow as hinted. I think blind_down may be hiding the fact that the code is buggy. Hiding the tr element and using grows shows the same flicker that was fixed earlier in the chapter by hiding the div. I'm assuming the bug isn't related to these js effects not working with block elements (why would the blind_down work with showing the cart the first time???) So, why is the flicker still occurring with the below code then? Seems like the code suggestion below is still buggy.

I had trouble finding a canonical mapping of the effects as they are named in the effects.js => how to access them in RoR?. I tried "shake" and "grow" but gave up.

Marcello:

You should use a symbol with the name of the effect (as set in the Effect.VIsualEffect? js functions). Something like that:

page[:current_item].visual_effect :grow

Any thoughts on sharing the cart item partial between the AJAX & the initial page display?

I came here looking for an answer to this problem, thought i'd find it here?! When I just add the line page[:current_item].visual_effect :grow to add_to_cart.rjs, the cart just blinks and winks at me, but its not pretty.

  • where does the page[:current_item].visual_effect :grow line go?
  • how do you hide the item initially if qty is 1?
  • whats the answer to the shared cart partial question?

I'm not sure about the cart item question, but here's my guess. If you want special effects based on the cart, you could have the cart items initially be hidden using CSS (such as using the hidden_div trick). However, only the Javascript from add_to_cart.rjs would be able to "unhide" the item by using "grow" or similar.

This makes it tough to share the code because the initial page display doesn't have the code to unhide the divs. If the user does a refresh, their cart is the same, but the store controller doesn't know to unhide the items.

I wanted to use the BlindDown? effect for this if a new item appeared and the Highlight if the item already exists. These two effects need these lines in my add_to_cart.rjs:

page[:current_item].visual_effect :blind_down if @current_item.quantity == 1
 
page[:current_item].visual_effect :highlight,
                                  :startcolor => "#88ff88",
                                  :endcolor => "#114411" unless @current_item.quantity == 1

For hiding the line I wrote a new helper, just like the one for divs, named hidden_tr_if… this goes to store_helper.rb:

def hidden_tr_if(condition, attributes = {})
  if condition
    attributes["style"] = "display: none"
  end
  attrs = tag_options(attributes.stringify_keys)
  "<tr #{attrs}>"
end

Now the _cart_item.rhtml has to use this helper. One question is: what happens if we don't have JavaScript?? The CSS would still kick in and hide the tr element… but we can get around this by choosing the condition right. This is how I call the method in my _cart_item.rhtml:

<% if cart_item == @current_item %>
    <%= hidden_tr_if(cart_item.quantity == 1 && request.xhr?, :id => "current_item") %>
<% else %>
   <!--  ... -->

Now I only hide the line using CSS if the view got invoked from a xhr request and this request can only happen if JavaScript? is active.

There is only one problem I still have and right now I don't have the solution: My BlindDown? is not beautiful. It is way too fast. I tried to change this line in add_to_cart.rjs

page[:current_item].visual_effect :blind_down if @current_item.quantity == 1

to this

page[:current_item].visual_effect :blind_down,
                                  :duration => 10 if @current_item.quantity == 1

but it has no effect on the speed at all. I tried all kinds of values without effect. I also tried the same duration parameter on the Highlight effect, there it works like a charm.

Anybody knows what is wrong with my BlindDown??

I'm new to Wiki's so sorry if this is in the wrong place but…

In answer to the question above "Anybody knows what is wrong with my BlindDown??"

I had a look at http://script.aculo.us and it says: "Works safely with most Block Elements, except table rows, table bodies and table heads."

This could be the problem if you are using table rows?

Just a note following the last comment to keep your code clean.

Instead of adding a new method to the store_helper.rb file, replace the hidden_div_if method with:

def hidden_element_if(element, condition, attributes = {})
  if condition
    attributes["style"] = "display:none"
  end
  attrs = tag_options(attributes.stringify_keys)
  "<#{element} #{attrs}>"
end

Then in _cart_item.rhtml, call the method with:

<% if cart_item == @current_item %>
  <%= hidden_element_if("tr", cart_item.quantity == 1 && request.xhr?, :id => "current_item") %>
<% else %>
...

Just make sure you change the method call accordingly for the div tag in store.rhtml.

I don't know if it's a good idea, but I've done the following

module StoreHelper
  def method_missing(name, *params, &block)
    if match = name.to_s.match('hidden_(\w+)_if')
      hidden_if(match[1], *params, &block)
    end
  end
 
  def hidden_if(tag, condition, attributes = {}, &block)
    if condition
      attributes['style'] = 'display: none;'
    end
    attrs = tag_options(attributes.stringify_keys)
 
    if block
      concat("<#{tag}#{attrs}>", block.binding)
      yield
      concat("</#{tag}>", block.binding)
    else
      "<#{tag}#{attrs}>"
    end
  end
end

And I use the following on the templates.
<%= hidden_tr_if(@current_item.quantity == 1, :id => 'current-item') %>
  ...
</tr>
<% hidden_div_if(@cart.items.empty?, :id => 'cart') do -%>
  <%= render :partial => 'cart', :object => @cart %>
<% end -%>

This way I can use both idioms and for any tag.

Anthony Ettinger says:

I tried effects too, but also saw that they only work on block elements. Since the shopping cart is a table (as it should be), there's no point in working around the clock to get a shake/grow pair working. I originally thought a slide_right/left would be cool for cart items, but alas, they only work on blocks as well.

Its more important to have the data show in a table (qty | title | price) then it is to convert to a pseudo-table using nested unordered lists…although that would be the route I would take should it be a requirement.

page_revision: 0, last_edited: 1196814376|%e %b %Y, %H:%M %Z (%O ago)
Unless stated otherwise Content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License