Skip to content

Create a custom field type for app development

Brett Newman edited this page Mar 28, 2016 · 9 revisions

Home > Knowledge Base > Custom Field Type

Creates a simple credit card field type

NOTE - does not translate to AdminUI at the current time. Can only be used for app development.

install credit-card
npm i credit-card

Create the custom type

creditcardType.js

var keystone = require('keystone');
var util = require('util');
var CC = require('credit-card');

/*
    Custom FieldType Constructor
    @extends Field
    @api public
*/
function creditcard(list, path, options) {
    // add your options to this
    // call super_  
    this._nativeType = Number;
    creditcard.super_.call(this, list, path, options);  
}
/* inherit Field */
util.inherits(creditcard, keystone.Field);    

/* override or add methods */

// validate the input for correct card number
// for 0.3.x you can use function(data, required, item)
creditcard.prototype.validateInput = function(data) {
	console.log('validate credit card');
	var value = this.getValueFromData(data);
	if (value === undefined) {
        return true;
	}
	var type = CC.determineCardType(value);
	if(value === null) {
        return false;
	}
	
	return CC.isValidCardNumber(value, type); 
  
};

/* Export Field Type */ 
module.exports = creditcard;

Add your model

Note we add our custom Field Type as hidden: true. Custom types do not currently translate to the Admin UI.

var keystone = require('keystone');
var Types = keystone.Field.Types;

var Post = new keystone.List('Post', {
	map: { name: 'title' },
	autokey: { path: 'slug', from: 'title', unique: true },
	sortable: 'unshift',
	perPage: 5,
	track: true,
	autocreate: true
});

Post.add({
    title: { type: Types.Text, required: true, initial: true, default: 'Title' },
    creditCard: { type: Types.CreditCard, label: 'Credit Card', hidden: true },
});

Post.register();

Add the new Type to the keystone.Field.Types object in your start file

// Require keystone
var keystone = require('keystone');

// add a new custom Field Type
Object.defineProperty(
	keystone.Field.Types,
	'CreditCard',
	{ 
		get: function() {
			return require('./creditcardType.js');
		} 
	}
);

keystone.init({
	'name': 'test34',
	'brand': 'My Site',
	'port': 4000,
	'auth': true,
	'user model': 'User',
	'cookie secret': '`l(tz:tNeX4=U.BHtJUzpDD@>swfti,K!;)eCkfLJBBlx9-{Me^mOe,2xlr#])Cd'
});

// Load your project's Models
keystone.import('models');

keystone.start();

Use the new field type in your app

In order to take advantage of your new methods we must use getUpdateHandler

var keystone = require('keystone');

keystone.list('Post')
	.model
	.findOne({'title': 'Title'})
	.exec( function(err, doc) {
		if(!doc) {
			console.log('No doc');
			return;
		}
               
        // if you use user tracking in your db we need to have user on the req 
		// object or add the user to our submitted fields as _req_user: userObject
		var req = {
			user: { 
				_id: "568b7ad68d07a2df048aba34" 
			}
		}
		doc.getUpdateHandler(req)
			.process(
				{ creditCard: '4111111111111111'},
				{ flashErrors: false, logErrors: true },
				function (err) {
					if (err) {
						return console.log(err);
					}
				console.log('doc saved');
				}
			);
	});

Any errors will return like so

{ 
    message: 'Validation failed',
    name: 'ValidationError',
    errors: { 
        creditCard: { 
            name: 'ValidatorError',
            path: 'creditCard',
            message: 'Please enter a valid creditcard in the Credit Card field',
            type: 'required' 
        } 
    } 
}