I have a need where in my application, I need to copy the URL that is rendered to the user. I am using the JS from this JSFiddle.
My code is slightly different from the HTML part of the Fiddle. I use mscConfirm for the JS message box.
My show.js.erb file,
<% if #exists == true %>
mscConfirm("Hold on", 'The file has been shared already, <%= #display %>', function(){
clipboard(this);
});
<% end %>
The function in the above code, is executed on clicking OK to the Message that appears. On doing Ctrl + C to the #display value in the screen, I still get 'undefined' when I try to paste it elsewhere.
My textfield output after pasting,
Any help is appreciated. Thanks in advance.
The provided clipboard() function accepts a DOM element. You will have to modify the function to suit your requirements.
function clipboard(el, txt) {
// deselect all
var selected = document.getElementsByClassName("selected");
for (var i = 0; i < selected.length; i++) {
selected[i].className = '';
};
el.className = 'selected';
clip.setValue(txt);
}
Here, you will have to explicitly pass the text to be copied. In mscConfirm's okCallback, this does not refer to any element.
So according to me, your function call should look like this:
<% if #exists == true %>
mscConfirm("Hold on", 'The file has been shared already, <%= #display %>', function(){
clipboard(document.getElementById("DOMnodeID"), #display);
});
<% end %>
Or you can remove the DOMnode altogether and just pass the text to be copied:
function clipboard(txt) {
// deselect all
var selected = document.getElementsByClassName("selected");
for (var i = 0; i < selected.length; i++) {
selected[i].className = '';
};
clip.setValue(txt);
}
Then your function call should look like this:
<% if #exists == true %>
mscConfirm("Hold on", 'The file has been shared already, <%= #display %>', function(){
clipboard(#display);
});
<% end %>
Related
Not sure if I am asking this question wrong, but I can't seem to find exactly the issue I am faced with.
I have a very basic rails 6 app for a task list. Tasks are either complete or incomplete and the change/update of this is to be done via javascript (the html side works just fine).
Here is my form partial _task.html.erb:
<%= form_with model: task, html: { class: "edit_task", id: "edit_task_#{task.id}" } do |f| %>
<%= f.check_box :complete %>
<%= f.submit "Update" %>
<%= f.label :complete, task.name %>
<%= link_to "(remove)", task, method: :delete, data: {confirm: "Are you sure?"}, remote: true %>
<% end %>
Here is the javascript to submit the form, tasks.js
function submit_update(){
const checkboxes = document.querySelectorAll('.edit_task input[type=checkbox]');
const submitbutton = document.querySelectorAll('.edit_task input[type=submit]');
submitbutton.forEach(button => button.remove());
checkboxes.forEach(checkbox => {
checkbox.addEventListener('click', () => checkbox.parentElement.submit());
});
}
window.addEventListener('turbolinks:load', event => {
submit_update();
document.addEventListener('task_added', event => submit_update());
});
This part works just fine, but once submitted and based on this section of the controller
def update
#task.update!(task_params)
respond_to do |format|
format.html { redirect_to root_url, notice: 'Task successfully updated' }
format.js
end
end
My understanding is together this should launch update.js.erb, which currently looks like
unction update_task() {
const current_task = document.querySelector('#edit_task_<%= #task.id %>');
const complete_tasks = document.querySelector('#complete_tasks');
const incomplete_tasks = document.querySelector('#incomplete_tasks');
<% if #task.complete? %>
complete_tasks.insertAdjacentHTML('beforeend',current_task.innerHTML);
<% else %>
incomplete_tasks.insertAdjacentHTML('beforeend',current_task.innerHTML);
<% end %>
}
update_task();
I have tried changing the above to a single line using an alert call and it still never gets called.
If someone could let me know why update.js.erb is not being called, it would be much appreciated :)
If any additional information is required, please let me know?
EDIT:
On further testing, I have found that if I submit the update via the click of the button, ie remove the submission via javascript, that the update.js.erb is actioned correctly.
So it would seem the focus needs to be on the tasks.js file and how that submits?
What is weird is that when that is included, after the submit the HTML format runs just fine, just not the js format??
After a number of days of trying to get the correct search words I have found the solution and happy to submit for others to find :)
The magic can be found here
The change for my example is as follows --
checkboxes.forEach(checkbox => {
checkbox.addEventListener('click', () => checkbox.parentElement.submit());
});
// becomes
checkboxes.forEach(checkbox => {
checkbox.addEventListener('click', event => {
checkbox.parentElement.dispatchEvent(new Event('submit', {bubbles: true}));
});
});
I have since edited the update.js.erb (does the same thing just a bit cleaner), but it also
needed an additional entry for newly added items to trigger having the entry change positions:
$ cat app/views/tasks/update.js.erb
function update_task() {
const current_task = document.querySelector('#edit_task_<%= #task.id %>');
const to_task = document.querySelector('#<%= #task.complete? ? "complete_tasks" : "incomplete_tasks" %>');
// Remove from previous list
current_task.remove();
// Append to the end of new list
to_task.insertAdjacentHTML('beforeend', '<%= j render(#task) %>');
// Advise tasks.js that new entry needs listener added
to_task.dispatchEvent(new Event('task_added', { bubbles: true }));
}
update_task();
Hope others find this useful :)
In my rails app I have a dropdown menu that a user can select an account to make a payment to:
//_payment.html.erb
<div class="field" id="payment-to-account">
<%= f.label 'Payment To:' %><br>
<%= f.collection_select :to_account_id, #liability_account_payment_list, :id, :account_details, {include_blank: 'Please Select'} %>
</div>
When the user selects a account I render a partial inside of this form based on their selection:
//_payment.html.erb
<%= form_for(#transaction,
as: :transaction,
url:
#transaction.id ? account_transaction_path(#account, #transaction) : account_transactions_path) do |f| %>
...
<% #f = f %>
<div id="to-account-form" style="display:none;"></div>
...
<script>
jQuery(function(){
$("#payment-to-account").change(function() {
var selected_item = $( "#payment-to-account option:selected" ).text();
var selected_item_index = $( "#payment-to-account option:selected" ).index();
//looks for account type in parentheses followed by space moneysign " $"
var regExp = /\(([^)]+)\)\s\$/;
var matches = regExp.exec(selected_item);
// array of account ids in order of list
var payment_account_ids = <%= raw #payment_list_ids %>;
switch (matches[1]) {
case 'Mortgage':
$('#to-account-form').html("<%= j render 'payment_to_mortgage', f: #f %>");
$('#to-account-form').slideDown(350);
break;
case 'PersonalLoan':
case 'CreditCard':
case 'StudentLoan':
case 'OtherLiability':
$('#to-account-form').html("<%= j render 'payment_to_all_other_liabilities', f: #f %>");
$('#to-account-form').slideDown(350);
break;
default:
$('#to-account-form').html("<br>" + "Contact support, an error has occurred");
$('#to-account-form').slideDown(350);
}
});
});
</script>
Right now it renders the correct partial based on the selection, but when that partial loads I need more information from the account model. I created a method called find_pay_to_account that take the input selected account id in the Accounts model that looks for the account based on the id.
When the user selects and account from the drop down, I'd like that method called on the partial that is loaded so I can show the user additional information about the account they are making a payment to before they submit the form. But I don't know how. I wanted to add something like this to my jQuery switch statement.
selected_account_id = payment_account_ids[selected_item_index-1]
#payment_to_account = Account.find_pay_to_account(selected_account_id)
Since rails preloads the partials in the background, making the following change to my partial render in the case statements still wont work:
From this
$('#to-account-form').html("<%= j render 'payment_to_mortgage', f: #f %>");
To this
$('#to-account-form').html("<%= j render 'payment_to_mortgage', f: #f, #payment_to_account: #payment_to_account %>");
I did some searching and found that with AJAX might be able to help:
Pragmatic Studio
Rails Cast
But i'm trying to access the model, not the controller and I'm trying to update a form partial. What is the correct way to do this?
Here are pics that show the user flow. An example of what I'm trying to update can be seen in the last pic. When the mortgage account is selected, it needs to show the minimum payment for the mortgage account. Right now it says zero because the partials rendering with all the information from BOA seed 0214.
If you want to access record information from your model inside of front-end javascript you will indeed want to setup a small api to query the database for that information. In ajax it would be something like this
function processDataFunction(data){
console.log(data)
}
$.ajax({
type: "GET",
dataType: "json",
url: "/some-path/:some_id",
success: processDataFunction(data){}
});
#config/routes.rb
Rails.application.routes.draw do
get "/some-path/:some_id", to: "some_controller#some_view", :defaults => { :format => :json }
end
#app/controllers/some_controller.rb
class SomeController < ApplicationController
def some_view
#some_records = SomeModel.find_by_id(params[:some_id])
respond_to do |format|
format.json { render json: #some_records }
end
end
end
To access the information in the rendered partial without making another controller action, I collected all data I might need in the original action. That way I could get the exact result I was looking for without changing my routes and doing ajax request.
To do this I added methods to the controller new action. You can see from my original question, all accounts I may need information for are in the variable that is in the dropdown menu:
#liability_account_payment_list
This is where the dropdown menu gets its information from
That variable is in the Transaction controller new action. So I created another variable storing an array on the line after the above variable:
#liability_accounts_payment_list_minimum_payments = #liability_account_payment_list.map {|account| account.minimum_payment.to_f + account.minimum_escrow_payment.to_f}
This new variable is an array of all the accounts minimum payments in the order they are listed in the dropdown menu the user will select from.
Then I changed the jQuery on the page to the following
//_payments.html.erb
<script>
jQuery(function(){
$("#payment-to-account").change(function() {
var selected_item = $( "#payment-to-account option:selected" ).text();
var selected_item_index = $( "#payment-to-account option:selected" ).index();
//looks for something in parentheses followed by space moneysign " $"
var regExp = /\(([^)]+)\)\s\$/;
var matches = regExp.exec(selected_item);
// array of minimum payments from accounts in list converted from ruby to js
var min_payments = <%= raw #liability_accounts_payment_list_minimum_payments %>;
// set the js variable to the appropriate minimum payment
var selected_account_min_payment = min_payments[selected_item_index-1];
switch (matches[1]) {
case 'Mortgage':
$('#to-account-form').html("<%= j render 'payment_to_mortgage', f: #f %>");
$("#min-payment-field-hidden").val(selected_account_min_payment);
$("#min-payment-field").html(selected_account_min_payment);
$('#to-account-form').slideDown(350);
break;
case 'PersonalLoan':
case 'CreditCard':
case 'StudentLoan':
case 'OtherLiability':
$('#to-account-form').html("<%= j render 'payment_to_all_other_liabilities', f: #f %>");
$("#min-payment-field-hidden").val(selected_account_min_payment);
$("#min-payment-field").html(selected_account_min_payment);
$('#to-account-form').slideDown(350);
break;
default:
$('#to-account-form').html("<br>" + "Contact support, an error has occurred");
$('#to-account-form').slideDown(350);
}
});
});
</script>
The lines that have min-payment-field-hidden are because setting two different divs with the same id does not work. One div is being used to set hidden_field, the other is showing the user what the value is.
//_payment.html.erb
<-- To make sure the appropriate minimum payment is submitted to controller -->
<%= f.hidden_field :amount, :id => "min-payment-field-hidden" %>
<div>
<%= f.label "Minimum Payment" %>
<div id="min-payment-field"></div>
</div>
If you look at my switch statement, you can see I set the above value with these lines:
$("#min-payment-field-hidden").val(selected_account_min_payment);
$("#min-payment-field").html(selected_account_min_payment);
Now the user can see the minimum payment for the specific account they choose from the dropdown.
I created the dynamic dropdown in template. and my further requirement is to change the value of the dropdown and send the value back to the web service to hit to change in the system. I have no idea how to do it in underscore template. below is the code that i write for dynamic dropdown. and where have to write the ratecall function either in template file or in main.js no idea about it. and rightnow I am just firing an alert showing on change fired but its not working. actually the error that is coming is ratecall is not defined. Any help will be appreciated. Thanks in advance.
<select id="rate" onchange="ratecall()">
<% for(var i=0;i<post.scales-1;i++){
if(i==post.rated){
var a= 'selected';
}else{
a='';
}
%>
<option id="<%=i%>"<%=a %> > <%= i%></option>
<%}%>
</select>
<%}else{
}
function ratecall(){
document.getElementById("rate").onchange = function () {
alert("ON CHANGE FIRED");
};
}
As pointed by #danblundell in the comments, the view should be responsible only for rendering.
I made a minimal backbone example which illustrates how it's done (for your example): http://jsfiddle.net/dh64x/3/
Backbone provides view objects where you can specify events and event handlers:
var PostView = Backbone.View.extend({
events: {
'change #rate': 'postSelected'
},
// ...
postSelected: function(e) {
console.log(e);
}
});
In this case, change events on select#rate element are bound to postSelected function.
Read the docu for more details:
http://backbonejs.org/#View
Please try this code..
<select id="rate" onchange="ratecall()">
<%
for(var i = 0;i < post.scales - 1;i++)
{
var a= ''
if(i==post.rated)
{
a = 'selected';
}
else
{
a = '';
}
%>
<option id="<%= i %>" <%= a %> > <%= i %></option>
<% } %>
</select>
<%
function ratecall()
{
alert("ON CHANGE FIRED");
}
I have a method inside helper which fires an action which changes value of instance variable. Inside my javascript I've done this:
if(cat_id == 1)
{
<% cat_appointments(1) %>
}
else if(cat_id == 2)
{
<% cat_appointments(2) %>
}
else if(cat_id == 3)
{
<% cat_appointments(3) %>
}
My helper:
module StaticHelper
def cat_appointments(cat_id)
#appointments = Appointment.where(cat_id: cat_id)
end
end
The problems is that appointments are set like every time there is selected cat with id=3. If I put alert in those conditions, alert with selected id is displayed correctly when user selects specific cat.
Any ideas what is wrong with this code? How to change that variable?
When I replace:
else if(cat_id == 2)
{
<% cat_appointments(2) %>
}
with:
else if(cat_id == 3)
{
<% cat_appointments(3) %>
}
Then there are not always displayed appointments with cat_id=3. Now there are always displayed events with cat_id=2. So, the last 'else if' statement is always correct.
Thank you.
Can you try adding =
<%= cat_appointments(1) %>
I have started working on a project and the person before me used HAML to display two select boxes and update the second based on the selection of the first. I do not understand how to convert the HAML to ERB so I just put the HAML in a partial. The first select box displays the correct values but the second does not contain anything. How can I make the first box update the second with the correct value? The first one contains states, then the second is supposed to contain installations base on the state selected. Here is my code:
Search view:
<%= render 'state_installation_select' %>
HAML partial:
= state_installation_select #states, #installation_options_by_state # ProgramsHelper
ProgramsHelper:
def state_installation_select(states, installation_options_by_state)
haml_tag(:div, class: 'field') do
haml_concat(label_tag :state, "Please select your state")
haml_concat(select_tag :state, options_for_select(states), include_blank: true, class: 'state state_installation_select')
end
haml_tag(:div, class: 'field') do
haml_concat(label_tag :installation_id, "Please select your installation")
haml_concat(select_tag :installation_id, nil, include_blank: true, class: 'installation state_installation_select')
end
content_for :domready, %(InstallationSelect.init(#{installation_options_by_state.to_json});).html_safe
end
Program Controller:
def search_form_for_parents
#installations = Installation.all
#states = Installation.states
#installations_by_state = #installations.group_by(&:state_code)
#installation_options_by_state = #installations_by_state.each_with_object({}){ |(state,installations), h| h[state] = installations.map{|i| [i.name, i.id]} }
end
Program Javascript:
var InstallationSelect = {
init: function(installations_for_state){
$state_select = $('select.state.state_installation_select');
$state_select.change(function(){
var state = $(this).val();
var installations = installations_for_state[state] || [];
var $installation_select = $(this).parent().parent().find('select.installation.state_installation_select');
$installation_select.html( InstallationSelect.options_for_select(installations) );
}).triggerHandler('change');
},
options_for_select:function(container){
var options = jQuery.map(container, function(c){
return '<option value="' + c[1] + '">' + c[0] + '</option>';
});
return options;
}
};