Add imaskjs with rails and hotwire stimulus but it doesn't work

414 Views Asked by At

I'm trying to make stimulus controller to mask 2 input field, "gross revenue" and "operating cost" to display thousand separator on both fields. I've tried imaskjs with stimulusjs, but I don't know why it doesn't werk at all.

<div class='' data-controller="currency">

    <%= f.label :gross_revenue %>

    <%= f.number_field :gross_revenue, class: '', data: { currency_target: "gross" } %>

  </div>

Below is my controller

import { Controller } from "@hotwired/stimulus"

import IMask from "imask"


// data-controller="currency"

export default class extends Controller {
  static targets = [ "currency" ]

  connect() {

    this.mask = IMask(this.currencyTarget, { 
      mask: Number,
      thousandsSeparator: ',',
    });

  }

  disconnect() {

    this.mask?.destroy();

  }

}
2

There are 2 best solutions below

1
On

You can't use number field:

Please note
If you apply mask to input element you have to use type="text". Other types are not supported.

https://imask.js.org/guide.html

<div data-controller="currency">
  <%= f.text_field :gross_revenue, data: { currency_target: "gross" } %>
  <!-- NOTE: target name is "gross"                          ^^^^^ -->
</div>

Fix target name (you should rename it to something more generic as well):

import { Controller } from "@hotwired/stimulus";
import IMask from "imask";

export default class extends Controller {
  static targets = ["gross"];

  connect() {
    this.mask = IMask(this.grossTarget, {
      mask: Number,
      thousandsSeparator: ",",
    });
  }
}

You can also use just the controller element:

<%= f.text_field :gross_revenue, data: {
  controller: "mask",
  mask_type_value: "currency"
} %>
// app/javascript/controllers/mask_controller.js

import { Controller } from "@hotwired/stimulus";
import IMask from "imask";

const maskOptions = {
  currency: { mask: Number, thousandsSeparator: "," },
};

export default class extends Controller {
  static values = { type: String };

  connect() {
    IMask(this.element, maskOptions[this.typeValue]);
  }
}
0
On

Alex's answer is the best!

In case you guys encounter problem when tryin to save masked value, you can also put code below to your {model}.rb (I assume we still use Rails 7 and :gross_revenue field/ column for example)

def gross_revenue=(val)
   write_attribute :gross_revenue, val.to_s.gsub(/\D/, '').to_i
end

CMIIW, but hope this helps!