I have two forms, one with uk_inputs and one with international_inputs. When one or more of the uk_inputs are filled out I want it so the international inputs in the other form are disabled.
This currently works when the first uk_input is filled out, but I can't manage to make it work but iterating over all of them with for_each.
The first code snippet is where it works with the first uk_input and the second code snippet is my attempt to iterate over all of them.
apologies if this isn't clear. thanks
$(document).ready(function() {
var uk_input = document.querySelector(".uk_input");
uk_input.onchange = function () {
international_input = document.querySelectorAll(".international_input")
international_input.forEach(function(international) {
international.disabled = uk_input.value
});
}
});
$(document).ready(function() {
var uk_input = document.querySelectorAll(".uk_input");
uk_input.for_each.onchange = function (uk) {
international_input = document.querySelectorAll(".international_input")
uk.international_input.forEach(function(international) {
international.disabled = uk_input.value
});
}
});
<%= fields.input :line_1, input_html: {class: "uk_input"} %>
<%= fields.input :line_2, input_html: {class: "uk_input"} %>
<%= fields.input :line_3, input_html: {class: "uk_input"} %>
<%= fields.input :town, input_html: {class: "uk_input"} %>
<%= fields.input :county, input_html: {class: "uk_input"} %>
<%= fields.input :postcode, input_html: {class: "uk_input"} %>
<%= fields.input :line_1, input_html: {class: "international_input"} %>
<%= fields.input :line_2, input_html: {class: "international_input"} %>
<%= fields.input :line_3, input_html: {class: "international_input"} %>
<%= fields.input :town, label: "City / Region", input_html: {class: "international_input"} %>
<%= fields.input :postcode, label: "Postcode / ZIP Code", input_html: {class: "international_input"} %>
Syntax of a for each function:
The correct syntax of the for each function in JavaScript is:
let uk_inputs = document.querySelectorAll(".uk_inputs");
uk_inputs.forEach(input=>{
input.addEventListener("click",event=>{
//Code you want to run for every uk_inputs class input
})
})
Also, as you can see detailed in the code above, to assign an event listener you must reference the DOM element you want to assign that event. This is a vanilla JavaScript solution. It's exactly the same result as it would be with jQuery.
Here is a functional fiddle. In case you want to check it out.
Adjustments to fit your question:
$(document).ready(function() {
let uk_inputs = document.querySelectorAll(".uk_inputs"),
international = document.querySelectorAll(".international");
const enabledInternational = (enabled) => {
international.forEach(input => {
if (enabled) {
input.removeAttribute("disabled");
} else {
input.setAttribute("disabled", `${enabled}`);
}
})
}
uk_inputs.forEach(input => {
input.addEventListener("change", event => {
enabledInternational(event.target.value === "");
})
})
});
Related
I have an index page where I have to filter Invoices by due_date to prepare them for mass edition. The idea is to keep the submit button disabled until a start_date and end_date have been selected.
I have the following simple_form working with flatpickrJS and I have added data-targets to it's input fields:
<div class="col-md-6 my-2">
<%= simple_form_for :date_params, { url: admin_invoices_batch_edit_index_path, method: :get } do |f| %>
<%= f.input :start_date, as: :string, placeholder: "Start date for filter",
input_html: { data:{ controller: "flatpickr", target: "required",
attributes:{ enableTime: false, enableSeconds: false } } }
%>
<%= f.input :end_date, as: :string, placeholder: "End date for filter", input_html: { data:{ controller: "flatpickr", target: "required",
attributes:{ enableTime: false, enableSeconds: false } }
}
%>
<%= f.button :submit, "Filtrar por fecha" %>
<% end %>
</div>
I also have this other simple_form to select a due_date to which all Invoices will be updated, and I need to keep this form's submit button disabled until all required targets have been selected (that is until a start and end date has been selected in the first form).
<div class="col-md-6 my-2" data-controller="activable">
<%= simple_form_for :due_date, { url: admin_invoices_batch_edit_index_path } do |f| %>
<%= f.input :due_date, as: :string, placeholder: "Nueva fecha de recibo",
input_html: { data:{ controller: "flatpickr",
attributes:{ enableTime: false, enableSeconds: false } } }
%>
<% if params[:date_params].present? %>
<%= hidden_field_tag :start_date, params[:date_params][:start_date] %>
<%= hidden_field_tag :end_date, params[:date_params][:end_date] %>
<% end %>
<%= f.button :submit, "Update Invoices", id: "deactivable-submit", disabled: true %>
<% end %>
</div>
This is my Stimulus controller but I don't know how to check that all requiredTargets have been selected so the disabled button gets enabled.
import { Controller } from 'stimulus';
export default class extends Controller {
static targets = ['deactivable required']
initialize() {
}
connect() {
this.requiredTargets.forEach((element) => {
element.config.onChange.push(function() { } ); })
// check that all required targets have been selected?
}
toggle(){
this.deactivableTargets.toggleAttribute("disabled");
}
}
I'm fairly new to Rails and I've managed to get multiple uploading to work with carrierwave (after about a week). Now I would like to make the uploading process a bit nicer. I'm not sure what's going on but I can't seem to get it working.
My form looks like this:
.edit-container
= simple_form_for #post, html: { multipart: true } do |f|
.edit-form
= f.input :title
= f.input :location, disabled: true
= f.input :price
= f.input :description
= f.input :contact_number, placeholder: "(999) 999-9999"
= f.label "Category"
= f.text_field :category_name, data: {autocomplete_source: Category.order(:name).map(&:name)}, placeholder: "Choose a category"
= f.fields_for :post_attachments do |p|
= p.file_field :image, :multiple => true, name: "post_attachments[image][]"
= f.button :submit
%script
$('#post_location').val("#{request.location.city}, #{request.location.state}")
I've tried doing this:
.edit-container
= simple_form_for #post, html: { multipart: true, class: "dropzone" } do |f|
.edit-form
= f.input :title
= f.input :location, disabled: true
= f.input :price
= f.input :description
= f.input :contact_number, placeholder: "(999) 999-9999"
= f.label "Category"
= f.text_field :category_name, data: {autocomplete_source: Category.order(:name).map(&:name)}, placeholder: "Choose a category"
= f.fields_for :post_attachments do |p|
= p.file_field :image, :multiple => true, name: "post_attachments[image][]"
= f.button :submit
%script
$('#post_location').val("#{request.location.city}, #{request.location.state}")
And this is the result (obviously NOT what I want):
The error message says:
ActionController::UnknownFormat in PostsController#create ActionController::UnknownFormat
Could you walk me through implementing dropzone.js to my application?
Hi have problem with cocoon: https://github.com/nathanvda/cocoon and datetimepicker:http://xdsoft.net/jqplugins/datetimepicker/. When I add through cocoon new nested field my calendar not showing up. I think that I must user cocoon after:insert event in my javascript file but I tried every way and this is not working.
This is my views:
costs.html.haml
= simple_form_for [:partners, #car], url: wizard_path do |f|
= f.simple_fields_for :costs do |cost|
= render 'cost_fields', f: cost
#links
= link_to_add_association '+', f, :costs
= link_to t('cars.back'), previous_wizard_path
= f.submit t('cars.next'), class: 'btn btn-primary'
and my cost_fields partial:
.nested-fields
%table.table.table-striped.table-bordered.dupa
%thead
%th.field
= f.association :cost_type
%th.field
= f.input :netto_price
%th.field
= f.input :document_number
%th.field
= f.association :vat
%th.field
= f.input :type_of_cost
%th.field
= f.input :date, as: :string , :input_html => { :class => 'date' }
= link_to_remove_association "X", f
Any ideas?
As this post eludes, this is because the dynamically added elements are not yet in the DOM.
Try to add a class or id before your nested simple fields (this will already be in the DOM), e.g.:
#container
= f.simple_fields_for :costs do |cost|
= render 'cost_fields', f: cost
Then in your javascript file:
$(document).on('ready page:change', function() {
$('#container').on('cocoon:after-insert', function() {
$('.datetimepicker').datetimepicker();
})
})
Also, I've used this datepicker gem, which allows you to generate a wrapper input/custom date/time fields
= f.input :date, :as => :date_picker
I would like to carry out a validation before saving by determining if a User has filled in a particular field, the Payment amount field below and chosen status = "Closed" before submitting the form. If he does one without the other then the form should not save
Edit page
<%= simple_form_for #invoice, :html => { :class => 'form-horizontal' } do |f| %>
<%= render "shared/error_messages", :target => #invoice %>
<%= f.association :customer, disabled: #invoice.persisted? %>
<%= f.input :due_date, as: :string, input_html: { class: "datepicker" }, disabled: #invoice.persisted? %>
<%= f.input :invoice_date, as: :string, input_html: { class: "datepicker" }, disabled: #invoice.persisted? %>
<%= f.input :payment_method, as: :select, :collection => [['Cash','Cash'],['Cheque','Cheque'],['In-House transfer','In-House transfer'],['Account Ledger','Account ledger']], :selected => ['Cash','Cash'] %>
<%= f.input :reference_no, :label => 'Payment Reference No', as: :string %>
<%= f.input :amount, as: :string %>
<%= f.input :payment_date, as: :string, input_html: {class: "datepicker"} %>
<%= f.input :status, as: :select, collection: Invoice::VALID_STATUS %>
VALID_STATUS = [ 'Draft', 'Open', 'Closed', 'Void' ] in Invoice.rb
I would like that if the user changes the Status to Closed he should have entered an amount in the form. A user should not be able to change status to closed without entering an amount
In the model (app/models/invoice_model.rb) put
validate :close_must_have_amount
Then define it (same file)
def close_must_have_amount
:status == 'closed' && :amount # May need to tweak this
end
To have the model level validations applied client side you can use
https://github.com/bcardarella/client_side_validations/
1) Javascript Form Validation is generally done by names.
function ValidateForm(){
var form = document.forms['myForm'];
if ((form['status'].value == "Closed") && !(form['amount'].value)){
alert("You gave a 'Closed' status value, but did not provide an amount, please rectify this problem!");
return(false);
} else {
return(true);
}
}
And then:
<%= simple_form_for #invoice, :onsubmit => "ValidateForm();", :html => { :class => 'form-horizontal', :name => 'myForm' } do |f| %>
<%= f.input :amount, :html => { :name => 'amount'}, as: :string %>
<%= f.input :status, as: :select, :html => { :name => 'status'}, collection: Invoice::VALID_STATUS %>
A brief walkthrough onSubmit triggers when a form is submitted, but before it is actually posted to the server.
A javascrtipt function that is trigered by an event and terminates with return(false); will immediately terminate the event, while return(true); (or pretty much anything else really) makes the event continue as planned.
Finally, be aware that relying exclusively on client side validation is a terrible idea, as a determined user could do something like:
1) Make a perfectly legitimate submission with firebug open and inspect the headers etc.
2) Craft their own HTTP request containing bogus/bad data.
3) Submit it through any one of the myriad HTTP tools.
Clientside Validation is a "nice to have".
Serverside Validation is a "must have".
If you want to do it in client side:
<script>
$(document).ready(function(){
$('#status').change(function(){
if($(this).val() == "Closed" && ($('#amount').val() == null || $('#amount') == "")){
alert("Amount must be needed when status is closed")
}
});
});
</script>
In my view, I have the following:
<%= select("event", :event_id, events_ids_titles_hash, { :include_blank => true, :onchange => "alert_me_test()" }) %>
alert_me_test() is:
<script type="text/javascript">
function alert_me_test()
{
alert ("this is a test")
}
</script>
The dropdown is appearing fine, but when I select from it, nothing happens. I'm expecting an alert box with "this is a test" in it.
The Edit case:
When I'm doing an edit, I have the following code:
<% if #panel.event_id %>
<%= select("panel", :event_id, events_ids_titles_hash, {:selected => #panel.event_id}, { :include_blank => true}) %>
My IDE (RubyMine) does not want to accept the "onchange" as an additional argument, and putting it inside one of the :selected or :include_blank argument hashes does not produce an error, but it does not work either
What ended up working for both new and edit:
<% if #panel.event_id %>
<%= 'Event is ' + events_ids_titles_hash.key(#panel.event_id) %>
<%= select("panel", :event_id, events_ids_titles_hash, {:selected => #panel.event_id}, { :include_blank => true, :onchange => "alert_me_test()"}) %>
<% else %>
<%= 'Select Event from list' %>
<%= select("event", :event_id, events_ids_titles_hash, { :include_blank => true }, { :onchange => "alert_me_test()" }) %>
<% end %>
<%= select("event", :event_id, events_ids_titles_hash, { :include_blank => true, :onchange => "alert_me_test()" }) %>
Worked for me, but I must say that you are fighting against the current with this one. Rails follows UJS, which means your even handlers should be separate from your HTML. In this case the select would be the same minus the onclick and then the script would be
<script type="text/javascript">
$('select').change(alert_me_test);
function alert_me_test(){
...
}
</script>
You don't have to do things this way, but it makes it clearer when looking at a script where your event calls are coming from.
I believe you need to set the :onchange as an HtmlOption, which is a 4th parameter:
<%= select("event", :event_id, events_ids_titles_hash, { :include_blank => true}, {:onchange => "alert_me_test()" }) %>