I have an application where user can see a list of cells. For each cell the user can see two images of the cell as popup menu. The problem is that all images are downloaded when a list is selected and that makes my page very slow.
I would like that the image is downloaded only if mouse is rolled-over the link.
For information: I’m using DOM popup kit link text
Here the main page and link to popup menu
<div id="span_div">
<span id="cell_link_<%= #cell.cellid %>" class="popup_link" Popup.modal = true><%= #cell.cellname%>
<%= render :partial => 'cell_popup' %>
<%= javascript_tag "new Popup('cell_popup_#{#cell.cellid}','cell_link_#{#cell.cellid}')" %>
</span>
</div>
Here a partial for cell images
<div id="cell_popup_<%= #cell.cellid %>" class="popup popup_draghandle" style="display:none">
<table width="418" border="0">
<tr>
<td width="201" align="center" valign="top">Raw</td>
<td width="201" align="center" valign="top">Repaired</td>
</tr>
<tr>
<td align="center" valign="top">
<% if #full_report == true then%>
<%raw_morph = #raw_morph.last%>
<img src="<%= url_for(:action => 'jpegfile', :controller => 'neuronviewer',:morph_id => raw_morph.morphologyid)%>" alt="" width="200" height="200"/>
<%end%>
</td>
<td align="center" valign="top">
<%if #repaired == true then%>
<%repaired_morph = #repaired_morph.last%>
<img src="<%= url_for(:action => 'jpegfile', :controller => 'neuronviewer', :morph_id => repaired_morph.morphologyid)%>" alt="" width="200" height="200"/>
</td>
</tr>
<%end%>
</table>
Anyone have any idea to do that?
Essentially the idea is to create an on mouseover action for your span that loads the images with an AJAX request. We'll use a cache variable to ensure that you aren't making the same request multiple times in a for one page load.
The following assumes Prototype. I haven't time to test it, so don't expect a flawless example.
Most of the work is done by adding an on mouseover attribute to the span.
<span id="cell_link_<%= #cell.cellid %>" class="popup_link" Popup.modal = true
onmouseover="<%=remote_function(:update => "cell_popup_#{#cell.cellid}",
:url =>
popup_cell_url(#cell, :full_report => #full_report, :repaired => #repared),
:success => "cell_#{#cell.cellid}_loaded = true",
:conditions => "cell_#{#cell.cellid}_loaded == false") %>"
><%= #cell.cellname%>
Now to clean things up:
Move everything in the partial but the div to a view called cell. Fill the void with a generic Fetching images message.
So your partial now looks like:
<div id="cell_popup_<%= #cell.cellid %>" class="popup popup_draghandle" style="display:none">
Fetching images. Please stand by.
</div>
And your new view called popup looks like:
<table width="418" border="0">
<tr>
<td width="201" align="center" valign="top">Raw</td>
<td width="201" align="center" valign="top">Repaired</td>
</tr>
<tr>
<td align="center" valign="top">
<% if #full_report == true then%>
<%raw_morph = #raw_morph.last%>
<img src="<%= url_for(:action => 'jpegfile', :controller => 'neuronviewer',:morph_id => raw_morph.morphologyid)%>" alt="" width="200" height="200"/>
<%end%>
</td>
<td align="center" valign="top">
<%if #repaired == true then%>
<%repaired_morph = #repaired_morph.last%>
<img src="<%= url_for(:action => 'jpegfile', :controller => 'neuronviewer', :morph_id => repaired_morph.morphologyid)%>" alt="" width="200" height="200"/>
<%end%>
</td>
</tr>
</table>
Now all that's left is to connect the controller to the new view and prepare it for AJAX.
Add a popup route responding to get for the cell controller.
map.resources :cells, :member => {:popup => :post}
Add the action to the CellsController
def popup
# sets #cell, #repaired, #full_report, #raw_morph,
# #repaired_morph and anything else needed by the popup view.
end
Related
I have made grid with html table tag .in one of TD tag I have this code
<td>
<a onclick="$('#lightBox').css('display','inline')"></a>
<div style="display: none" id="lightbox">
<%--<%Html.RenderAction("LightBox","PremiumSharingAdmin",new {historyId = premium.SharingPremiumHistoryID}); %>--%>
<img src="Storage/Images/<%=premium.SharingPremiumHistoryID %>.jpg" title="image" width="100" height="100"/>
<div>
<textarea readonly="readonly">
<%= premium.Content %>
</textarea>
</div>
<div>
<input type="text" readonly="readonly" value="<%= premium.SharingTitle %>"/>
</div>
</div>
</td>
These tag provide me some extra info from grid row that By default is hidden.
In other side I have Link tag that if user pressed that display that row.
but problem is that when I pressed it, it just show me the first record detail and when I press the others it show me the first row detail.
where is the problem guys ?
This is my whole ASPX view
<% foreach (var premium in Model)
{%>
<tr>
<td style=" font-weight: bold;width: 130px;">
<span ><%= premium.SharingTitle %></span>
</td>
<td style=" font-weight: bold;width: 130px;">
<span ><%= premium.AddedDate.ConvertToPersianDate(true) %></span>
</td>
<td style="width: 130px;">
<span> <%= premium.IsSubmit %></span>
</td>
<td style="width: 130px;">
<span> <%= premium.ResturantName %></span>
</td>
<td style="width: 130px;">
<span> <%= premium.Content %></span>
</td>
<td style="width: 130px;">
<div class="group">
<a class="delete" href="<%= Url.Action("submit", "PremiumSharingAdmin", new {historyId = premium.SharingPremiumHistoryID}) %>" onclick="return confirm('آیا میخواهید این خبر را تایید کنید؟');">تایید</a>
</div>
</td>
<td>
<a onclick="$('#lightBox').css('display','inline')"></a>
<div style="display: none" id="lightBox">
<%--<%Html.RenderAction("LightBox","PremiumSharingAdmin",new {historyId = premium.SharingPremiumHistoryID}); %>--%>
<img src="Storage/Images/<%=premium.SharingPremiumHistoryID %>.jpg" title="image" width="100" height="100"/>
<div>
<textarea readonly="readonly">
<%= premium.Content %>
</textarea>
</div>
<div>
<input type="text" readonly="readonly" value="<%= premium.SharingTitle %>"/>
</div>
</div>
</td>
</tr>
<%} %>
You are generating invalid html by giving multiple <div> elements the same id attribute. $('#lightBox').css('display','inline') will return all elements with id="lightbox" but set the style of only the first.
Instead, use class names and use relative selectors. I also recommend you use Unobtrusive Javascript and css, rather tan polluting your mark up with behavior.
Html
<td>
Show
<div class="lightbox">Some content to display</div>
</td>
CSS
.lightbox {
display: none;
}
Script (at bottom of page)
<script>
$('.toggle').click(function () {
if ($(this).hasClass('hidden')) {
$(this).next('div').show();
$(this).text('Hide');
} else {
$(this).text('Show');
$(this).next('div').hide();
}
$(this).toggleClass('hidden');
});
</script>
</body>
Side note: Using RenderAction to render the contents of the hidden div suggest the contents are large and/or you calling a service/database to get the contents. If that's the case you should be loading the contents on demand using ajax (unless your expecting the users to view the details of all rows)
On in my production env. I keep getting this error:
ActionView::Template::Error: undefined method `protocol' for nil:NilClass
I can't figure out where this error are in my template, can anybody help me figure this out?
CODE UPDATE
Complete code: Pastebin
I cut out, the area I think might cause problem:
<tr>
<td class="eHeader" style="">
<table width="100%" border="0" cellpadding="0" cellspacing="0" style="">
<tr>
<td class="eHeader" style="">
<table width="100%" border="0" cellpadding="0" cellspacing="0" style="">
<tr>
<td class="eHeaderLogo" style="">
<a href="#" style="">
<img class="imageFix" src="<%= image_url('crewnetlogo-white.png') %>" width="200" height="48" alt="Crewnet" style="">
</a>
</td>
<!-- end .eHeaderLogo-->
<td class="eHeaderOptions" style="">
</td>
<!-- end .eHeaderOptions-->
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
<tr>
<td>
<h1>
<span>
Du er blevet tildelt <%= #workplace.name %>
</span>
</h1>
<div class="bannerLink">
<a href="#" style="">
<img src="<%= image_url "app.png" %>" alt="Crewnet" width="512" height="194" style="">
</a>
</div>
</td>
<!-- end .highlight-->
</tr>
<tr>
<td class="eBody bottomLine" style="">
<table width="100%" border="0" cellpadding="0" cellspacing="0" class="entryBox" style="">
<tr>
<td class="width132 pdBt16" style="">
<a href="#" style="">
<img src="<%= image_url "file_icon.gif" %>" width="116" height="116" alt="File" style="">
</a>
</td>
<td class="alignLeft" style="">
<p style="">
Hej <%= #user.name %>!<br>
Du har fået tildelt <%= #workplace.name %> som ansvarsområde. <br>
For mere info log på CrewNet | <%= #workplace.name %>.
</p>
<p style="">
Skulle du have nogle spørgsmål, kan du kontakte supporten på support#crewnet.dk.
<br>
<br>
Teamet bag CrewNet.dk
</p>
</td>
</tr>
</table>
</td>
<!-- end .eBody-->
</tr>
Mailer
class SupervisorMailer < ActionMailer::Base
default from: "support#crewnet.dk"
def assigned(user, workplace)
#user = User.find(user)
#workplace = Workplace.find(workplace)
mail to: #user.email, subject: "Du er ansvarlig for #{#workplace.name}."
end
end
production.rb
config.action_mailer.default_url_options = { :host => Rails.application.secrets.domain_name, :protocol => "http" }
config.action_mailer.asset_host = Rails.application.secrets.domain_name
env
secrets.domain_name = crewnet.dk
Probably it's realted to url building. Do you have asset_host setting in your production.rb? Maybe you have to add protocol to asset_host?
Rails.application.configure do
...
config.action_mailer.asset_host = 'http://example.com'
...
end
I have a show page /invoices/show that displays contents of my Invoice
<p id="notice"><%= notice %></p>
<div class="row">
<div class="span7">
<h2 style="text-align:center;"> CONSTRUCTION LTD </h2>
<h3 style="text-align:center;">OHIO</h3>
<address style="text-align:center;"> Plot 10<br/>
</address>
<h3 style="text-decoration:underline; text-align:center;"> UTILITY BILL </h3>
<h4 style="text-decoration:underline; text-align:center;"> TAX INVOICE </h4>
<table>
<td valign="top" align="left">
<div style="float:left; width:450px;">No: <%= #invoice.id %></div>
<div style="float:right"> Date: <%= #invoice.invoice_date %></div>
</td>
</table>
<P></P>
<P></P>
<div>To: <%= #invoice.customer.name%></div>
<p></p>
<table class="table table-bordered table-condensed">
<thead>
<tr class="success">
<th><label class="control-label">Description</label></th>
<th><label class="control-label">Rate</label></th>
<th><label class="control-label">Tax</label></th>
<th><label class="control-label">Amount</label></th>
</tr>
</thead>
<tbody>
<% #invoice.invoice_items.each do | item| %>
<tr class="controls">
<td><%= item.description %></td>
<td><%= item.rate %></td>
<td><%= item.tax_amount %></td>
<td><%= item.amount %></td>
</tr>
<tr>
<td colspan="3" align="left"><strong>TOTAL:</strong></td>
<td colspan="1"><%= item.amount %></td>
</tr>
<% end %>
</tbody>
</table>
<div class="row">
<div class="span3">
<table>
<tbody>
<tr>
<td> <b>For Landlord</b></td></tr>
<tr> <td>Approved by:</td></tr>
<tr> <td>Sign:</td></tr>
</tbody>
</table>
</div>
<div class="span3" style="position: relative; align:left; left:150px;">
<table>
<tbody>
<tr>
<td> <b>For Tenant</b></td></tr>
<tr> <td>Approved by:</td></tr>
<tr> <td>Sign:</td></tr>
</tbody>
</table>
</div>
</div>
<br/>
<br />
<div>
<small><strong>Terms and Conditions</strong></small>
<table>
<tbody>
<tr>
<td><%= Settings.invoice_terms%></td>
</tr>
</tbody>
</table>
</div>
<br />
<div class="form actions">
<p>
<%= link_to t('.edit', :default => t("helpers.links.edit")),
edit_invoice_path, :class => 'btn btn-primary' %>
</p>
</div>
</div>
</div>
In my application.html.erb, I have this for CSS
<%= stylesheet_link_tag "application", :media => "all" %>
More to that, my application file has a nav-bar element.
I am trying to print the Invoices/show.html.erb page by going to the print option in a browser, however, I do not want it to include the nav-bar element in my application.html.erb file and the edit button in invoices/show.html.
I am using Twitter bootstrap, how can i go about this?
Here's one solution I've thought of:
What you can do is, in your show view (or the application layout) add a predicate:
if params[:controller] == "invoice" && params[:action] == "show"
# do or show whatever you want
end
Or you could do add a different layout to your views/layouts folder. Then in your controllers/invoice_controller
def show
# ...
render layout: 'a_different_layout_for_invoices'
end
This snippet is from my admin. I have a description field next to an image, and a demo of how'd that look below it.
Right now it works after a page refresh but i'd like it to work asynchronously using AJAX, so as the user types it updates the demo below the textarea.
#This is where you update the field
<tr><th>Description</th><td><%= f.text_area(:description) %></td></tr>
<tr><th>Demo</th>
<td>
<% if #org.images.present? %>
<table border="0">
<tr>
<td>
<%= featured_image_tag(#org, :type => 'organization') %>
</td>
<td style="vertical-align:top;padding-top:5px;padding-left:5px;">
<span class="font-avebook"><%= #org.description %> </span><br>
</td>
</tr>
</table>
<% else %>
You need to assoicate an image first before seeing the demo!
<% end %>
</td>
</tr>
To get the text to appear directly below at the same time as you're writing you need to use a jQuery Keyup event to submit the data. However, submitting the data after each keyup is not the best idea. If you want to get that effect, why don't you just do the whole thing with jQuery without actually saving the data. You can append the contents of the input to the element beside the image after each keyup. I've made a little demo below.
<!DOCTYPE html>
<html>
<head>
<script src="http://code.jquery.com/jquery-latest.js"></script>
</head>
<body>
<input type="text" id="copy_text">
<div id="mirror_paragraph"></div>
<script>
$("#copy_text").keyup(function () {
var txt = $("#copy_text").val();
$("#mirror_paragraph").html(txt);
});
</script>
</body>
</html>
Adapted to your code:
<tr>
<th>Description</th>
<td><%= f.text_area(:description), :id => "copy_text" %></td>
</tr>
<tr>
<th>Demo</th>
<td>
<% if #org.images.present? %>
<table border="0">
<tr>
<td>
<%= featured_image_tag(#org, :type => 'organization') %>
</td>
<td style="vertical-align:top;padding-top:5px;padding-left:5px;">
<span class="font-avebook" id="mirror_paragraph"><%= #org.description %> </span><br>
</td>
</tr>
</table>
<% else %>
You need to assoicate an image first before seeing the demo!
<% end %>
</td>
</tr>
<script>
$("#copy_text").keyup(function () {
var txt = $("#copy_text").val();
$("#mirror_paragraph").html(txt);
});
</script>
I'm using Steve Sanderson's BeginCollectionItem helper with ASP.NET MVC 2 to model bind a collection if items.
That works fine, as long as the Model of the collection items does not contain another collection.
I have a model like this:
-Product
--Variants
---IncludedAttributes
Whenever I render and model bind the Variants collection, it works jusst fine. But with the IncludedAttributes collection, I cannot use the BeginCollectionItem helper because the id and names value won't honor the id and names value that was produced for it's parent Variant:
<div class="variant">
<input type="hidden" value="bbd4fdd4-fa22-49f9-8a5e-3ff7e2942126" autocomplete="off" name="Variants.index">
<input type="hidden" value="0" name="Variants[bbd4fdd4-fa22-49f9-8a5e-3ff7e2942126].SlotAmount" id="Variants_bbd4fdd4-fa22-49f9-8a5e-3ff7e2942126__SlotAmount">
<table class="included-attributes">
<input type="hidden" value="0" name="Variants.IncludedAttributes[c5989db5-b1e1-485b-b09d-a9e50dd1d2cb].Id" id="Variants_IncludedAttributes_c5989db5-b1e1-485b-b09d-a9e50dd1d2cb__Id" class="attribute-id">
<tr>
<td>
<input type="hidden" value="0" name="Variants.IncludedAttributes[c5989db5-b1e1-485b-b09d-a9e50dd1d2cb].Id" id="Variants_IncludedAttributes_c5989db5-b1e1-485b-b09d-a9e50dd1d2cb__Id" class="attribute-id">
</td>
</tr>
</table>
</div>
If you look at the name of the first hidden field inside the table, it is Variants.IncludedAttributes - where it should have been Variants[bbd4fdd4-fa22-49f9-8a5e-3ff7e2942126].IncludedAttributes[...]...
That is because when I call BeginCollectionItem the second time (On the IncludedAttributes collection) there's given no information about the item index value of it's parent Variant.
My code for rendering a Variant looks like this:
<div class="product-variant round-content-box grid_6" data-id="<%: Model.AttributeType.Id %>">
<h2><%: Model.AttributeType.AttributeTypeName %></h2>
<div class="box-content">
<% using (Html.BeginCollectionItem("Variants")) { %>
<div class="slot-amount">
<label class="inline" for="slotAmountSelectList"><%: Text.amountOfThisVariant %>:</label>
<select id="slotAmountSelectList"><option value="1">1</option><option value="2">2</option></select>
</div>
<div class="add-values">
<label class="inline" for="txtProductAttributeSearch"><%: Text.addVariantItems %>:</label>
<input type="text" id="txtProductAttributeSearch" class="product-attribute-search" /><span><%: Text.or %> <a class="select-from-list-link" href="#select-from-list" data-id="<%: Model.AttributeType.Id %>"><%: Text.selectFromList.ToLowerInvariant() %></a></span>
<div class="clear"></div>
</div>
<%: Html.HiddenFor(m=>m.SlotAmount) %>
<div class="included-attributes">
<table>
<thead>
<tr>
<th><%: Text.name %></th>
<th style="width: 80px;"><%: Text.price %></th>
<th><%: Text.shipping %></th>
<th style="width: 90px;"><%: Text.image %></th>
</tr>
</thead>
<tbody>
<% for (int i = 0; i < Model.IncludedAttributes.Count; i++) { %>
<tr><%: Html.EditorFor(m => m.IncludedAttributes[i]) %></tr>
<% } %>
</tbody>
</table>
</div>
<% } %>
</div>
</div>
And the code for rendering an IncludedAttribute:
<% using (Html.BeginCollectionItem("Variants.IncludedAttributes")) { %>
<td>
<%: Model.AttributeName %>
<%: Html.HiddenFor(m => m.Id, new { #class = "attribute-id" })%>
<%: Html.HiddenFor(m => m.ProductAttributeTypeId) %>
</td>
<td><%: Model.Price.ToCurrencyString() %></td>
<td><%: Html.DropDownListFor(m => m.RequiredShippingTypeId, AppData.GetShippingTypesSelectListItems(Model.RequiredShippingTypeId)) %></td>
<td><%: Model.ImageId %></td>
<% } %>
As you are using MVC 2 and EditorFor, you shouldn't need to use Steve's solution, which I believe is just a work around for MVC 1. You should just be able to do something like:
<% for (int i = 0; i < Model.Variants.Count; i++) { %>
<%= Html.DisplayFor(m => m.Variants[i].AttributeType.AttributeTypeName) %>
<% for (int j = 0; j < Model.Variants[i].IncludedAttributes.Count; j++) { %>
<%= Html.EditorFor(m => m.Variants[i].IncludedAttributes[j]) %>
<% } %>
<% } %>
Please note that the use of the indexes ...[i]...[j]... is important and is how MVC will know how to render the Id's and names correctly.