import { FormlyFieldConfig } from './core'; export function getFieldId(formId: string, options: FormlyFieldConfig, index: string|number) { if (options.id) return options.id; let type = options.type; if (!type && options.template) type = 'template'; return [formId, type, options.key, index].join('_'); } export function getKeyPath(field: {key?: string|string[], fieldGroup?: any, fieldArray?: any}): (string|number)[] { /* We store the keyPath in the field for performance reasons. This function will be called frequently. */ if (field['_formlyKeyPath'] !== undefined) { return field['_formlyKeyPath']; } let keyPath: (string|number)[] = []; if (field.key) { /* Also allow for an array key, hence the type check */ let pathElements = typeof field.key === 'string' ? field.key.split('.') : field.key; for (let pathElement of pathElements) { if (typeof pathElement === 'string') { /* replace paths of the form names[2] by names.2, cfr. angular formly */ pathElement = pathElement.replace(/\[(\w+)\]/g, '.$1'); keyPath = keyPath.concat(pathElement.split('.')); } else { keyPath.push(pathElement); } } for (let i = 0; i < keyPath.length; i++) { let pathElement = keyPath[i]; if (typeof pathElement === 'string' && stringIsInteger(pathElement)) { keyPath[i] = parseInt(pathElement); } } } field['_formlyKeyPath'] = keyPath; return keyPath; } function stringIsInteger(str: string) { return !isNullOrUndefined(str) && /^\d+$/.test(str); } export function getFieldModel(model: any, field: FormlyFieldConfig, constructEmptyObjects: boolean): any { let keyPath: (string|number)[] = getKeyPath(field); let value: any = model; for (let i = 0; i < keyPath.length; i++) { let path = keyPath[i]; let pathValue = value[path]; if (isNullOrUndefined(pathValue) && constructEmptyObjects) { if (i < keyPath.length - 1) { /* TODO? : It would be much nicer if we could construct object instances of the correct class, for instance by using factories. */ value[path] = typeof keyPath[i + 1] === 'number' ? [] : {}; } else if (field.fieldGroup) { value[path] = {}; } else if (field.fieldArray) { value[path] = []; } } value = value[path]; if (!value) { break; } } return value; } export function assignModelValue(model, path, value) { if (typeof path === 'string') { path = path.split('.'); } if (path.length > 1) { const e = path.shift(); if (!model[e]) { model[e] = isNaN(path[0]) ? {} : []; } assignModelValue(model[e], path, value); } else { model[path[0]] = value; } } export function getValueForKey(model, path) { if (typeof path === 'string') { path = path.split('.'); } if (path.length > 1) { const e = path.shift(); if (!model[e]) { model[e] = isNaN(path[0]) ? {} : []; } return getValueForKey(model[e], path); } else { return model[path[0]]; } } export function getKey(controlKey: string, actualKey: string) { return actualKey ? actualKey + '.' + controlKey : controlKey; } export function reverseDeepMerge(dest, source = undefined) { let args = Array.prototype.slice.call(arguments); if (!args[1]) { return dest; } args.forEach((src, index) => { if (!index) { return; } for (let srcArg in src) { if (isNullOrUndefined(dest[srcArg]) || isBlankString(dest[srcArg])) { if (isFunction(src[srcArg])) { dest[srcArg] = src[srcArg]; } else { dest[srcArg] = clone(src[srcArg]); } } else if (objAndSameType(dest[srcArg], src[srcArg])) { reverseDeepMerge(dest[srcArg], src[srcArg]); } } }); return dest; } export function isNullOrUndefined(value) { return value === undefined || value === null; } export function isBlankString(value) { return value === ''; } export function isFunction(value) { return typeof(value) === 'function'; } export function objAndSameType(obj1, obj2) { return isObject(obj1) && isObject(obj2) && Object.getPrototypeOf(obj1) === Object.getPrototypeOf(obj2); } export function isObject(x) { return x != null && typeof x === 'object'; } export function clone(value) { if (!isObject(value)) { return value; } return Array.isArray(value) ? value.slice(0) : Object.assign({}, value); } export function evalStringExpression(expression: string, argNames: string[]) { try { return Function.bind.apply(Function, [void 0].concat(argNames.concat(`return ${expression};`)))(); } catch (error) { console.error(error); } } export function evalExpressionValueSetter(expression: string, argNames: string[]) { try { return Function.bind .apply(Function, [void 0].concat(argNames.concat(`${expression} = expressionValue;`)))(); } catch (error) { console.error(error); } } export function evalExpression(expression: string | Function | boolean, thisArg: any, argVal: any[]): boolean { if (expression instanceof Function) { return expression.apply(thisArg, argVal); } else { return expression ? true : false; } }