Skip to content

Instantly share code, notes, and snippets.

@abinoam
Created July 22, 2024 17:11
Show Gist options
  • Save abinoam/334379c37c13dc4f5646196a4fdf9543 to your computer and use it in GitHub Desktop.
Save abinoam/334379c37c13dc4f5646196a4fdf9543 to your computer and use it in GitHub Desktop.
IMasks through Stimulus (Hotwire)
# app/views/price_versions/_form.html.erb
# Shorted to only the main parts.
# I hook into the stimulus controller with "html: { data: { controller: :imask } }" at the form.
# I trigger the mask in each input field by using "as: masked_priced" (that will be rendered by MaskedPriceInput custom SimpleForm input.
<%= simple_form_for [versionable, price_version],
wrapper: :half_horizontal_form_bs5,
html: { data: { controller: :imask } } do |f| %>
<%= f.simple_fields_for :size_prices, size_prices do |spf| %>
<%= spf.input_field :value, as: :masked_price, class: 'form-control' %>
<% end %>
<% end %>
# app/javascript/controllers/imask_controller.js
import { Controller } from "@hotwired/stimulus"
// Connects to data-controller="imask"
export default class extends Controller {
static targets = ['price'];
connect() {
// console.log('Connected to imask controller at element: ', this.element);
}
priceTargetConnected(element) {
this.#maskPrice(element);
}
#maskPrice(element) {
const maskOptions = {
mask: Number, // enable number mask
// other options are optional with defaults below
scale: 2, // digits after point, 0 for integers
thousandsSeparator: '.', // any single char
padFractionalZeros: true, // if true, then pads zeros at end to the length of scale
normalizeZeros: true, // appends or removes zeros at ends
radix: ',', // fractional delimiter
mapToRadix: ['.'], // symbols to process as radix
// additional number interval options (e.g.)
min: 0,
max: 99999.99,
autofix: false, // if true it jumps back to 99999 when exceeds max
};
IMask(element, maskOptions);
}
}
# app/inputs/masked_price_input.rb
# As I was already using a custom SimpleForm input
# I made it inject "data-imask-target='price'" into each field to be masked.
class MaskedPriceInput < SimpleForm::Inputs::Base
include ActionView::Helpers::NumberHelper
def input(wrapper_options)
merged_input_options = merge_wrapper_options(input_html_options, wrapper_options)
original_value = object.send(attribute_name)
if original_value
merged_input_options[:value] = number_to_currency(original_value, unit: "").strip
end
merged_input_options["data-imask-target"] = :price
"#{@builder.text_field(attribute_name, merged_input_options)}".html_safe
end
def input_html_classes
super.push('masked-price')
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment