How to fix file field button submitting form multiple times - javascript

The button for file field keeps submitting the form when it should be opening a window to select files to upload. Does anyone have an idea why?
= render 'show'
.row
.col-12
%ZenForm{ path: zen_support_urls.ticket_path, id: #zendesk_ticket.id, method: :put, :multipart => true, data: { remote: true } }
%button.fileUpload.btn.btn-default#upload_button{data: {type: "button"}}
Attach File
%input.upload#file_input{:name => "attachments[]", multiple: true, :type => "file"}/
%ul#filelist
- #zendesk_ticket.comments.each do | comment |
= render 'files', comment: comment
%ZenTextArea#comment{ label: "Comments", placeholder: "Add any comments you think will help us address your issue.", error: #zendesk_ticket.errors&.dig(:comment) }
Here is my JavaScript in app.js:
//= require jquery
//= require bootstrap-sprockets
//= require select2
//= require ./base
//= require ./tickets
//= require_tree .
Here is my CoffeeScript for tickets:
$(document).on "ready page:load", () ->
# this method forwards clicks to the first <a> element in the row
$.activateRowClick = (selector) ->
$(selector).click (e) ->
if !$(e.target).is('a')
$(this).find('a').click()
$(selector).css('cursor', 'pointer')
$.activateRowClick('tr.clickable')
Here is my JavaScript for ticketform.js:
$(document).on "ready page:load", ->
$support = new ZenSupport.Form "zs-ticket-form"
$support.comment = $support.form.find('textarea')
$support.subject = $("#zs-ticket-form__subject")
$support.priority = $("#zs-ticket-form__priority")
# $support.actions = $support.form.find('.support-ticket__action-btns')
$support.fields =
inputs: [$support.comment]
select2: [
$support.subject,
$support.priority
]
$support.subject.select2
theme: "bootstrap"
placeholder: "Please select..."
width: "100%"
allowClear: true
tags: true
$support.priority.select2
theme: "bootstrap"
placeholder: "Please select..."
width: "100%"
allowClear: true
tags: false
# Provide the beforeSend
$support.beforeSend = ->
has_subject = $support.subject.val().length
has_comment = $support.comment.val().length
placeholder = $support.comment.attr('placeholder')
required_inputs = $support.form.find(".required:visible")
inputs_valid = true
$.each required_inputs, (index, element) ->
console.log $(element).val().length
if($(element).val().length == 0)
$(element).parent().addClass('has-error')
inputs_valid = false
else
$(element).parent().removeClass('has-error')
return
if has_subject and has_comment and has_comment isnt placeholder and inputs_valid
$support.showLoader false
return true
else
$support.comment.parent('.form-group').toggleClass 'has-error', !has_comment
$support.subject.parent('.form-group').toggleClass 'has-error', !has_subject
return false
Here is my code for uploads.js. This file is not getting called when tickets is being called so this code is currently not doing anything and I think that is the problem:
$ ->
files = [];
$("#upload_button").click ->
$("#file_input").trigger "click";
$("#file_input").change (event) ->
file = event.target.files[0];
files.push(file);
uploadfile files.length - 1, file;
uploadfile = (index, file) ->
formData = new FormData();
formData.append "file", file;
fileitem = "
<li class='file-item success'>
<div class='active'>
<span class='remove'>×</span>
<span>#{file.name}</span>
</div>
<div class='lds-ellipsis'><div></div><div></div><div></div><div></div></div>
</li>
";
$('#filelist').append fileitem;
setRemove();
setRemove = ->
$(".remove").unbind();
$(".remove").click ->
index = $(#).parent().parent().index();
files.splice index, 1;
$('.file-item').eq(index).remove();

Related

Jquery in rails app is not working properly

I have a rails application that allows users to attach multiple files and detach files using jquery. However, the problem is you can select multiple files but only the last file selected gets uploaded. Not all files that were selected. Think it's something with my javascript code.
below is an image of what i am talking about
enter image description here
zen_support/zen_upload.js
$(function() {
files = void 0;
setRemove = void 0;
uploadfile = void 0;
files = [];
$('#upload_button').click(function(event) {
return $('#file_input').trigger('click');
});
$('#file_input').change(function(event) {
var file;
file = void 0;
file = event.target.files[0];
files.push(file);
return uploadfile(files.length - 1, file);
});
uploadfile = function(index, file) {
var fileitem, formData;
fileitem = void 0;
formData = void 0;
formData = new FormData;
formData.append('file', file);
fileitem = '<li class=\'file-item success\'> <div class=\'active\'> <span class=\'remove\'>×</span> <span>' + file.name + '</span> </div> <div class=\'lds-ellipsis\'><div></div><div></div><div></div><div></div></div> </li>';
$('#filelist').append(fileitem);
return setRemove();
};
return setRemove = function() {
$('.remove').unbind();
return $('.remove').click(function() {
var index;
index = void 0;
index = $(this).parent().parent().index();
files.splice(index, 1);
return $('.file-item').eq(index).remove();
});
};
});
_edit.html.haml
= render 'show'
= javascript_include_tag "zen_support/zen_upload.js"
.row
.col-12
%ZenForm{ path: zen_support_urls.ticket_path, id: #zendesk_ticket.id, method: :put, :multipart => true, data: { remote: true } }
.row
.col-md-4
%button.fileUpload.btn.btn-default#upload_button{type: "button"}
Attach File
%input.upload#file_input{:name => "attachments[]", multiple: true, :type => "file"}
.col-md-8
%ul#filelist
- #zendesk_ticket.comments.each do | comment |
= render "files", comment: comment
%ZenTextArea#comment{ label: "Comments", placeholder: "Add any comments you think will help us address your issue.", error: #zendesk_ticket.errors&.dig(:comment) }

Render js file in js.erb

Is it possible to render a javascript file inside a js.erb file? I have a modal that's being render in my new.js.haml file. However I have some javascript code that needs to run only when that modal gets called.
new.js.haml
$('.modal-content').html("#{ j(render partial: 'new') }");
I want to be able to call this file or render this file when new.js.haml is called upload.js
$ ->
files = [];
$("#upload_button").click ->
$("#file_input").trigger "click";
$("#file_input").change (event) ->
file = event.target.files[0];
files.push(file);
uploadfile files.length - 1, file;
uploadfile = (index, file) ->
formData = new FormData();
formData.append "file", file;
fileitem = "
<li class='file-item success'>
<div class='active'>
<span class='remove'>×</span>
<span>#{file.name}</span>
</div>
<div class='lds-ellipsis'><div></div><div></div><div></div><div></div></div>
</li>
";
$('#filelist').append fileitem;
setRemove();
setRemove = ->
$(".remove").unbind();
$(".remove").click ->
index = $(#).parent().parent().index();
files.splice index, 1;
$('.file-item').eq(index).remove();
Here is my form file that gets rendered but the upload.js file doesn't get called because it's already loaded on the main page. When the the new form button gets clicked it renders this form in a modal.
- #ticket.errors.full_messages.each do |message|
.error= message
= render 'layouts/standard_flash'
%ZenTicketForm{ title: 'Submit Help Request', :multipart => true, data: { remote: true } }
.col-xs-12.col-sm-12.col-md-12.col-lg-12{style: 'padding:0;'}
.col-xs-12.col-sm-12.col-md-12.col-lg-6
%dl.dl-horizontal
%dt Type
%dd.show-more-container
%ZenSelect#ticket_type{options: ['Questions', 'Incidents', 'Problems', 'Tasks'],
class: 'select2',
placeholder: t('activerecord.placeholders.zen_support/ticket.ticket_type') }
.col-xs-12.col-sm-12.col-md-12.col-lg-12
%dl.dl-horizontal
%dt Subject
%dd.show-more-container
%input.form-control{ type: 'text',
name: 'zen_support_ticket[subject]',
placeholder: t('activerecord.placeholders.zen_support/ticket.subject') }
.col-xs-12.col-sm-12.col-md-12.col-lg-6
%dl.dl-horizontal
%dt Priority
%dd.show-more-container
%ZenSelect#priority{ options: ['Low', 'Normal', 'High', 'Urgent'],
data: { placeholder: "activerecord.placeholders.zen_support/ticket.priority" },
class: 'select2' }
.col-xs-12.col-sm-12.col-md-12.col-lg-12
%dl.dl-horizontal
%dt Comment
%dd.show-more-container
%ZenTextArea#comment{ placeholder: t('activerecord.placeholders.zen_support/ticket.comment'),
error: #zendesk_ticket.errors&.dig(:comment) }
%dl.dl-horizontal
.new-show-less
%button.fileUpload.btn.btn-default#upload_button{type: "button"}
Attach File
%input.upload#file_input{:name => "attachments[]", multiple: true, :type => "file"}
%ul#filelist
You can put the JS code directly inside the js.erb file and it'll only be executed when that partial is rendered.
See more:
https://guides.rubyonrails.org/working_with_javascript_in_rails.html

Dynamic button values from javascript?

I have a page that does a search, using javascript, and I want to take the list of users that it comes up with, and send that as a submit to the next page. What I have, is:
.search_client_users
= form_tag admin_clients_path, method: "get" , class: "search_form" do
= label_tag 'search_term', 'Old domain name:'
= text_field_tag 'search_term', nil, autocomplete: "off", size: "50"
.main_form.client_emails
= simple_form_for(:domainNameSwap, url: { action: "update" }, html: { method: :put }) do |f|
.input-row
= f.hidden_field :users, value: #clients
.submit-row
.row
.col-xs-5
.submit
= f.submit "Update domains", id: "submit", :class => "btn btn-primary submit"
.client_list
- content_for :javascript do
= javascript_include_tag 'admin/search_client_users'
[some of the formatting may not be quite right due to cut and paste, sorry]
The admin/search_client_users creates an #clients, I'm pretty sure, at least, with:
class App.ClientUserList
constructor: ->
#incrementalSearchAttempts = 0
search: (searchTerm, completeCallback) =>
handleResponseWithOrderAwareness = (attemptNumber, response) =>
if attemptNumber >= #incrementalSearchAttempts
completeCallback(response)
#incrementalSearchAttempts++
onComplete = _.partial(handleResponseWithOrderAwareness, #incrementalSearchAttempts)
$.get('/admin/manage_clients/client_list', { search_term: searchTerm }).complete(onComplete)
class App.Views.SearchClientUsers extends Backbone.View
events:
"keyup input[name='search_term']": "search",
"click .profile_attribute": "showClientUserProfile"
initialize: =>
#clientUserList = new App.ClientUserList()
search: =>
searchTerm = $('.search_form input[name=search_term]').val()
#clientUserList.search(searchTerm, #render)
showClientUserProfile: (event) =>
window.location = $(event.currentTarget).closest('tr').data('client-path')
render: (response) =>
#$el.find('.client_list').html(response.responseText)
$ ->
new App.Views.SearchClientUsers(el: $('.search_client_users')).search()
so, I'm trying to take the list of clients, and send it to the update method in the controller. However, due to when javascript and ruby take place, it doesn't seem to be working... is there a way to do this? or do I have to figure out how to do this in Ajax?
ETA: An alternative idea is, I suppose to just turn the initial text_field into a form, so that the text field is used both for the javascript, and THEN submitted to the form, and then the update can re-do the search... My dataset is small enough that doing the search twice is not a huge problem I suppose...
But I'm not quite sure exactly how to merge the two forms...

Laravel and Dropzone - How to get files in server side

I'm trying to use dropzone in laravel project but I can't get the files in server side.
My blade html code:
{!! Form::open(['id' => 'create-intervention-form', 'url' => '/create-intervention', 'method' => 'post', 'class' => '']) !!}
<div id="multimedia" class="data new dropzone">
</div>
<div class="btn-new-bottom">
Criar Intervenção
</div>
{!! Form::close() !!}
In jquery I put this code:
$("div#multimedia").dropzone({
url: "/create-intervention",
paramName: "file", // The name that will be used to transfer the file
maxFilesize: 1024,
autoProcessQueue: false
});
To submit the form I have a jquery function to submit. In controller I try to get $files[] = Input::file('file'); but this return null.
Controller:
public function store(Request $request)
{
$rules = array(
);
// do the validation ----------------------------------
// validate against the inputs from our form
$validator = Validator::make(Input::all(), $rules);
// check if the validator failed -----------------------
if ($validator->fails())
{
// get the error messages from the validator
$messages = $validator->messages();
return redirect()->back()->withErrors($validator)->withInput();
}
else
{
$files[] = Input::file('file');
var_dump($files);
}
};
How can I do this? I want to use dropzone to upload multiple files but just when I submit the form. In controller I have to save each file in directory and file name in database.
Thank you
Add to your form open method 'files' => true
documentation
You can try to get the files thought Request too in a loop:
Controller:
public function store(Request $request)
{
$rules = array();
// do the validation ----------------------------------
// validate against the inputs from our form
$validator = Validator::make(Input::all(), $rules);
// check if the validator failed -----------------------
if ($validator->fails())
{
// get the error messages from the validator
$messages = $validator->messages();
return redirect()->back()->withErrors($validator)->withInput();
}
else
{
foreach( $request->file('file') as $file ){
$filename = $file->store('file');
#saves the file
$array_images_names[] = $filename;
}
var_dump($files);
}
};
JavaScript (allowing to accept multiple files)
var post_url_images = $('#post_url_images').val();
Dropzone.options.frm_drop_images = {
paramName: "file", // The name that will be used to transfer the file
maxFilesize: 1024,
// The configuration we've talked about above
url: post_url_images,
autoProcessQueue: false,
uploadMultiple: true,
parallelUploads: 100,
maxFiles: 100,
// The setting up of the dropzone
init: function() {
var myDropzone = this;
// First change the button to actually tell Dropzone to process the queue.
this.element.querySelector("button[type=submit]").addEventListener("click", function(e) {
// Make sure that the form isn't actually being sent.
e.preventDefault();
e.stopPropagation();
myDropzone.processQueue();
});
// Listen to the sendingmultiple event. In this case, it's the sendingmultiple event instead
// of the sending event because uploadMultiple is set to true.
this.on("sendingmultiple", function() {
// Gets triggered when the form is actually being sent.
// Hide the success button or the complete form.
});
this.on("successmultiple", function(files, response) {
// Gets triggered when the files have successfully been sent.
// Redirect user or notify of success.
});
this.on("errormultiple", function(files, response) {
// Gets triggered when there was an error sending the files.
// Maybe show form again, and notify user of error
});
}
};
Try to use your HTML form as below:
<div class="dropzone dropzone-previews" id="frm_drop_images" class="dropzone" method="post" action="{{ url('/admin/products/upload/image') }}"></div>
<!-- hiddent field to set where to post the images -->
<input type="hidden" name="post_url_images" id="post_url_images" value="{{ url('/create-intervention') }}" >
<div class="btn-new-bottom">
Criar Intervenção (Não precisa usar este botão)
</div>

Symfony2 cascasing dropdown value change via ajax not accepting on submission

I have two entity dropdowns field in my symfony form. On the front end i change the option list of 2nd drop drown using ajax based on the value of first dropdown selected value. and Upon submitting the form i get the error that,
This value is not valid.
below is the code;
/**
* #ORM\ManyToOne(targetEntity="State")
* #ORM\JoinColumn(name="province_id", referencedColumnName="id")
*/
protected $Province;
/**
* #ORM\ManyToOne(targetEntity="District")
* #ORM\JoinColumn(name="district_id", referencedColumnName="id")
*/
protected $District;
and in the form,
->add('domicileDistrict','entity', [
'label' => ucwords('District'),
'class'=>'GeneralBundle\Entity\District',
'required' => true,
'mapped' => true,
'attr' => ['class' => 'form-control'],
'label_attr' => ['class' => 'control-label'],
])
->add('domicileProvince','entity', [
'label' => ucwords('Province'),
'class'=>'GeneralBundle\Entity\State',
'required' => true,
'attr' => ['class' => 'form-control select2'],
'label_attr' => ['class' => 'control-label'],
])
and on front end,
$("#profile_from_type_domicileProvince").change(function() {
var state = $('option:selected', this).val();
getDistrictByState(state);
});
function getDistrictByState(state){
var dict = {
type: "POST",
url: "{{ url('ajax_district_by_stateId') }}?id=" + state,
success: function(e) {
$("#profile_from_type_domicileDistrict option").remove();
$.each(e, function(e, p) {
$("#profile_from_type_domicileDistrict").append($("<option />", {
value: e,
text: p
}));
});
}
};
$.ajax(dict);
}
UPDATE: Add PRE_SUBMIT Event;
After suggestion form #Alsatian, I update my form and add the event as below, but nothing happens on selecting first dropdown.
$builder->addEventListener(FormEvents::PRE_SUBMIT, [$this, 'preSubmitData']);
public function preSubmitData(FormEvent $event){
$form = $event->getForm();
$data = $event->getData();
if (array_key_exists('Province', $data)) {
$state = $data['Province'];
$event->getForm()
->add('District','entity', [
'label' => ucwords('District'),
'class'=>'GeneralBundle\Entity\District',
'required' => true,
'mapped' => true,
'query_builder' => function(DistrictRepository $repository) use ($state) {
$qb = $repository->createQueryBuilder('d')
->andWhere('d.verified = :verified')
->andWhere('d.active = :active')
->setParameter('verified', true)
->setParameter('active', true);
if ($state instanceof State) {
$qb = $qb->where('d.state = :state')
->setParameter('state', $state);
} elseif (is_numeric($state)) {
$qb = $qb->where('d.state = :state')
->setParameter('state', $state);
} else {
$qb = $qb->where('d.state = 1');
}
return $qb;
},
'attr' => ['class' => 'form-control select2'],
'label_attr' => ['class' => 'control-label'],
]);
}
}
I had the same problem.
I wrote a bundle here to deal with "extensible" choice types (also entity or document) :
https://github.com/Alsatian67/FormBundle/blob/master/Form/Extensions/ExtensibleSubscriber.php
How I do it :
Hooking in the form submission process, we can access to the submitted entity by the PRE_SUBMIT FormEvent.
All submitted entity are loaded and are in $event->getData().
Then we have just to take this submitted choices as new 'choices' option for the field.
Caution :
Doing it so it will only validate that the entity submitted exist !
If only a part of the entities are possible choices you have to add a constraint to validate them.
You can also set the choices in the PRE_SUBMIT event, depending on the value of the first dropdown (instead of using all submitted entities).

Categories

Resources