I use Gritter notifications in Rails 5 app and can't find a way to remove default title of the notification popup. I add Gritter as bellow:
<%= js add_gritter(flash[:notice], title: 'I dont need you', sticky: false) %>
Tried:
<%= js add_gritter(flash[:notice], title: false, sticky: false) %>
<%= js add_gritter(flash[:notice], title: nil, sticky: false) %>
<%= js add_gritter(flash[:notice], title: '', sticky: false) %>
<%= js add_gritter(flash[:notice], title: ' ', sticky: false) %>
And still popup appears with the default title - "Notification". Tried to search in the whole app's project "Notification" or "gritter", but nothing related was found.
How to get rid of it?
The add_gritter method in the gem sets the options[:title] as "Notification" if options[:title].blank? returns true.
The "dirty" option is to define it again, with a hash of options instead *args, and to render the title if it was passed as an option argument, like:
def add_gritter(text, options={})
if %w(success warning error notice progress).include?(options[:image].to_s)
options[:image] = image_path("#{options[:image]}#{options[:image].to_s == 'progress' ? '.gif' : '.png'}")
end
notification = Array.new
notification.push("jQuery(function(){") if options[:nodom_wrap].blank?
notification.push("jQuery.gritter.add({")
notification.push("image:'#{options[:image]}',") if options[:image].present?
notification.push("sticky:#{options[:sticky]},") if options[:sticky].present?
notification.push("time:#{options[:time]},") if options[:time].present?
notification.push("class_name:'#{options[:class_name]}',") if options[:class_name].present?
notification.push("before_open:function(e){#{options[:before_open]}},") if options[:before_open].present?
notification.push("after_open:function(e){#{options[:after_open]}},") if options[:after_open].present?
notification.push("before_close:function(e){#{options[:before_close]}},") if options[:before_close].present?
notification.push("after_close:function(e){#{options[:after_close]}},") if options[:after_close].present?
notification.push("on_click:function(e){#{options[:on_click]}},") if options[:on_click].present?
notification.push("title:'#{escape_javascript(options[:title])}',") if options[:title].blank? # Here
notification.push("text:'#{escape_javascript(text)}'")
notification.push("});")
notification.push("});") if options[:nodom_wrap].blank?
text.present? ? notification.join.html_safe : nil
end
But the gritter.js file has an if to check if the title has any content, so you should have to deal with your own and edit it, just to check for the text, like:
//We might have some issues if we don't have a title or text!
if (!params.text) {
throw 'You need to fill out the text parameter.';
}
Doesn't sound like a best way, but works. If any other solutions - please feel free :)
.gritter-title {
display: none;
}
Edit:
Since I use SCSS, this is better:
<%= js add_gritter(flash[:notice], sticky: false, :on_click => remove_gritter, :time => 100000, class_name: 'no-title') %>
.no-title {
.gritter-title {
display: none;
}
}
Related
I am a beginner in Rails, but I have done a lot of searching on this and can't seem to find something to help me since I am having difficulty breaking down the problem. I have built a working method that requests information about a book given the ISBN from Amazon and would now like to use it to autofill information about the book after a user enters in the ISBN into a form. Here is my method (which is in my listing.rb model file):
def self.isbn_lookup(val)
request = Vacuum.new('US')
request.configure(
aws_access_key_id: 'access_key_here',
aws_secret_access_key: 'secret_access_key_here',
associate_tag: 'associate_tag_here'
)
response = request.item_lookup(
query: {
'ItemId' => val,
'SearchIndex' => 'Books',
'IdType' => 'ISBN'
},
persistent: true
)
fr = response.to_h #returns complete hash
author = fr.dig("ItemLookupResponse","Items","Item","ItemAttributes","Author")
title = fr.dig("ItemLookupResponse","Items","Item","ItemAttributes","Title")
manufacturer = fr.dig("ItemLookupResponse","Items","Item","ItemAttributes","Manufacturer")
url = fr.dig("ItemLookupResponse","Items","Item","ItemLinks","ItemLink",6,"URL")
return {title: title, author: author, manufacturer: manufacturer, url: url}
end
Here is my controller for now. I am not sure how to make this generic so that the ISBN number relies on what the user enters (it should take in a value given by the user instead of assuming the #isbn instance variable is always set):
def edit
#isbn = Listing.isbn_lookup(1285741552)
end
Here is my _form.html.erb partial where I want to call this ISBN autofill:
<%= form_for(#listing, :html => {class: "form-horizontal" , role: "form"}, method: :get) do |f| %>
<div class="form-group">
<div class="control-label col-sm-2">
<%= f.label :isbn, "ISBN" %>
</div>
<div class="col-sm-8">
<%= f.text_field :isbn, id: "auto-isbn", class: "form-control" , placeholder: "ISBN (10 or 13 digits)", autofocus: true %>
</div>
</div>
...
<% end %>
Finally, here is my JS for what I think should maybe be the start to the AJAX call:
$(document).ready(function() {
$(document).on('keyup','input#auto-isbn',function() {
$.get(this.action, $(this).serialize(), null, "script");
return false;
});
});
How do I make it so that when users put in an ISBN, my app will call the isbn_lookup method and then return the information gathered?
To begin, I would create a lookup path in your routes.rb file. That would look something like:
resources :listings do
collection do
get :lookup
end
end
Which will give you:
lookup_listings GET /listings/lookup(.:format) listings#lookup
Then create the lookup action in your listings_controller.rb, something like:
class ListingsController < ApplicationController
...
def lookup
#isbn_lookup_result = Listing.isbn_lookup(params[:isbn])
render partial: 'isbn_lookup_result'
end
...
end
Naturally, this requires that you have a _isbn_lookup_result.html.erb file that accesses/uses the values from #isbn_lookup_result.
Then, to call this action from your JS, do something like (full disclosure, I use coffeescript, so my plain JS skills are a little rusty):
$(document).ready(function() {
#TIMEOUT = null
$(document).on('keyup','input#auto-isbn',function() {
clearTimeout(#TIMEOUT)
#TIMEOUT = setTimeout(function(){
var ajaxResponse = $.ajax({
url: "listings/lookup",
type: 'GET',
data: {isbn: $('input#auto-isbn').val()}
});
ajaxResponse.success(function(data){
# do stuff with your data response
# perhaps something like:
$('#isbn-lookup-results-container').html(data)
});
}, 500);
});
});
This bit:
clearTimeout(#TIMEOUT)
#TIMEOUT = setTimeout(function(){
...
}, 500);
creates a 1/2 second delay between when your user stops typing and when the ajax function is called. That way, you're not literally doing a lookup on every keyup, only when the user pauses in their typing.
This bit:
var ajaxResponse = $.ajax({
url: "listings/lookup",
type: 'GET',
data: {isbn: $('input#auto-isbn').val()}
});
is the AJAX call. You can see the new listings/lookup path in use. The data: {isbn: $('input#auto-isbn').val()} bit gives you params[:isbn], which is used in the lookup action.
Then, upon success, you use this bit to do something with your response:
ajaxResponse.success(function(data){
# do stuff with your data response
# perhaps something like:
$('#isbn-lookup-results-container').html(data)
});
In this case, data is the HTML that resulted from the render partial: call, so could load it into a div.
I created a rails (v5) form with multiple select and collection_select elements.
Then I use Select2-rails (v4.0.3) to allow a nice selection looking like tags.
The search-options are pulled by ajax.
It works fine until one presses the submit-button with missing required fields.
Valid field-content has now been deleted from the field.
Let me give some example-code:
controller:
...
def form
if params[:form_request].nil?
#form_request = FormRequest.new
else
#form_request = FormRequest.new(params[:form_request])
end
end
def request_form
#form_request = FormRequest.new(params[:form_request])
if #form_request.valid?
render :summary
else
render :form
end
end
...
form:
...
<%= bootstrap_form_for(#form_request, url: '/form/request_form') do |f| %>
<%= f.select :field, [], {label: 'Field label'} %>
<%= f.submit "Submit form" %>
<% end %>
:field is for sure a writable field in the model (and data is set fine)
coffee-script:
Query ->
$("#form_request_from").select2({
ajax: {
url: func =(params) ->
filter = params.term
return "/data.json?filter=" + filter;
,
dataType: 'json',
processResults: processData
},
theme: 'bootstrap',
placeholder: 'Enter data here'
});
processData = (data) ->
mapdata = $.map(data, func =(obj) ->
obj.id = obj.id;
obj.text = obj.name;
return obj;
);
return { results: mapdata };
I am thinking of a lot of possibilities, but at the end I am not sure where the field-data comes from. It is inside the object, but it isn't written to the resulting HTML in any way.
And even if the id would be written as a selected option,
the select2 script would need to know how to transform that into the string to show the real data.
Any idea how to achieve that the data is still written into a field after a failing validation?
After trying out some things I found out how to do it.
At first I just changed the empty array to be the :field variable,too.
This doesn't work too well because it only remembers the ID of the value that has been entered before and like this the SELECT2-script could not find the value to that key and nothing is shown.
Then I created a new variable inside the controller in which I place the array with name and id:
field_object = ObjectsModel.find(#form_request.field.to_i)
#form_field = []
if !field_object.nil?
#form_field = [[field_object.name, field_object.id]]
end
And in the view I now use this field to show the available options:
<%= bootstrap_form_for(#form_request, url: '/form/request_form') do |f| %>
<%= f.select :field, #form_field, {label: 'Field label'} %>
<%= f.submit "Submit form" %>
<% end %>
This works perfectly fine for me without the need to touch the SELECT2-script.
The possible values are still fetched by AJAX but already filled out fields will persist upon redirect to another action.
Is there an easy way to remove options attributes for the tag or content_tag helper?
<%= content_tag :div, content, {
class: 'content',
style: styles_hash.map{|x| "#{x[0].underscore.dasherize}: #{x[1]}"}.join('; '),
data: {
hyperlink: (hyperlink if hyperlink.present?)
}
} %>
In this example, I'm wondering how to remove the data-hyperlink. Even if I throw a nil or false it stills displays as either data-hyperlink="null" or data-hyperlink="false" respectively. I need it to not display entirely if not present.
I've gotten a solution like this but I'd like to know if there is any better, or inside that data attribute?
<%= content_tag :div, content, {
class: 'content',
style: styles_hash.map{|x| "#{x[0].underscore.dasherize}: #{x[1]}"}.join('; '),
'data-hyperlink' => (hyperlink if hyperlink.present?)
} %>
I have a form with input fields/labels etc. How do I get the error message to show up next to the field? instead of clumped together at the top?
I am using devise, rails 3
I have this at the top of my form:
= form_for(resource, :as => resource_name, :url => registration_path(resource_name)) do |f|
- if resource.errors.any?
#errorExplanation
%h2
= pluralize(resource.errors.count, "error")
prevented this user from being saved:
%ul
- resource.errors.full_messages.each do |msg|
%li
= msg
You can use this
- if #resource.errors[:field_name]
...
Also useful link:
http://guides.rubyonrails.org/active_record_validations.html#working-with-validation-errors
Just create a file in your initializers folder.
config/initializers/inline_errors.rb
Place this code in it:
ActionView::Base.field_error_proc = Proc.new do |html_tag, instance|
unless html_tag =~ /^<label/
%{<div class="has-error">#{html_tag}<span class="help-block">#{instance.error_message.first}</span></div>}.html_safe
else
%{#{html_tag}}.html_safe
end
end
PD: Sorry for my english.
How about this
if you want to put the error message just beneath the text field, you can do like this
.row.spacer20top
.col-sm-6.form-group
= f.label :first_name, "*Your First Name:"
= f.text_field :first_name, :required => true, class: "form-control"
= f.error_message_for(:first_name)
What is error_message_for?
--> Well, this is a beautiful hack to do some cool stuff
# Author Shiva Bhusal
# Aug 2016
# in config/initializers/modify_rails_form_builder.rb
# This will add a new method in the `f` object available in Rails forms
class ActionView::Helpers::FormBuilder
def error_message_for(field_name)
if self.object.errors[field_name].present?
model_name = self.object.class.name.downcase
id_of_element = "error_#{model_name}_#{field_name}"
target_elem_id = "#{model_name}_#{field_name}"
class_name = 'signup-error alert alert-danger'
error_declaration_class = 'has-signup-error'
"<div id=\"#{id_of_element}\" for=\"#{target_elem_id}\" class=\"#{class_name}\">"\
"#{self.object.errors[field_name].join(', ')}"\
"</div>"\
"<!-- Later JavaScript to add class to the parent element -->"\
"<script>"\
"document.onreadystatechange = function(){"\
"$('##{id_of_element}').parent()"\
".addClass('#{error_declaration_class}');"\
"}"\
"</script>".html_safe
end
rescue
nil
end
end
Result
Markup Generated after error
<div id="error_user_first_name" for="user_first_name" class="signup-error alert alert-danger">This field is required.</div>
<script>document.onreadystatechange = function(){$('#error_user_first_name').parent().addClass('has-signup-error');}</script>
Corresponding SCSS
.has-signup-error{
.signup-error{
background: transparent;
color: $brand-danger;
border: none;
}
input, select{
background-color: $bg-danger;
border-color: $brand-danger;
color: $gray-base;
font-weight: 500;
}
&.checkbox{
label{
&:before{
background-color: $bg-danger;
border-color: $brand-danger;
}
}
}
Note: Bootstrap variables used here
and, do not forget to Restart the server now and after any modification to the file in config dir.
You can use error_message_on
http://apidock.com/rails/ActionView/Helpers/ActiveRecordHelper/error_message_on
Update:
form.error_messages was removed from Rails and is now available as a plugin. Please install it with rails plugin install git://github.com/rails/dynamic_form.git.
If anyone is looking for a way how to display error messages for particular field in Rails 6:
a = Post.new
a.save # => false
a.errors.full_messages_for(:title)
["Title can't be blank"]
a.errors.full_messages_for(:title).join(', ')
"Title can't be blank, Title too short"
best_in_place is working well but I'd like to use fontawesome icons for the optional "OK" button, rather than a string. How can I incorporate the '<i class="icon-ok"></i>'.html_safe syntax in the :ok_button hash?
= best_in_place #book, :default_price_amount, :html_attrs => {:class => 'medium_no_dropdown'}, :ok_button => "OK"
This is an old question, and the desired functionality is now supported in the best_in_place gem using the :ok_button_class option. Usage is like this:
<%= best_in_place #post, :title, :ok_button => "Submit", :ok_button_class => "btn post-title" %>
There is a solution , but not exactly to add a style to the ok_button . If you don't mind to use unicode glyphs , you can try :
= best_in_place #book, :default_price_amount, :html_attrs => {:class => 'medium_no_dropdown'}, :ok_button => "✓".html_safe
The table with all the unicode characters could be your reference for another variant .
The problem with the real styling of ok_button is that the hash is accepting data-attribute only for defining of the button . Probably in one of the next versions of BIP this will be improved.
In the source code, where the button is created (best_in_place.js):
if(this.okButton) {
output.append(
jQuery(document.createElement('input'))
.attr('type', 'submit')
.attr('value', this.okButton)
)
}
'value' is what we pass on the hash . If there is a way to make a reference to the glyph-codes , defined by awesome font ( for icon-ok ) , it would be beautiful .
Since I spent couple hours to do the same thing, I found that we can override the prototype of this function to create <button> instead of <input type="button">. However, the activateForm function only wait for click event from input[type="button"] and since I can't override it, so I try another (a bit dirty) way – and it works.
Overwrite this script at another js tag/files
BestInPlaceEditor.prototype.placeButtons = function (output, field){
'use strict'
// the ok button isn't changed
if (field.okButton) {
output.append(
jQuery('<button>').html(field.okButton).attr({
type: 'submit',
class: field.okButtonClass
})
)
}
if (field.cancelButton) {
// create new cancel "<button>"
var $resetBtn = jQuery('<button>').html(field.cancelButton).attr({
type: 'reset',
class: field.cancelButtonClass
}),
// and traditional cancel '<input type="button">', but this should be hidden
$_resetBtn = jQuery('<input>').val(field.cancelButton).css({ display: 'none' })
.attr({
type: 'button',
class: '__real-btn-close-best_in_place'
});
// and bind event to 'trigger' click traditional button when the new <button> is clicked
$resetBtn.bind('click', function (event) {
$(event.currentTarget).parents('form.form_in_place').find('input.__real-btn-close-best_in_place').trigger('click');
event.stopPropagation(); // << also neccessary
});
// append both
output.append($_resetBtn).append($resetBtn);
}
}
}