Creating Input masking component using Ember-modifier

AbulAsar S.AbulAsar S.
8 min read

If you are an Ember dev you may have come across handlebars element like {{on}} (which was introduced in Ember Octane). It is nothing but modifiers. It is very similar to helpers in handlebars. It is available in two flavorsclass based and function based modifiers. In this blog, we are going to create a simple function-based modifier.

What are we going to build? 🤔

We are going to create an input masking component, which will take the input pattern value from the user (as per the pattern mentioned in the input definition) and render the input as per provided pattern. Refer to the diagram below to get an idea of what we are going to get as a final product.

input-masking

The component usage would be something like this:

<InputMasking @value={{this.myValue}} @pattern="99999-9999" />

How function based modifier works?

  • As per GitHub documentation of ember-modifier, Modifiers are a basic primitive for interacting with the DOM in Ember.
  • It helps you to interact and manipulate DOM.
  • This modifier runs the first time when the element the modifier was applied to is inserted into the DOM, and it also tracks the changes while running. It tracks changes including the arguments it receives, and if any of them changes, the function will run again.
  • A Function-based modifiers take 3 parameters:
    • The element
    • An array of positional arguments
    • An object of named arguments
  • Something like this
    export default modifier(function maskInput(element/*, params, hash*/) {
    
  • The first param i.e element it is nothing but the DOM element on which you are going to apply some changes.

Example:

  • The on modifier helps you to apply event listener on the element you are applying.
  • Say, you want to apply focus on the input tag. You can add on something like this
    <Input {{on 'focus' this.handler}} />
    
  • The on modifier applies an event listener like this behind the scene.
    document.getElementById('yourInput').addEvent('focus', this.handler)
    
  • Similarly, if you want to create your own custom modifier, ember-modifier helps you create one.
  • Suppose, if you are creating a modifier say do-something. It can be used something like this
    <Button {{do-something 'param1 param2'}} > Click </Button>
    
  • In modifier doSomething(element, params, hash), the first parameter element is nothing but DOM element on which we are applying this modifier and params are nothing but the passed parameters.
  • We will look into its work in the following input-masking example.

Let's create one!!

  • First of all, I am assuming you have one running ember application of at least v3.12. If not create one ember new my-ember-project.
  • Why v3.12? Because for making use of modifier we have to install an ember plugin called ember-modifier which has this basic requirement.
  • So, let's install ember-modifier by running ember install ember-modifier in your terminal.
  • Now we are going to create a component input-masking. For this we will create app/templates/components/input-masking.hbs and app/components/input-masking.js.
  • Add some code in the template file of the component.
    <Input @value='' />
    
  • As per our requirement user should enter the telephone of the format 4137-4224 in the input. But we don't want the user to specifically add - in between the numbers for consistency. Our component should be smart enough to add - after four numbers.
  • We could write a simple regex in some handler event instead, we are going to use an npm package to make our work easier.
  • The npm package we are going to use is called inputmask.
  • So, we will install this plugin npm install inputmask --save.
  • inputmask plugin is not an ember plugin, so to use any npm package without any configuration there is a plugin called ember-auto-import.
  • This plugin will help you to directly import inputmask. Something like this
    import Inputmask from 'inputmask';
    
  • Now we will create a modifier mask-input. Run ember g modifier mask-input. This will generate a file called mask-input inside modifiers folder with some pre-generated code.
    import { modifier } from 'ember-modifier';
    export default modifier(function maskInput(element, params/*, hash*/) {
    });
    
  • It's usage will be something like in our InputMasking component.
    <Input {{mask-input}} @value='' />
    
  • As per usage of Inputmask plugin. We need to create an instance of it and passed the pattern we want to apply to our element. So, will import Inputmask into our modifier file and create an instance of it.
    import { modifier } from 'ember-modifier';
    import Inputmask from 'inputmask';
    export default modifier(function maskInput(element, params/*, hash*/) {
     const im = Inputmask('9999-9999');  //this is the instance of Inputmask
     im.mask(element);
    });
    
  • We will apply the pattern of our choice where we want the input of length 9, with a dash after the fourth number and all should be number. The 9 represent number(Please refer input-mask` documentation for further configurations).
  • After creating an instance of inputmask, we will pass the element.
  • As per the behavior of modifier, it will continuously keep track of the input we pass.
  • Everything looks fine except one thing. Right now, we have hard-coded the pattern during the instantiation of inputmask. It should be as per the value passed to the component.
  • In our component template file we will pass @pattern value. Add the following changes:

    <Input {{mask-input @pattern}} @value='' />
    
  • The passed pattern in the modifier will be received as the second parameter in the modifier js file. We receive that change and passed to the Inputmask instance.

export default modifier(function maskInput(element, params/*, hash*/) {
   const [pattern] = params;      // receive pattern 
   const im = Inputmask({ mask: pattern}); // pass the pattern here.
   im.mask(element);
});

Final Usage:

<Form>
   <Label> Telephone </Label>
   <InputMasking @value={{this.telephone}} @pattern="99999-9999" />

   <Label> Credit Card </Label>
   <InputMasking @value={{this.creditCard}} @pattern="9999-9999-9999-9999 />
   .....
</Form>

I hope you like this blog. If you have any questions then please comment below.

References:

10
Subscribe to my newsletter

Read articles from AbulAsar S. directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

AbulAsar S.
AbulAsar S.

I am a Software Engineer from Mumbai, India. In love with Functional programming ( precisely Elixir). Love to share the knowledge that I learn while developing things.