I have a Rails application which has some <li> elements with style display: none; CSS property. I want to make it appear on the page only while dragging that element. However, some elements don't have display: none; style. How do I do it ?
Following is my HTML code :
<div class="col-xs-12 col-md-6 col-lg-3">
<li id="<%=video_upload.id %>" <% if video_upload.invisible == true %> <%= "style=display:none;" %> <%end%> >
<% if mobile? %>
<a href="<%= showvideo_path(video_upload.id) %>">
<div style="background-color: white">
<%= image_tag("/images/upload_images/"+"#{video_upload.imagename}", height: '130', width: '200') %>
</div>
</a>
<% else %>
<div style="background-color: white">
<img src="<%= '/images/upload_images/'+"#{video_upload.imagename}" %>" class="img-responsive" style="cursor:pointer" onclick="popVideo('https://app.box.com/embed/s/<%= video_upload.link[/([^\/]+)$/] %>');" >
</div>
<% end %>
<span style="float: left">
<%= File.basename(video_upload.imagename, '.*') %>
</span>
<span style="float: right">
<%= link_to '', edit_video_uploads_path(video_upload), {class: 'btn btn-primary glyphicon glyphicon-pencil', :style => 'color: white'} %>
<%= button_tag(:del_flag => 'button', :id => video_upload.id ,:class => 'btn btn-danger user-approve-btn glyphicon glyphicon-trash') do
""
end %>
</span>
</li>
</div>
I am using this javascript for drag and drop.
Select all your <li> elements, and show them while dragging. Then hide them when the drag ends:
document.querySelectorAll('li').forEach(li => {
// Show the <li> on drag
li.addEventListener('dragstart', event => {
event.target.style.display = 'block';
});
// Hide each <li> back
li.addEventListener('dragleave', event => {
event.target.style.display = 'none';
});
});
This is using the HTML5 native drag and drop feature as you can see in this blog article. Let me know if it works as you want.
UPDATE:
In case that you want to select 1 element like you said, you just have to add an id="myElement" in that element and then select it like so:
let element = document.querySelector('#myElement');
element.addEventListener('dragstart', event => {
event.target.style.display = 'block';
});
element.addEventListener('dragleave', event => {
event.target.style.display = 'none';
});
Related
I have a simple form(product model) and I’m also using the cocoon gem for the nested fields(attachments model) that I have inside that form. When I create a product I use the cocoon gem for the nested fields in order to create attachments(images) and associate them to that product. The user can add a cocoon field and add an image to that field. I also have a preview inside each field so the user can view the image they attach to that field. But the only problem is that the preview only shows in the first cocoon field. If I try to add an image to another cocoon field the image preview doesn’t appear inside that field. I would like to be able to add a cocoon field, then add the image to that field and view the preview of that image inside that field. Any ideas on how I can change around my code in order to achieve the above?
This is the setup I have:
<%= f.simple_fields_for :attachments do |attachment| %>
<%= render 'products/attachment_fields', form: attachment %>
<% end %>
<div class="links" id="add_attachment">
<%= link_to_add_association raw('<i class="fas fa-plus"></i>'), f, :attachments, form_name: 'form' %>
</div>
attachment_fields partial :
<div class="nested-fields">
<div class="col-md-12">
<div class="image-border">
<div class="image-border-content">
<div class="parent">
<div class="image-content" id="divImageMediaPreview">
<div class="font-awesome-image"><i class="far fa-image"></i></div>
</div>
</div>
<label class="btn btn-light btn-sm" style="width: 100%;">
Add a file!
<span style="display:none;">
<%= form.input :image, label: false, as: :file, input_html: { class:"custom-file-input", id: "ImageMedias" } %>
</span>
</label>
</div>
</div>
<div class="links" style="margin-bottom: 10px;">
<%= link_to_remove_association raw('<i class="far fa-trash-alt"></i> Remove'), form, class: "btn btn-light btn-sm", :style => "width: 100%; margin-top: -15px;" %>
</div>
</div>
</div>
Image preview:
$("#ImageMedias").change(function () {
if (typeof (FileReader) != "undefined") {
let dvPreview = $("#divImageMediaPreview");
dvPreview.html("");
$($(this)[0].files).each(function () {
let file = $(this);
let reader = new FileReader();
reader.onload = function (e) {
let img = $("<img />");
img.attr("style", "width: 100%; height:auto;");
img.attr("src", e.target.result);
dvPreview.append(img);
}
reader.readAsDataURL(file[0]);
});
} else {
alert("This browser does not support HTML5 FileReader.");
}
});
Update 1
I got it to work with a minor adjustment to #nathanvda answer. But I have a small glitch. If I add one field at a time, the preview appears in each field but if I add more then one field I get the issue that is showing in the image below. Any idea how I can fix this issue ?
This is the exact code I'm using:
<div class="nested-fields">
<div class="col-md-12">
<div class="image-border">
<div class="image-border-content">
<div class="parent">
<div class="image-content image-media-preview">
<div class="font-awesome-image"><i class="far fa-image"></i></div>
</div>
</div>
<label class="btn btn-light btn-sm" style="width: 100%;">
Add a file!
<span style="display:none;">
<%= form.input :image, label: false, as: :file, input_html: { class:"custom-file-input" } %>
</span>
</label>
</div>
</div>
<div class="links" id="remove_attachment" style="margin-bottom: 10px;">
<%= link_to_remove_association raw('<i class="far fa-trash-alt"></i> Remove'), form, class: "btn btn-light btn-sm", :style => "width: 100%; margin-top: -15px;" %>
</div>
</div>
</div>
$(function() {
$('input[type=file]').change(function(){
if (typeof (FileReader) != "undefined") {
let dvPreview = $(this).parents(".image-border").find(".image-media-preview");
dvPreview.html("");
$($(this)[0].files).each(function () {
let file = $(this);
let reader = new FileReader();
reader.onload = function (e) {
let img = $("<img />");
img.attr("style", "width: 100%; height:auto;");
img.attr("src", e.target.result);
dvPreview.append(img);
}
reader.readAsDataURL(file[0]);
});
} else {
alert("This browser does not support HTML5 FileReader.");
}
})
});
You use an element with an id of #divImageMediaPreview: this means that html expect this element to be present only once on the page. You need to give the element a class, and then search the closest instance.
For instance, in your view write
<div class="nested-fields">
<div class="col-md-12">
<div class="image-border">
<div class="image-border-content">
<div class="parent">
<div class="image-content image-media-preview">
<div class="font-awesome-image"><i class="far fa-image"></i></div>
</div>
</div>
<label class="btn btn-light btn-sm" style="width: 100%;">
Add a file!
<span style="display:none;">
<%= form.input :image, label: false, as: :file, input_html: { class:"custom-file-input", id: "ImageMedias" } %>
</span>
</label>
</div>
</div>
<div class="links" style="margin-bottom: 10px;">
<%= link_to_remove_association raw('<i class="far fa-trash-alt"></i> Remove'), form, class: "btn btn-light btn-sm", :style => "width: 100%; margin-top: -15px;" %>
</div>
</div>
</div>
And then in your code do the following:
$("#ImageMedias").change(function () {
if (typeof (FileReader) != "undefined") {
let dvPreview = $(this).parents(".image-border").find(".image-media-preview");
dvPreview.html("");
$($(this)[0].files).each(function () {
let file = $(this);
let reader = new FileReader();
reader.onload = function (e) {
let img = $("<img />");
img.attr("style", "width: 100%; height:auto;");
img.attr("src", e.target.result);
dvPreview.append(img);
}
reader.readAsDataURL(file[0]);
});
} else {
alert("This browser does not support HTML5 FileReader.");
}
});
so the main change is
let dvPreview = $(this).parents(".image-border").find(".image-media-preview");
this will search a parent element up in the DOM tree with class image-border and then we descend the DOM to find your preview element. It is possible that the simpler $(this).closest('.image-media-preview') also works, but I was not sure.
Facing same problem solved by below code, where I created a div with class="upload_preview" containing image tag given id="preview_image" then on change event class="upload_image" to form field of image :-
NOTE :- I used the same form for create and edit page that's why I used if else condition for preview image
<%= f.fields_for :images, f.object.images.present? ? f.object.images : f.object.images.build do |image_form| %>
<div class="field-group">
<div class="form-group">
<label class="font-weight-bold">Image</label>
<div class="upload_preview preview_style">
<% if image_form.try(:object).try(:image).present? %>
<img id="preview_image" class="preview_img" src="<%= image_form.try(:object).try(:image_url) %>" alt="" width="40px" height="40px" /> ## image preview
<%else%>
<img id="preview_image" class="preview_img" src="/assets/default-image.png" alt="" width="40px" height="40px" /> ## image preview
<% end %>
</div>
<%= image_form.file_field :image, class: "form-control upload_image"%> ## on change event
</div>
<div class="form-group">
<%= image_form.link_to_remove "Delete image", class: "btn btn-danger btn-sm" %>
</div>
</div>
<% end %>
<div class="form-group">
<%= f.link_to_add "Add more image", :images, class: "btn btn-info btn-sm" %>
</div>
java script code
<script type="text/javascript">
$(document).ready(function(){
$(document).on('change', '.upload_image', function() {
readURL(this);
});
});
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
$(input).siblings('.upload_preview').children('#preview_image').attr('src', e.target.result);
}
reader.readAsDataURL(input.files[0]);
}
}
</script>
I am fairly new to Rails.
I was able to correctly get the onclick to function for a f.checkbox.
Now I am trying to do something similar for a f.select in a _form.
here is my working code for a checkbox
erb portion :
<div class="row">
<div class="col-md-4">
<div class="field">
<%= f.label :air? %>
<%= f.check_box :air, :id => "chk_air", :onclick => "manageAirDisp();" %>
</div>
</div>
<% if request.air? %>
<div class="col-md-4", id="MultiButton", style="display: block">
<% else %>
<div class="col-md-4", id="MultiButton", style="display: none">
<% end %>
<button onclick="showAirMulti(); return false;", class="btn-custom-normal">Show/Hide Multi-Destinations</button>
</div>
</div>
on top of the _frm the corresponding script portion:
function manageAirDisp (){
var checkbox = document.getElementById('chk_air');
// this check below checks if checkbox is checked or not.
if (checkbox.checked){
document.getElementById("air_div").style.display = "block";
document.getElementById("MultiButton").style.display = "block";
} else {
document.getElementById("air_div").style.display = "none";
document.getElementById("MultiButton").style.display = "none";
}
}
Now what I cannot get to work with a dorp down selection instead:
the erb portion:
<div class="row">
<div class="col-md-4">
<div class="field">
<%= f.label :event %>
<!-- < f.check_box :event, :id => "chk_event", :onclick => "manageEvent();" > -->
<%= f.select :event, [['Unkown', 'unk'], ['yes', 'yes'], ['no', 'no']], :onchange => "manageEvent();" } %>
</div>
</div>
</div>
<div class="row", id="event_blk", style="display: none">
<div class="col-md-4">
<div class="field">
<%= f.label :registration, "addQuestion?" %>
<%= f.check_box :addquestion %>
</div>
</div>
</div>
and now the corresponding script portion that I canot get to work:
function manageEvent(){
var checkbox = document.getElementById('chk_event');
// this check below checks if checkbox is checked or not.
if (selection.val() = "yes"){
document.getElementById("event_blk").style.display = "block";
} else {
document.getElementById("event_blk").style.display = "none";
}
// to check on value instead it should look as follows:
// if (checkbox.val() = "something") { then do something }
}
So what I want to do is to have the section event_blk to become visible when the user select "yes" and that as soon as they have it selected, or make it invisible as soon as they select no or unk
Thanks for any help
It looks like you aren't declaring selection -- you are setting the variable checkbox instead.
Also, you should use .value instead of .val().
Try this:
function manageEvent(){
// change checkbox to selection
var selection = document.getElementById('chk_event');
// changed selection.val() to selection.value
if (selection.value == "yes"){
document.getElementById("event_blk").style.display = "block";
} else {
document.getElementById("event_blk").style.display = "none";
}
}
Update:
You will also need to fix your select helper. If you check out the documentation, you will find that the last two arguments accepted by the select helper are the options hash and the html_options hash. You need to pass :onchange in the html_options hash. Also, Rails will default to [model_name]_[attribute_name] as the id for the select element, so you will also need to pass :id => "chk_event" in the html_options hash if you want to use that string as the id:
<div class="row">
<div class="col-md-4">
<div class="field">
<%= f.label :event %>
<!-- < f.check_box :event, :id => "chk_event", :onclick => "manageEvent();" > -->
<%= f.select :event,
[['Unkown', 'unk'], ['yes', 'yes'], ['no', 'no']],
{}, #empty options hash
{ :id => "chk_event", :onchange => "manageEvent();" } %>
</div>
</div>
</div>
I have some trouble with an rails formular.
I have a form to create "projects".
Project form
<%= bootstrap_form_for(#project) do |f| %>
...
<div class="container-fluid">
<%= f.static_control label:"Vordefinierte Aufgaben" do %>
<div class="actions form-group nopadding">
<div class="center-block">
<%=link_to "", data: {toggle:"modal", target:".newTask-modal"} , class: "btn btn-success center-block btn-sidebar-ok", id: "singlebutton" do%>
<i> <span class="glyphicon glyphicon-plus pull-left btn-sidebar-icon"></span>Neue Aufgabe hinzufügen </i>
<% end %>
</div>
</div>
<div class="task-table">
<%=render 'tasks/table'%>
</div>
<% end %>
</div>
...
<!-- task Modal to create a new task -->
<%=render 'tasks/newTaskModal' %>
<% end %>
<!-- Button -->
<div class="actions form-group">
<div class="center-block">
<%= button_tag( type: 'submit', class: "btn btn-success center-block btn-sidebar-ok", id: "singlebutton") do%>
<i> <span class="glyphicon glyphicon-ok pull-left"></span>Projekt anlegen </i>
<% end %>
</div>
</div>
Within this form a have a table which shows created tasks and a button to open an bootstrap modal. This modal contains a new form to create a task.
Task Form within modal
<%= bootstrap_form_tag() do |f| %>
<div class="col-sm-8">
<%= f.text_field :task_title, label: "Titel", placeholder: "Betreff", icon: "pencil",wrapper: { class: 'icon-addon addon-md'} %>
</div>
<div class="col-sm-4">
<%= f.number_field :task_in_min, label: "Arbeitszeit in Min", placeholder: "Bsp.: 25", icon: "time", wrapper: { class: 'icon-addon addon-md'}%>
</div>
<div class="col-sm-12">
<%= f.text_area :task_description, label: "Beschreibung*", placeholder: "Aufgabenbeschreibung", icon: "pencil", rows: 10, wrapper: { class: 'icon-addon addon-md'}%>
</div>
<%= button_tag( type: 'button', id:"taskSubmit", class: "btn btn-success center-block btn-sidebar-ok") do %>
<i > <span class="glyphicon glyphicon-ok pull-left btn-sidebar-icon"></span> Speichern </i>
<% end %>
<% end %>
If I click to "taskSubmit" a javascript put this task (title, description, min) into the table within the project form. JS create a new table row with the task content.
Javascript
//take data from task form and at a new task element to the task table in project form
$(function TaskSubmitFunction(){
$('#taskSubmit').click(function(){
var task_title = $('#task_title').val();
var task_description = $('#task_description').val();
var task_in_min = $('#task_in_min').val();
//Remove spaces from title
var id = task_title.replace(/ /g,'');
$('#taskTable tr:last').after('<tr id="task_'+id+'"> <td>'+task_title+'</td> <td>'+task_description+'</td><td>'+task_in_min+'</td><td> <span class="pull-right"><span data-toggle="tooltip" data-placement="right" data-original-title="Löschen"><button class="btn btn-sm btn-danger btn-colored delete-position" id="'+id+'"name="button" type="button" task="'+task_title+'"><i><span class="glyphicon glyphicon-remove"/></i></button></span></span></td></tr>');
$('#taskTable').after('<input type="hidden" id="1" name="1" value="'+task_title+'" />');
$('#task_title').val('');
$('#task_description').val('');
$('#task_in_min').val('');
//initialize task delete
$(function TaskDeleteFunction(){
$('#'+id).click(function(){
var task_title = $(this).attr('task');
if (confirm("Soll die Aufgabe wirklich gelöscht werden?")) {
$('#'+id).remove();
}
return false;
});
});
});
});
What I want to do now is to submit these table elements to the project controller to create the project and all necessary tasks activeRecords. Is this possible?
How can I do this? Maybe create a hidden field for every table element which will be submit to the project form? But every table element consists of three values... how can I do this?
Do you have any idea?
best regards
Why not just use three hidden fields (one for each value)? Straightforward and they will be easy to access in the params hash.
i have two div id=left and div id=right. now, there are multiple checkboxes with item listed in left div. when i select one check box then that item should remove from left div and added to right div and do it same for move selected item from div id=right to div id=left. and when i click one check box its status also updated in database. so tell me how to perform this task with jquery-ajax in rails 3.
Script :
<script>
$(function () {
$(".checkbox").click(function() {
$('.allchkb').each(function(){
var item = $(this).attr('id');
if($(this).is(':checked')){
$("#right > span."+item).appendTo("#left");
$(this).siblings("#left").css("text-decoration","line-through");
$(this).siblings("#left").css("color","#aaa");
$(this).parent('li').css("background-color","#ccc");
}
else
{
$("#left > span."+item).appendTo("#right");
}
});
});
});
</script>
rails code:
<div class="box-body box-body-nopadding" id="left">
<% #activity.each do |p| %>
<% p.task.each do |t| %>
<ul class="tasklist">
<li class="bookmarked">
<label class="checkbox">
<%= check_box_tag 'activity_status', task.id, :class => 'checkbox'%>
<%= link_to task.title, mytask_path(#task), :title => "is responsible. , Total my task : " %>
<span class="task-actions">
<%= link_to "Edit", task(#activity) %> |
<%= link_to "delete", #task, :method => :delete %>
</span>
<span class="task-actions">
<%= task.due_date %>
</span>
</li><li>
</li>
</ul>
<% end %>
<% end %>
</div>
<div class="box-body box-body-nopadding" id="right">
</div>
I've created a wizard form with this gem: https://github.com/stephenbaldwin/fuelux-rails
Everything is working in terms of getting to the next and previous steps. However, what's a 'rails way' to hide the 'prev' button on first step and show only the 'submit' button on last step? Is this something I'd do do in js?
_form.html.erb
<%= form_for(#wizard) do |f| %>
<div>
<div id="MyWizard" class="wizard">
<ul class="steps">
<li data-target="#step1" class="active"><span class="badge badge-info">1</span>Step 1<span class="chevron"></span></li>
<li data-target="#step2"><span class="badge">2</span>Step 2<span class="chevron"></span></li>
<li data-target="#step3"><span class="badge">3</span>Step 3<span class="chevron"></span></li>
</ul>
</div>
<div class="step-content">
<div class="step-pane active" id="step1">
<div class="field">
<%= f.label :field1 %><br />
<%= f.text_field :field1 %>
</div>
</div>
<div class="step-pane" id="step2">
<div class="field">
<%= f.label :field2 %><br />
<%= f.text_field :field2 %>
</div>
</div>
<div class="step-pane" id="step3">
<div class="field">
<%= f.label :field3 %><br />
<%= f.text_field :field3 %>
</div>
</div>
<input type="button" class="btn btn-mini" id="btnWizardPrev" value="prev">
<input type="button" class="btn btn-mini" id="btnWizardNext" value="next"></br>
<div>
<%= f.submit :class => 'btn btn-mini btn-primary' %>
</div>
</div>
</div>
<% end %>
application.js file:
$(function() {
$('#MyWizard').on('change', function(e, data) {
console.log('change');
if(data.step===3 && data.direction==='next') {
// return e.preventDefault();
}
});
$('#MyWizard').on('changed', function(e, data) {
console.log('changed');
});
$('#MyWizard').on('finished', function(e, data) {
console.log('finished');
});
$('#btnWizardPrev').on('click', function() {
$('#MyWizard').wizard('previous');
});
$('#btnWizardNext').on('click', function() {
$('#MyWizard').wizard('next','foo');
});
$('#btnWizardStep').on('click', function() {
var item = $('#MyWizard').wizard('selectedItem');
console.log(item.step);
});
});
Side note/question - is there a way to put this .js in my asset pipeline without storing it in application.js? I tried to create a separate .js under javascripts but it dosen't pull in.
In your javascript file replace this block
$('#MyWizard').on('change', function(e, data) {
console.log('change');
if(data.step===3 && data.direction==='next') {
// return e.preventDefault();
}
});
with following block: (UPDATED)
$('#MyWizard').on('change', function(e, data) {
console.log('change');
$('#wizard-submit').hide(); //hide the submit button on each step.
if(data.step === 3 && data.direction === 'next') {
// return e.preventDefault();
$('#wizard-submit').show(); //show the submit button only on last(3rd in your case) step.
}
switch(data.step) {
case 1:
if(data.direction === 'next')
$('#btnWizardPrev').show();
else
$('#btnWizardPrev').hide();
$('#btnWizardNext').show();
break;
case 2:
if(data.direction === 'next') {
$('#btnWizardPrev').show();
$('#btnWizardNext').hide();
}
else {
$('#btnWizardPrev').hide();
$('#btnWizardNext').show();
}
break;
case 3:
// I would recommend to show the prev button on last step but hide the next button.
if(data.direction === 'next')
$('#btnWizardNext').hide();
else
$('#btnWizardNext').show();
$('#btnWizardPrev').show();
break;
default:
$('#btnWizardPrev').show();
$('#btnWizardNext').show();
}
});
The above code will show/hide the buttons based on the step you're in.
And for you second question: are you specifying the //= require_tree . in the application.js. If yes then try enclosing the code in $(document).ready(function(){..code goes here..})
UPDATE See the updated code above. I am not sure if this is the correct way, but I am able to get it working this way.
Also add #btnWizardPrev { display: none; }
Assumption: There are three steps in the form. If there are more you would need to add more cases in switch statement. Basically you'll need to break the case 2: statement in that case. In case 2: the next condition is for removing the next button, so in case there are more steps, move the next condition to second last step.
UPDATE Replace your submit button code with <%= f.submit :class => 'btn btn-mini btn-primary', :id => 'wizard-submit' %>. This will simply add id attribute to your submit button. You can use any value to be its id. Then just hide the submit button by adding this css #wizard-submit { dispay: none } and then use the above updated jquery code in your javascript file.
The wizard plugin already disables the previous button on the first step. It looks for a button.btn-prev located in the wizard container
<div id="myWizard" class="wizard">
<div class="actions">
<button class="btn btn-mini btn-prev"> <i class="icon-arrow-left"></i>Prev</button>
<button class="btn btn-mini btn-next" data-last="Finish">Next<i class="icon-arrow-right"></i></button>
</div>
If you'd like to hide the disabled previous button you could target it with css to avoid javascript
.wizard button.btn-prev[disabled] {
display: none;
}