Skip to content

Instantly share code, notes, and snippets.

@sibelius
Last active February 25, 2020 12:43
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save sibelius/c564ded5bfd39534cf035e0460f2ee9a to your computer and use it in GitHub Desktop.
Save sibelius/c564ded5bfd39534cf035e0460f2ee9a to your computer and use it in GitHub Desktop.
import React from 'react';
import {
View,
Text,
} from 'react-native';
import { TextInputMask } from 'react-native-masked-text'
export default function maskedInputTemplate(locals) {
if (locals.hidden) {
return null;
}
const stylesheet = locals.stylesheet;
let formGroupStyle = stylesheet.formGroup.normal;
let controlLabelStyle = stylesheet.controlLabel.normal;
let textboxStyle = stylesheet.textbox.normal;
let helpBlockStyle = stylesheet.helpBlock.normal;
const errorBlockStyle = stylesheet.errorBlock;
if (locals.hasError) {
formGroupStyle = stylesheet.formGroup.error;
controlLabelStyle = stylesheet.controlLabel.error;
textboxStyle = stylesheet.textbox.error;
helpBlockStyle = stylesheet.helpBlock.error;
}
if (locals.editable === false) {
textboxStyle = stylesheet.textbox.notEditable;
}
const label = locals.label ? <Text style={controlLabelStyle}>{locals.label}</Text> : null;
const help = locals.help ? <Text style={helpBlockStyle}>{locals.help}</Text> : null;
const error = locals.hasError && locals.error ? <Text accessibilityLiveRegion="polite" style={errorBlockStyle}>{locals.error}</Text> : null;
let maskType = 'money';
let maskOptions = {};
if (locals.config) {
if (locals.config.mask) {
maskType = locals.config.mask;
}
if (locals.config.options) {
maskOptions = locals.config.options;
}
}
return (
<View style={formGroupStyle}>
{label}
<TextInputMask
type={maskType}
options={maskOptions}
accessibilityLabel={locals.label}
ref="input"
autoCapitalize={locals.autoCapitalize}
autoCorrect={locals.autoCorrect}
autoFocus={locals.autoFocus}
blurOnSubmit={locals.blurOnSubmit}
editable={locals.editable}
keyboardType={locals.keyboardType}
maxLength={locals.maxLength}
multiline={locals.multiline}
onBlur={locals.onBlur}
onEndEditing={locals.onEndEditing}
onFocus={locals.onFocus}
onLayout={locals.onLayout}
onSelectionChange={locals.onSelectionChange}
onSubmitEditing={locals.onSubmitEditing}
placeholderTextColor={locals.placeholderTextColor}
secureTextEntry={locals.secureTextEntry}
selectTextOnFocus={locals.selectTextOnFocus}
selectionColor={locals.selectionColor}
numberOfLines={locals.numberOfLines}
underlineColorAndroid={locals.underlineColorAndroid}
clearButtonMode={locals.clearButtonMode}
clearTextOnFocus={locals.clearTextOnFocus}
enablesReturnKeyAutomatically={locals.enablesReturnKeyAutomatically}
keyboardAppearance={locals.keyboardAppearance}
onKeyPress={locals.onKeyPress}
returnKeyType={locals.returnKeyType}
selectionState={locals.selectionState}
onChangeText={(value) => locals.onChange(value)}
onChange={locals.onChangeNative}
placeholder={locals.placeholder}
style={textboxStyle}
value={locals.value}
/>
{help}
{error}
</View>
);
}
@sibelius
Copy link
Author

Usage

const options = {
      fields: {
        price: {
          template: MaskedInputTemplate,
          config: {
            mask: 'money',
          },
        },
      },
    };

@jmpridgen
Copy link

This worked really well for me. However, I wanted the value that was submitted in my form to be different than the value in the masked input. I ended up wrapping this template inside of a factory and using a transformer to change the value when the form is submitted. My particular application was a phone number. For anyone else that has used this they can use the below code as a reference. I am open to suggestions for different ways to achieve this as well.

Options for the form:

phoneNumber: {
      factory: MaskedInputFactory,
      transformer: {
        format: (value) => value,
        parse: (str) => str ? phoneFormatter.normalize(str) : '',
      },
      config: {
        mask: 'custom',
        options:{
          mask: '(999)-999-9999',
        }
      },
    },

Relevant snippet from the factory definition

import tcomb from "tcomb-form-native"
var Component = tcomb.form.Component;

export default class MaskedInputFactory extends Component {
  getTemplate() {
    return MaskedInputTemplate
  }
}

@sibelius
Copy link
Author

you can use getRawValue of TextInputMask

@alfarioekaputra
Copy link

@sibelius, any example how to use getRawValue?

@jonathonlui
Copy link

@alfarioekaputra one way to use getRawValue is in your factory. You can use the getLocals to modify onChange so it returns the raw value.

export default class MaskedInputFactory extends Component {
  getTemplate() {
    return MaskedInputTemplate
  }

  getLocals() {
    const locals = super.getLocals();
    const { onChange } = locals;
    // eslint-disable-next-line react/no-string-refs
    locals.onChange = () => onChange(this.refs.input.getRawValue());
    return locals;
  
}

Since you're using a custom mask you'll need to define a custom getRawValue which takes the place of the transformer

  phoneNumber: {
    factory: MaskedInputFactory,
    config: {
      mask: 'custom',
      options:{
        mask: '(999)-999-9999',
        getRawValue: (str) => str ? phoneFormatter.normalize(str) : '',
      }
    },
  },

@pandrebarbosa
Copy link

@sibelius, how to get the ref of a masked field?

@Otik133040040
Copy link

Otik133040040 commented May 21, 2019

@sibelius, how to get the ref of a masked field?

anyone can solve this?

@Otik133040040
Copy link

when value is already fill (default value) from tcomb-form-native, when submit value from mask is null, how to solve this?

@sibelius
Copy link
Author

Use Formik instead

@Otik133040040
Copy link

Use Formik instead

mean use transformers and factory from tcomb-form-native?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment