I want to create a "details" row dynamically like below:
I'd like to be able to toggle details for every item on the grid. Can you advise how I can achieve this functionality?
I'm using rails 4 with wice_grid gem
I found out how to do this:
VIEW:
<%= grid(#items_grid) do |g|
g.after_row do |fill, number_of_columns|
content_tag(:tr, class: 'extra-row') do
content_tag(:td,
content_tag(:div) do
# without buffer only the last tag will appear
buffer = content_tag(:p,"data1: #{item.add_data1}")
buffer += content_tag(:p,"data2: #{item.add_data2}")
raw buffer
end,
colspan: number_of_columns)
end
g.column name: "ID", attribute: 'id' do |item|
item.id
end
g.column name: "Data", attribute: 'data' do |item|
item.data
end
g.column do |item|
button_tag("Details", class: "btn btn-default toggle-trigger")
end
end -%>
.JS:
$(document).on("page:load ready", function(){
$(".toggle-trigger").click(function(){
$(this).parents('tr').next('.extra-row').slideToggle("fast");
return false;
});
});
.CSS:
.extra-row {
display: none;
}
Related
I am trying out Reason-React. I am facing a problem when I try to add a key to one of the components.
I have a TodoApp that takes a list of TodoItem as state. The app works fine when I don't have a key for the TodoItem. When I add it, however I am getting a compilation error. I am adding the files here for reference:
TodoItem.re:
type item = {
id: int,
title: string,
completed: bool
};
let lastId = ref(0);
let newItem = () => {
lastId := lastId^ + 1;
{id: lastId^, title: "Click a button", completed: false}
};
let toString = ReasonReact.stringToElement;
let component = ReasonReact.statelessComponent("TodoItem");
let make = (~item, children) => {
...component,
render: (self) =>
<div className="item">
<input _type="checkbox" checked=(Js.Boolean.to_js_boolean(item.completed)) />
(toString(item.title))
</div>
};
TodoApp.re:
let toString = ReasonReact.stringToElement;
type state = {items: list(TodoItem.item)};
type action =
| AddItem;
let component = ReasonReact.reducerComponent("TodoApp");
let currentItems = [TodoItem.{id: 0, title: "ToDo", completed: false}];
let make = (children) => {
...component,
initialState: () => {items: currentItems},
reducer: (action, {items}) =>
switch action {
| AddItem => ReasonReact.Update({items: [TodoItem.newItem(), ...items]})
},
render: ({state: {items}, reduce}) => {
let numOfItems = List.length(items);
<div className="app">
<div className="title">
(toString("What to do"))
<button onClick=(reduce((_evt) => AddItem))> (toString("Add Something")) </button>
</div>
<div className="items">
(
ReasonReact.arrayToElement(
Array.of_list(
(List.map((item) => <TodoItem key=(string_of_int(item.id)) item />, items))
/*List.map((item) => <TodoItem item />, items) This works but the above line of code with the key does not*/
)
)
)
</div>
<div className="footer"> (toString(string_of_int(numOfItems) ++ " items")) </div>
</div>
}
};
I've added a comment near the line where the error occurs.
The error reads as Unbound record field id, but I am not able to figure out how it is not bound. What am I missing here?
Type inference is unfortunately a bit limited when it comes to inferring the type of a record from another module based on the usage of record fields, so you need to give it some help. Two options that should work are:
Annotating the type of ìtem:
List.map((item: TodoItem.item) => <TodoItem key=(string_of_int(item.id)) item />)
or locally opening the module where the record field is used:
List.map((item) => <TodoItem key=(string_of_int(item.TodoItem.id)) item />)
I am using rails and algolia gem with mongoid datastore.
I am sending data to algolia for a model Question. One of the doc example in Algolia system is
objectID: 5691e056410213a381000000
text: "what is #cool about your name Mr. John? #name #cool"
asked_to: ["565571704102139759000000", "i7683yiq7r8998778346q686", "kjgusa67g87y8e7qtwe87qwe898989"]
asked_by: "564a9b804102132465000000"
created_at: "2016-01-10T04:38:46.201Z"
card_url: "http://localhost:3000/cards/5691e056410213a381000000"
answerers: []
has_answer: false
requestor_count: 0
status: "active"
popularity_point: 0
created_at_i: 1452400726
_tags: ["cool", "name"]
I want to find all those documents, where it meets these two conditions:
1) text contains your name
2) asked_to contains i7683yiq7r8998778346q686
I am using Twitter's typeahead javascript library. And my UI's javascript to implement algolia search is as follows:
<input class="typeahead ui-widget form-control input-md search-box tt-input" id="typeahead-algolia" placeholder="Search questions" spellcheck="false" type="text" autocomplete="off" dir="auto" style="position: relative; vertical-align: top;">
$(document).on('ready page:load', function () {
var client = algoliasearch("APPLICATION_ID", "SEARCH_KEY");
var index = client.initIndex('Question');
$('#typeahead-algolia').typeahead(
{
hint: false,
highlight: true,
minLength: 1
},
{
source: index.ttAdapter({hitsPerPage: 10}),
displayKey: 'text'
}
).on('keyup', this, function (event) {
if (event.keyCode == 13) {
$('#typeahead-algolia').typeahead('close');
window.location.href = "/?keyword="+encodeURIComponent($('#typeahead-algolia').val());
}
});
$('.typeahead').bind('typeahead:select', function(ev, suggestion) {
window.location.href = suggestion.card_url;
});
});
So my question is:
This code works perfectly. But how to add condition for asked_to contains i7683yiq7r8998778346q686 in above javascript to filter out result.
You can use a facet filter on the asked_to attribute in your query.
You first need to declare the attribute asked_to as an attribute for faceting in your index settings and then pass asked_to:i7683yiq7r8998778346q686 as a facet filter in your query via the facetFiltersquery parameter.
When your index settings are changed, you can change your source to add the facetFilters parameter:
$('#typeahead-algolia').typeahead(
{
hint: false,
highlight: true,
minLength: 1
},
{
source: index.ttAdapter({hitsPerPage: 10, facetFilters: "asked_to:i7683yiq7r8998778346q686"}),
displayKey: 'text'
}
).on('keyup', this, function (event) {
if (event.keyCode == 13) {
$('#typeahead-algolia').typeahead('close');
window.location.href = "/?keyword="+encodeURIComponent($('#typeahead-algolia').val());
}
});
gmaps4rails 2 + rails 4 + ruby 2.0
<script>
handler = Gmaps.build('Google');
handler.buildMap({ provider: {}, internal: {id: 'map'}}, function(){
markers = handler.addMarkers(<%= raw #geo_hash.to_json %>);
});
handler.map.centerOn({ lat: <%= raw #geo_city[0][:lat] %>, lng: <%=raw #geo_city[0][:lng] %> })
handler.getMap().setZoom(7)
</script>
#geo_hash = [{:lat=>16.9916,
:lng=>81.7838,
:infowindow=>"railway station",
:picture=>{:url=>"/assets/web/blank_red.png", :width=>32, :height=>32},
:title=>"abc temple"}
]
#geo_city = [{:lat=>15.8273,
:lng=>78.047,
:infowindow=>"Bus stand",
:picture=>{:picture=>"/assets/web/**blank.png", :width=>32, :height=>32},
:title=>"A.S. Peta"}]
I want two different marker on Google map but only one marker is coming ? any suggestion ?
I got the solution...
<script>
handler = Gmaps.build('Google');
handler.buildMap({ provider: {}, internal: {id: 'map'}}, function(){
markers1 = handler.addMarkers(<%= raw #geo_hash.to_json %>);
markers2 = handler.addMarkers(<%= raw #geo_city.to_json %>);
});
handler.map.centerOn({ lat: <%= raw #geo_city[0][:lat] %>, lng: <%=raw #geo_city[0][:lng] %> })
handler.getMap().setZoom(7)
</script>
Thanks.
I have a model Declaration which has many Costs:
class Declaration < ActiveRecord::Base
has_many :costs
accepts_nested_attributes_for :costs
end
class Cost < ActiveRecord::Base
belongs_to :declaration
end
I want a form where I have 10 cost lines for a declaration, so in the Declaration controller I have the follwing, with the permit params for strong parameters:
def new
#declaration = Declaration.new
#costs = Array.new(10) { #declaration.costs.build }
end
def create
#declaration = Declaration.new(declaration_params)
if #declaration.save
redirect_to user_declarations_path, notice: I18n.t('.declaration.message_create')
else
render action: "new"
end
end
private
def declaration_params
params.require(:declaration).permit(:approval_date, :submit_date, :status, :user_id, :declaration_number,
costs_attributes: [:id, :description, :amount_foreign, :rate, :amount, :cost_date, :projectuser_id])
end
And there is the form of course, so when I submit the form I see this in the log:
Started POST "/users/3/declarations" for 127.0.0.1 at 2013-09-05 19:12:38 +0200
Processing by DeclarationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"mhaznOuBy/zj7LA/nIpDTy7X2u5UrR+0jleJsFid/JU=", "declaration"=>{"user_id"=>"3", "cost"=>{"cost_date(3i)"=>"", "cost_date(2i)"=>"", "cost_date(1i)"=>"", "projectuser_id"=>"", "description"=>"", "amount_foreign"=>"", "rate"=>"", "amount"=>""}}, "commit"=>"Opslaan", "user_id"=>"3"}
User Load (0.7ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 ORDER BY "users"."id" ASC LIMIT 1
Unpermitted parameters: cost
So why do I get an unpermitted parameter cost??
Update: declaration form added below:
- if can? :create, Declaration
= form_for [current_user, #declaration] do |f|
= f.hidden_field :user_id, value: current_user.id
.row
.page-header
.span7
%h1.title
%i{ class: "icon-coffee icon-large" }
= I18n.t('.declaration.add_title')
.span5
.action
- if can? :create, Declaration
= link_to I18n.t('.general.cancel'), user_declarations_path(current_user), class: 'btn'
= f.submit(class: 'btn', value: I18n.t('.general.save'))
.row
.span12
= render "layouts/error_messages", target: #declaration
.row
.span12
= render "form", f: f
And the rendered form:
.row
.span12
%table.table.table-striped#declarations
%thead
%tr
%th= I18n.t('.cost.cost_date')
%th= I18n.t('.cost.project')
%th= I18n.t('.cost.description')
%th= I18n.t('.cost.amount_foreign')
%th= I18n.t('.cost.rate')
%th= I18n.t('.cost.amount')
%tbody
- #costs.each do |cost|
= f.fields_for cost, html: { class: "form-inline"} do |c|
%tr
%td{ "data-title" => "#{I18n.t('.cost.cost_date')}" }= c.date_select :cost_date, { include_blank: true, default: nil }
%td{ "data-title" => "#{I18n.t('.cost.project')}" }= c.collection_select :projectuser_id, #projectusers, :id, :full_name, include_blank: true
%td{ "data-title" => "#{I18n.t('.cost.description')}" }= c.text_field :description, class: "input-large"
%td{ "data-title" => "#{I18n.t('.cost.amount_foreign')}" }= c.text_field :amount_foreign, class: "input-small", type: :number, step: "any"
%td{ "data-title" => "#{I18n.t('.cost.rate')}" }= c.text_field :rate, class: "input-small", type: :number, step: "any"
%td{ "data-title" => "#{I18n.t('.cost.amount')}" }= c.text_field :amount, class: "input-small", type: :number, step: "any"
With permit! I get this error message:
Started POST "/users/3/declarations" for 127.0.0.1 at 2013-09-09 09:29:44 +0200
Processing by DeclarationsController#create as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"jQwy7psQwixneWF8DezrR/Wo5VKU/dpfz+sosiatm9c=", "declaration"=>{"user_id"=>"3", "cost"=>{"cost_date(3i)"=>"", "cost_date(2i)"=>"", "cost_date(1i)"=>"", "projectuser_id"=>"", "description"=>"", "amount_foreign"=>"", "rate"=>"", "amount"=>""}}, "commit"=>"Opslaan", "user_id"=>"3"}
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."id" = 3 ORDER BY "users"."id" ASC LIMIT 1
Completed 500 Internal Server Error in 6ms
ArgumentError - wrong number of arguments (6 for 0):
app/controllers/declarations_controller.rb:70:in `declaration_params'
app/controllers/declarations_controller.rb:21:in `create'
First impression is you are returning three cost_date parameters. I think this needs to be returned as an array. Your params would then be:
def declaration_params
params.require(:declaration).permit(:approval_date, :submit_date, :status, :user_id, :declaration_number,
costs_attributes: [:id, :description, :amount_foreign, :rate, :amount, :projectuser_id, :cost_date =>[]])
end
Then instead of your web server getting back:
... "cost"=>{"cost_date(3i)"=>"", "cost_date(2i)"=>"", "cost_date(1i)"=>"",...
it should get:
"cost"=>{"cost_date"=>["","",""],...
though without seeing the form I don't know if this is what you are trying to achieve.
It seems that changing this:
- #costs.each do |cost|
= f.fields_for cost, html: { class: "form-inline"} do |c|
to this:
= f.fields_for(:costs) do |c|
Does the trick, because now all costs records are being saved. In the controller I have now this:
#declaration = Declaration.new
10.times do |n|
#declaration.costs.build
end
The only issue I have now left is that it saves empty cost records.
I need to retrieve the index position of each value in a list I have. I'm doing this so that I can display a gsp table with alternating row background colors. For example:
(list.indexVal % 2) == 1 ? 'odd' : 'even'
How can I get the index position number of each item in a Groovy list? Thanks!
According the documentation, the g:each tag in the gsp view allows the "status" variable
where grails store the iteration index in.
Example:
<tbody>
<g:each status="i" in="${itemList}" var="item">
<!-- Alternate CSS classes for the rows. -->
<tr class="${ (i % 2) == 0 ? 'a' : 'b'}">
<td>${item.id?.encodeAsHTML()}</td>
<td>${item.parentId?.encodeAsHTML()}</td>
<td>${item.type?.encodeAsHTML()}</td>
<td>${item.status?.encodeAsHTML()}</td>
</tr>
</g:each>
</tbody>
Any of g:each, eachWithIndex, or for loops can be used.
But, for this specific case, the index value is not needed. Using css pseudo-classes is recommended:
tr:nth-child(odd) { background: #f7f7f7; }
tr:nth-child(even) { background: #ffffff; }
If you still need to get the index, options are:
<g:each status="i" in="${items}" var="item">
...
</g:each>
<% items.eachWithIndex { item, i -> %>
...
<% } %>
<% for (int i = 0; i < items.size(); i++) { %>
<% def item = items[i] %>
...
<% } %>