View rails record details in bootstrap modal on row click - ruby-on-rails

I have been stuck on this problem for quite some time now and looked through several posts as well, however I cannot achieve exactly what I want for my Rails application. Essentially, I want to be able to click on a table row on my page and have a modal pop up which displays all the information for that specific record. Here are the scenarios which I have thought of/attempted partially:
Set the data-link attribute in table row with some JS as follows
HTML:
<tr data-link="<%= kid_path %>">
...
</tr>
JS:
$("tr[data-link]").dblclick(function() {
window.location = $(this).data("link")
})
This worked fine to open the show path page generated by the scaffold, but I was not able to modify it to work with a modal and have the same data for the kid in the modal.
Use data-id and JavaScript to load onto the modal
HTML:
<tr data-id="<%= kid.id %>">
...
</tr>
JS:
$(function () {
$('#showModal').modal({
keyboard: true,
backdrop: "static",
show: false,
}).on('show', function () {
});
$(".table-striped").find('tr[data-id]').on('click', function () {
debugger;
$('#showDetails').html($('<p>' + 'Kid ID: ' + $(this).data('id') + '<%= Kid.find(30).first_name %>' + '</p>'));
$('#showModal').modal('show');
});
});
In this approach I am able to load the modal on row click and am able to access the Kid ID, however I cannot move further to access other attributes of the record. For example, I want to set #Kid = kid.find(id) using JS where id would be the extracted ID from the row. And then, I want to be able to write the generic modal template which displays other elements (ex. kid.first_name, kid.last_name, etc).
I am totally stuck and cannot find any approach that helps to accomplish my goal. Any help is appreciated, thank you.

You need to ajax call record attributes because the line Kid.find(30).first_name doesn't exist at the time page loaded.
Try this:
KidsController
def show
kid = Kid.find(params[:id])
respond_to do |format|
format.html { // Usually show.html.erb }
format.json do
# Return kid as json object
result = {
first_name: kid.first_name,
last_name: kid.last_name
}
# If you want to return the whole kid record attributes in json: result = kid.attributes.to_json
render json: result
end
end
end
Try /kid/[:id].json to verify that you are not getting UnknownFormat error.
JS
$(".table-striped").find('tr[data-id]').on('click', function () {
var kid_id = $(this).data('id');
$.getJSON("/kid/" + kid_id, function(data) {
// Render the modal body here
// first_name = data.first_name, last_name = data.last_name etc
$('#showDetails').html($('<p>'+ data.first_name + '</p>'));
$('#showModal').modal('show');
});
})
If you have setup correct route for Kid model then these are what you needed.
UPDATED: I made a typo in the result hash. FIXED

Related

Value not bind to the view from controller

I have two select tags as follow
<%= f.select(:floor_id, ProjectFloor.find(:all,:order => "name ASC",:conditions => ["project_id = ?", #project.id]).collect{|b|[b.name, b.id]}, {:include_blank => 'Select'}) %>
<%= f.select(:unit_id, #floor.collect{|b|[b.name, b.id]}, {:include_blank => 'Select'}) %>
When the user select the value on the first select tag called :floor_id then the value of the select tag data should be load to :unit_id select tag
I have try the following to read and fetch the data but. the floor_id always receiving null
My controller method is as follow :
#floor_id = params[:floor_id]
#project = Project.find(params[:project_id])
#proposed_customer = ProposedCustomer.new
#floor = ProjectFloorUnit.select_units(#project.id, #floor_id)
The select unit method is work fine for static values so it must work if we pass the proper param.
When a page is completely loaded, it disconnects from the server. So, you need to initiate a separate request, and the response of the request will change the values or whatever you want in the second dropdown.
You can use jQuery to send a new request:
$("#floorIDSelectTag").change(function() {
var floorID = $(this).val();
$.ajax({
type: '',
url: '',
// other things
success: function(data) {
// Here, you need to use the data from the request's response,
// and update the things in 2nd dropdown
}
});
});
What will be the URL that you will use in AJAX call? For it, you need to build a new route in config/routes.rb file, a new action in your controller, and send back the data in JSON format. Something like following:
def get_data_for_floor_id
#floor_id = params[:floor_id]
# Do the other stuff, and prepare the response you need to send.
respond_to do |format|
format.json { }
end
end

Should Backbone collection 'create' add new model to collection with id from server included?

In my Backbone view here, I want to be able to immediately add my model to my collection with an 'id' attribute included in the newly created model. In other words, I need to have access to this 'id' right away. With the id available, my removeCategory method can work. To "solve" that problem, I tried to add the line this.collection.fetch() directly below this.collection.add(model);, but it gave me very bad UI (the new <li> wouldn't even render, etc), plus it seems like very bad coding practice anyway.
I'm relatively new with Backbone, so I'm not sure if create (save/add) should automatically add the model to the collection with an id or not. If it should, then there must be something wrong with the JSON data I'm receiving from my Rails RESTful API. If create does NOT do that, then how can I instantly get access to this specific newly created model, with an id (other than by refreshing the browser -- ugh!)? I need the id for <li data-id={{id}}></li> in my Handlebars template as soon as I invoke the "addCategory" method.
Also (& this might be a related problem), when I do model.fetch();, I get back the model's entire collection, plus that newly-created server-side model without an id. Any help on this would be much appreciated.
window.CategoriesView = Backbone.View.extend({
index_template: HandlebarsTemplates['categories/index'],
events: {
'click .delete': 'removeCategory',
'click .category_add': 'addCategory'
},
initialize: function() {
_.bindAll(this, 'render');
this.collection.fetch();
this.listenTo(this.collection, 'all', this.render);
},
show: function() {
$("#categorymodal").modal();
},
addCategory: function(e) {
e.preventDefault();
// I wrote the next three lines here explicitly rather than using 'create'
var model = new Category({ name: $(this.el).find('.category_name').val() });
model.save();
this.collection.add(model);
this.show();
},
removeCategory: function(e) {
e.preventDefault();
var id = $(e.target).parents('li').data('id');
var model = this.collection.where({ id: id })[0];
this.collection.remove(model);
if (model) { model.destroy(); }
this.render();
},
render: function() {
$(this.el).html(this.index_template());
this.collection.models.forEach(function(cat) {
var li_template = HandlebarsTemplates['categories/show']
$(this.el).find('.categories').append(li_template({
id: cat.toJSON().id,
name: cat.toJSON().name
}));
}, this);
return this;
}
});
Here is my #create action in Rails....
def create
#category = Category.create(category_params)
render :nothing => true
end
I am using jbuilder to provide the JSON from the Rails API.
Here is my Backbone model and collection...
window.Category = Backbone.Model.extend({
urlRoot: "categories"
});
window.Categories = Backbone.Collection.extend({
model: Category,
url : function() {
return 'categories';
}
});
I figured out my problem. It was in my Rails controller, not with Backbone create. I changed my #create action from this...
def create
#category = Category.create(category_params)
render :nothing => true
end
...to this....
def create
#category = Category.create(category_params)
redirect_to category_path(#category)
end
...with my show action being this...
def show
#category = Category.find(params[:id])
end
...that provided me with http://localhost:3000/categories/752.json. I've gotta make sure my backend is providing what I need JSON-wise!

How to pass value through link in controller function

How to pass value through link in controller function.
I want to pass below rc value in link so that routes collect it and send to controller.I am new bies in rails.Anyone please help me to solve the problem.
my html.erb .which collect value from text box through jQuery function.
<script type="text/javascript">
var rc=jQuery("#commonid").val();
</script>
<div ><%=link_to "Alert By Region",alerts/filter_alert %></div>
my routes.rb
file which match the link and send to controller
match 'alerts/filter_alert', :controller => 'alerts', :action => 'filter_alert'
my controller
def filter_alert(x)
#message=x
#title = #title + ' - Alerts'
render :site_alerts
end
Javascript things belong to Javascript. You need to manipulate this value dynamically upon visitor's clicking this link.
In Rails' controller side, you can't hard code the method. You need to use params from query string because you won't know what the input is.
# Views
link_to 'Alert By Region', 'alerts/filter_alert', id: 'alert-link'
# Javascript
$('#alert-link').on('click', function() {
var rc = $("#commonid").val();
if rc {
this.attr['href'] += '?rc='+ encodeURI(rc);
return true;
} else {
alert 'input is blank!';
return false;
}
});
# Controller
def filter_alert
rc = params[:rc]
# Then process based on this
end

Update progress bar in rails using jQuery

I'm a complete novice in JavaScript/jQuery and I believe it's a very simple question; however I'm not being able to accomplish it.
I have an asynchronous task being performed (by sidekiq) and it's progress is available by a method from the model (percentage_complete) that retrieves its progress from Redis.
I want to display a progress bar in model's show view, and I want it to update every x seconds using AJAX.
The progress bar is being displayed like this on the show.html.erb file:
<div class="progress">
<div class="bar" style="width: <%= #model.percentage_complete %>%;"></div>
</div>
How can I set a jQuery script to update this attribute asynchronously?
EDIT
I also have a a :status attribute which is set do "done" when the task is complete. I would like to stop updating when that happens.
By reading my question it appears that I haven't tried nothing and just want someone to write the code for me. Let me add some comments:
I know I should use setInterval to update the attribute every "x" seconds
I know I should use $('.progress .bar').width(<%= #model.percentage_complete %>%) to set the new percentage
However, since I'm not familiar to jQuery and JavaScript, specially in Rails, I'm not sure if this script should be loaded in a view, or if it should be a view itself.
I solved it by creating an action to retrieve the status
# GET /status/1.json
def status
#batch = Batch.find(params[:id])
respond_to do |format|
format.json
end
end
and using the following JavaScript:
<script type="text/javascript">
function progress(){
var progress = setInterval(function() {
var $bar = $('.bar');
var $pct = $('#pct');
$.get("<%= #batch.id %>/status.json", function(data){
if (data.status == "done") {
location.reload();
} else {
$bar.width(data.progress+"%");
$pct.text(data.progress+"%");
}
});
}, 800);
}
$(document).ready(function() {
$.get("<%= #batch.id %>/status.json", function(data) {
if (data.status == "processing") {
progress();
}
});
});
</script>

Auto refresh <div> without reload entire page

I'm trying to update the content of "mydiv" without refreshing the entire index page.
#mydata is given by mycontroller. I need to recalculate it every n seconds and pass it to "mydiv"
With "link_to" it works!
index.html.erb
<%=
link_to('refresh', '/mycontroller/index', :remote => true)
%>
<div id="mydiv">
<%=
#mydata
%>
</div>
index.js.erb
$('#mydiv').html('<%= escape_javascript(#mydata) %>')
Now I need to refresh the content of "mydiv" automatically every n seconds (so without click on the link). I have tried solutions from:
First Link
Second Link
but no luck.
In my application.js I have writed this:
function executeQuery() {
$.ajax({
//url: '/index',
success: function(data) {
$('#mydiv').html(data)
}
});
setTimeout(executeQuery, 500);
}
$(document).ready(function() {
setTimeout(executeQuery, 500);
});
For who is facing my same problem, I solved it by replacing
$('#mydiv').html(data)
with
$('#mydiv').load('/mycontroller/index #mydiv')
Use setInterval() instead of using setTimeout().
Ref: https://www.w3schools.com/jsref/met_win_setinterval.asp
function executeQuery() {
$.ajax({
type: 'GET',
url: 'example.com/url/', // Provide your response URL here.
success: function(data) {
$('#mydiv').html(data);
}
});
}
setInterval(executeQuery(), (n * 1000)); // Replace 'n' with how many seconds you want.
This code will run the executeQuery() method in every 'n' seconds interval. So that your requirement is accomplished.
Set layout to false in the action and just pass on the relevent content, not the entire page
def action1
<your code here>
end
def action2
<your code here>
render :layout => false
end
Your view for action2 should have content pertaining only to #mydiv.
A better solution would be to use a single action and change render options based on type of request. (Ajax or non ajax)

Resources