Ruby on Rails clipboard-rails dynamic url copy issue - ruby-on-rails

So I wanted to copy the url of each resource to the clipboard so I tried:
<% #posts.each do |post|%>
<script>
$(document).ready(function(){
var clipboard = new Clipboard('.clipboard-btn');
console.log(clipboard);
});
</script>
<textarea id="bar"><%= post_path(post)%></textarea>
<button class="clipboard-btn" data-clipboard-action="copy" data-clipboard-target="#bar">
Copy to clipboard
</button>
<% end %>
But the problem with that was it only copied the url of the first resource. So I tried this:
<% #posts.each do |post|%>
<script>
$(document).ready(function(){
var clipboard = new Clipboard('.clipboard-btn<%=post.id%>');
console.log(clipboard);
});
</script>
<textarea id="bar<%=post.id%>"><%= post_path(post)%></textarea>
<button class="clipboard-btn<%=post.id%>" data-clipboard-action="copy" data-clipboard-target="#bar<%=post.id%>">
Copy to clipboard
</button>
<% end %>
without any luck

You can move your script outside the iteration, in order to create just one, not one for each of your posts inside #posts, and to use a way to match each element in the DOM with class starting with clipboard-btn, so you don't need to add the id, like:
<% #posts.each do |post|%>
<textarea id="bar<%= post.id %>">
<%= post_path(post) %>
</textarea>
<button
class="clipboard-btn<%= post.id %>"
data-clipboard-action="copy"
data-clipboard-target="#bar<%= post.id %>">
Copy to clipboard
</button>
<% end %>
<script>
$(document).ready(function(){
var clipboard = new Clipboard('[class^="clipboard-btn"]');
});
</script>
As example:
$(document).ready(function() {
var clipboard = new Clipboard('[class^="clipboard-btn"]');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.7.1/clipboard.min.js"></script>
<textarea id="bar1">Some content 1</textarea>
<button class="clipboard-btn1" data-clipboard-action="copy" data-clipboard-target="#bar1">
Copy to clipboard
</button>
<br>
<textarea id="bar2">Some content 2</textarea>
<button class="clipboard-btn2" data-clipboard-action="copy" data-clipboard-target="#bar2">
Copy to clipboard
</button>
<br>
<textarea id="bar3">Some content 3</textarea>
<button class="clipboard-btn3" data-clipboard-action="copy" data-clipboard-target="#bar3">
Copy to clipboard
</button>
<br>

You cannot copy multiple target elements at once. However, you can use some more advanced options in the imperative api for that:
new Clipboard('.clipboard-btn', {
text: function(trigger) {
var a = document.querySelector('#a').value;
var b = document.querySelector('#b').value;
return a + b;
}
});

Related

How do I properly handle submit events in Vue + Rails?

I'm learning Rails, Vue and JS and I've got a question on the proper handling of submit buttons on Rails using Vue component to validate it. I'm using mdbootstrap for the styles.
I built a form wizard which uses vee-validate for validating the fields and in some forms I want to perform some server side operations too (eg.: validate exact address with geocoding). I'm currently facing basically three issues.
Although I added a v-clock directive, I'm still seeing a little
flicker every time the form wizard component gets loaded (eg.: page
refresh).
I had to workaround the Rails automatic data-disable-with handling to get it working, and it looks not optimal to me, and I'd like to know if there's a better way to deal with it (I had to disable the submit event propagation and prevent default and do the disabling/enabling manually otherwise the handler from Rails UJS will receive it afterwards and disable the button forever).
Although the button gets enabled again, it gets brighter every time I click on it if validation fails (some handler from mdbootstrap maybe?). It happens only after I click on refresh button on the browser and I've noticed the following div is created after each click followed by an error during form validation, causing the button to become "brighter" as in a accumulated "disabled effect":
Anyone has ideas on how these issues could be solved? Thanks!
new.html.erb:
<div id="stepper">
<div v-cloak>
<transition-group name="fade">
<div class="d-none d-lg-block" key="progress_bar">
<%= render 'forms/progress_bar' %>
</div>
<div id="step1" v-if="step === 1" key="step1">
<%= render 'forms/description' %>
</div>
<div id="step2" v-if="step === 2" key="step2">
<%= render 'forms/address' %>
</div>
</transition-group>
</div>
</div>
_description.html.erb:
<template>
<form
id="description-form"
data-vv-scope="description-form"
novalidate="true"
#submit.prevent="next('description-form', $event)">
<div class="row mb-5">
<div class="col-lg-12 col-md-12">
<div class="container">
<div class="row" id="step-1">
<div class="col-lg-6">
<div class="max-height-80">
<div class="mb-4">
<h4><%= t(:'step1.title') %></h4>
</div>
<div class="form-group">
<label
for="name"
class="control-label">
<%= t(:'step1.label.name') %>
</label>
<input
id="name"
name="name"
type="text"
class="form-control"
placeholder="<%= t(:'step1.input.name') %>"
v-validate="'required'"
v-model="name"
:class="{ 'is-invalid': errors.has('name','description-form') }"
required/>
<div
v-if="errors.has('name','description-form')"
class="invalid-feedback">
<%= t(:'name.required') %>
</div>
</div>
<div class="form-group">
<label
for="description"
class="control-label">
<%= t(:'step1.label.description') %>
</label>
<textarea
id="description"
name="description"
class="form-control"
placeholder="<%= t(:'step1.input.description') %>"
rows="11"
v-validate="'required'"
v-model="description"
:class="{ 'is-invalid': errors.has('description','description-form') }"
required>
</textarea>
<div
v-if="errors.has('description','description-form')"
class="invalid-feedback">
<%= t(:'description.required') %>
</div>
</div>
</div>
<footer class="page-footer white fixed-bottom d-block d-sm-none z-depth-1" id="footer">
<div class="d-flex justify-content-end">
<button class="btn btn-default pull-right" type="submit" data-remote="true" data-disable-with="<%= wait_spinner %>"><%= t(:'btn.next') %></button>
</div>
</footer>
<div class="d-none d-sm-block">
<div class="d-flex justify-content-end mt-2">
<button class="btn btn-default pull-right" type="submit" data-remote="true" data-disable-with="<%= wait_spinner %>"><%= t(:'btn.next') %></button>
</div>
</div>
</div>
<div class="col-lg-2"></div>
<div class="col-lg-4 d-none d-lg-block mt-lg-5">
</div>
</div>
</div>
</div>
</div>
</form>
</template>
stepper.js
var element = document.getElementById("stepper");
if (element != null) {
Vue.use(VeeValidate);
Vue.use(VueResource);
Vue.http.headers.common['X-CSRF-Token'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
const stepper = new Vue({
el: element,
data() {
return {
/**
* The step number (starting from 1).
* #type {Integer}
*/
step:1,
name:null,
description:null
}
}
},
methods: {
/**
* Goes back to previous stepp
*/
prev() {
this.step--;
},
/**
* Triggers validation of current step and goes to the
* next step if validation succeeds
* #param {String} scope The step scope used for validation.
* #param {Object} Event that triggered the next step (form submit)
*/
next(scope, event) {
if (event != undefined) {
event.stopImmediatePropagation();
event.preventDefault();
event.stopPropagation();
}
const form = event.currentTarget;
$("button[type=submit]",form).each(function() {
Rails.disableElement(this);
});
this.validateFields(scope, event);
},
validateFields(scope, event) {
this.$validator.validateAll(scope).then(function (valid) {
this.postFieldsValidation(valid, event);
}.bind(this));
},
postFieldsValidation(valid, event) {
if (valid) {
stepper.step++;
}
const form = event.currentTarget;
$("button[type=submit]",form).each(function() {
Rails.enableElement(this);
});
},
handleError(error) {
alert(error)
},
submit() {
}
}
});
}
* edit *
for #3, I'm using a workaround for removing the div with waves-ripple class inside my button when re-enabling elements on the form.
$("div").remove("button .waves-ripple");
however, it would be nice to know the root cause for it.

Bootstrap model showing the same text each time

I am using bootstrap modal for showing a popup:
<% #yourphotos.each do |photo| %>
<!-- Modal -->
<div class="modal fade" id="myModal" role="dialog">
<div class="modal-dialog">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
<h4 class="modal-title"><%= name %></h4>
</div>
<div class="modal-body">
<p>
<% if photo.caption != nil %>
<%= photo.caption.text %>
<% else %>
nil text
<% end %>
</p>
</div>
<form class="navbar-form pull-left">
<input type="text" class="span2">
<button type="submit" class="btn">Comment</button>
</form>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</div>
<% end %>
Lets say I loop through the above and have 10 photos (in #yourphotos) my caption.text in each of the modals when I launch is the same each time even though when I view source I can see the 10 different modal captions..is this a JavaScript thing?
How do you open the modal? Maybe you keep on opening the same modal all the time?
Try one of Following (For bootstrap 3). It will remove the loaded data before open next time.
$( document ).ready(function() {
$("#myModal").on('hidden.bs.modal', function () {
$(this).data('bs.modal', null);
});
});
Or
$( document ).ready(function() {
$('#myModal').on('hidden.bs.modal', '.modal', function () {
$(this).removeData('bs.modal');
});
});
Or
$( document ).ready(function() {
$('#myModal').on('hidden.bs.modal', function () {
$(this).removeData('bs.modal');
});
});
Reference Link

How to toggle a div based on a select box value change inside same component in ember

I am new to ember. I have two divs with a select box each. I want the second div to toggle based on the change in the first select box value.
First DIV with select box:
<div class="row row-space">
<div class="col-sm-10">
<div class="input-group input-group-sm">
<span class="input-group-addon edit_schedule_label" id="sizing-addon3">Schedule Level</span>
<div class="recurrence_box">
{{view "select" content=schedule_levels optionValuePath="content.value" optionLabelPath="content.label" selection="default_schedule_level.value" value="default_schedule_level.value" selectionBinding="default_schedule_level"}}
</div>
</div>
</div>
</div>
Second DIV:
{{#if group_level_decider }}
<div class="row row-space">
<div class="col-sm-10">
<div class="input-group input-group-sm">
<span class="input-group-addon edit_schedule_label" id="sizing-addon3">Location </span>
<div class="recurrence_box">
{{view "select" content=schedule_levels optionValuePath="content.value" optionLabelPath="content.label" selection="default_schedule_level.value" value="default_schedule_level.value" selectionBinding="default_schedule_level"}}
</div>
</div>
</div>
</div>
{{/if}}
In Controller, I am observing the change in selection binding of the first select box and setting the condition to toggle for the second div. I can see the condition variable here "group_level_decider" getting set to the correct value but it is not reflecting in the view.
Controller:
group_level_decider : false,
schedule_level_changed: function() {
var model = this.get('store');
model.set('selected_schedule_level',this.get('default_schedule_level.value'))
model.set('group_level_decider',true)
}.observes('default_schedule_level')
Please help me. Thanks!
Here is an example of filtering out cities based on a state:
App.IndexController = Ember.ArrayController.extend({
cities: function(){
var state = this.get('state');
var states = this.get('model');
var cities = [];
if(state){
cities = states.filterBy('state', state).get(0).get('cities');
}
return cities;
}.property('state'),
states: function(){
return this.get('model').mapBy('state');
}.property(),
stateObserver: function(){
this.set('city', null);
}.observes('state')
});
Then, inside your template:
States: {{view "select" prompt="Pick State..." content=states value=state}}
Cities: {{view "select" prompt="Pick City..." content=cities value=city }}
Working solution here

How to passing form params from formRemote to remoteFunction in GSP

example is very simple.
select the two search condition and return a table with pagination, the whole page will not refresh.
so i use the grails formRemote to submit the form, and the control return the gender with template and it work well. However, the pagination i want to use Jquery, but i cant pass the formRemote params to the remoteFunction using onSuccess method in formRemote.
Here it is the code:
<div class="formSep col-md-12">
<g:formRemote update="searchResult" class="form-inline" role="form" name="form"
url="[controller: 'autoRateRecord', action: 'search']" onSuccess="initPagination(data)">
<div class="form-group col-lg-2">
<g:select class="form-control" name="notified" from="${['done', 'undone']}"
noSelection="${['null': 'Oops']}">
</g:select>
</div>
<div class="form-group col-lg-2 pull-right">
<button type="submit" class="btn btn-primary btn-lg">
<span class="glyphicon glyphicon-search"></span> search
</button>
</div>
</g:formRemote>
</div>
<div id="searchResult">
<g:render template="searchList"/>
</div>
<script type='text/javascript'>
function initPagination(data) {
console.log("------> " + data)
$("#Pagination").pagination(10, {
callback: getRecordList(1),
prev_text: "prev",
next_text: "next",
items_per_page: 15,
num_edge_entries: 1
});
}
**!!!!!!! need formRemote data !!!!!!!**
function getRecordList(page_index) {
<g:remoteFunction controller="autoRateRecord" action="search" update="searchResult" params="'page='+page_index"/>
}
// On load, style typical form elements
$(function () {
});
</script>
the controller code is:
def search = {
log.info(ToStringBuilder.reflectionToString(params))
// logic .....
render(template: "searchList", model: [
autoRateRecords: result,
total : result.totalCount
])
}
I would change the pagination script to something like
$("#pageHiddenFieldId").val(pageNo);
$("#myForm").submit();

jquery ui tab select method not working

I have two tabs with a submit button on each tab. When the button is clicked, I need to reload the content of that specific tab to get updated data from the server.
if (validStatus()) {
$.ajax({
//...
success: reloadTab
});
}
function reloadTab() {
var currentTab = $("#tabs").tabs("option", "active");
alert(currentTab);
$('#tabs').tabs('select', currentTab);
alert(currentTab);
}
When the button is clicked, the tab doesn't refresh. I see the first alert but not the second.
HTML is as follows:
Head:
<link rel="stylesheet" href="#this.Url.Content("//code.jquery.com/ui/1.10.3/themes/smoothness/jquery-ui.css")" />
<script>
$(function () {
$("#tabs").tabs();
});
</script>
Body:
<div id="tabs">
<ul>
<li>The first tab</li>
<li>the second tab</li>
<li>Success</li>
</ul>
<div id="Success">
testing
</div>
<div id="Tab1">
<fieldset >
<legend>Overview</legend>
<input type="button" id="submit1" value="submit" />
<br />
</fieldset>
<fieldset style="width: 700px;">
<legend>Overview</legend>
<div>
<table >
//updated with ajax
</table>
</div>
</fieldset>
<script>
//reloadTab is in here
</script>
</div>
<div id="Tab2">
<fieldset style="float:left; width:300px;">
<input id="submit2" type="button" value="submit"/>
</fieldset>
<fieldset style="float:left;">
<legend>Overview</legend>
<table>
//updated with ajax
</table>
</fieldset>
<script>.....</script>
</div>
Turns out tabs.('select', ...) is deprecated, using tabs.('option', 'active', index) fixed my issue. Solution found in this comment: https://stackoverflow.com/a/16033969/1463649
Do you see anything in the console of your browser? What browser are you using?
Try this to help you with the debugging.
function reloadTab() {
console.log($('#tabs')); // if this is an empty object, the element doesn't exist when you call this function
console.log($('#tabs').tabs()); // if this doesn't return 'function', you haven't included a library properly, maybe jquery ui, or jquery, or you're using an old version or something
console.log(currentTab); // if this is undefined then something went wrong and no tab is active
var currentTab = $("#tabs").tabs("option", "active");
alert(currentTab);
$('#tabs').tabs('select', currentTab);
alert(currentTab);
}

Resources