8

I want to format both phone and credit card input using cleave.js (in rails). I've got the formatting working if I only declare one new Cleave object, but I get this error if I attempt to declare two:

Uncaught Error: [cleave.js] Please check the element

Here's the relevant parts of the JS file:

var Global = {};

Global.onLoad = function(){
  Global.setupDatepickers(); //unrelated function
  Global.setupCleavePhone();
  Global.setupCleaveCreditCard();
};

$(document).on('turbolinks:load', function(){
  Global.onLoad();
});

Global.setupCleavePhone = function() {
  new Cleave('.phone-input', {
    phone: true,
    phoneRegionCode: 'US',
    delimiter: '-'
  });
}

Global.setupCleaveCreditCard = function() {
  new Cleave('.card-input', {
    delimiter: '-',
    blocks: [4,4,4,4]
  });
}

I've tried a few remixes of this including assigning the Cleave objects to variables and declaring them in the same function, but no dice. Here's a jsfiddle of multiple cleave objects being delared at once, and I can't see any meaningful differences between my code and theirs. The selector classes are properly applied in the view. Any thoughts why I can't seem to format two fields at once?

Nic
  • 13,287
  • 7
  • 40
  • 42
Daniel Grimes
  • 333
  • 2
  • 9

4 Answers4

12

SOLVED:

As it turned out it needs the objects to exist in order to run new Cleave. If one of the elements doesn't exist on the page, the whole thing fails for some reason. I ended up going with wrapping each new Cleave, checking if an element with that class existed or not, for example:

if ($('.card-input').length) {
  new Cleave('.card-input', {
    delimiter: '-',
    blocks: [4,4,4,4]
  });
}

UPDATE:

Or even better, if you're like me and need to format more than one object of the same class on a page (which causes cleave to only format the first one with the code above) retrieve the array of objects and run cleave on each. It performs the same 'does it exist' check as well as formatting each object. For example:

for(let field of $('.zip_code').toArray()){
  new Cleave(field, {
    numericOnly: true,
    delimiter: ' ',
    blocks: [5,4]
  });
}

UPDATE AGAIN:

So as it turns out the above is less than ideal because, as I understand it, the above let-of loop (like for-in loops) will iterate across the enumerable objects of an array, instead of just over its indices. Have a look at this answer if you too would like interpret what that's about: For-each over an array in JavaScript?.

As well, I couldn't precompile my assets for production becasue it hated the use of let, and while changing let-of to for-in also worked, I ended up going with the more specific forEach loop.

$('.zip-code').toArray().forEach(function(field){
   new Cleave(field, {
      numericOnly: true,
      delimiter: ' ',
      blocks: [5,4]
   })
});
Daniel Grimes
  • 333
  • 2
  • 9
1

this should work as well

$('.zip-code').each(function (index, ele) {
    var cleaveCustom = new Cleave(ele, {
        numericOnly: true,
        delimiter: ' ',
        blocks: [5, 4]
    });
});
irfandar
  • 1,690
  • 1
  • 23
  • 24
0

If you enable only one each time it works? I mean only enable .card-input and then only enable .-phone-input ?

Jacopo Beschi
  • 178
  • 2
  • 6
0

I solved the issue with multiple inputs like this:

$(parentElement).find('[data-cleave]').each(function (i,e) {
                var opt;
                switch ($(e).attr('data-cleave')) {
                    case 'phone': opt = {numericOnly:true,blocks:[12],prefix:'+7'};break;
                    case 'inn': opt = {numericOnly:true,blocks:[12]};break;
                    case 'passport': opt = {numericOnly:true,blocks:[4,6],delimeter:'-'};break;
                    /* e.t.c. */
                    default: opt = {numericOnly:true,blocks:[12],prefix:'+'};break;
                }
                new Cleave('[data-cleave-id="'+$(e).attr('data-cleave-id')+'"]',opt);
            });

and include a input element new attributes:

data-cleave="phone/inn/passport/etc"
data-cleave-id="<?=hash(md5,rand(1,2048))?>"

JSFiddle

Mordent
  • 1
  • 1