smart-webcomponents
Version:
Web Components & Custom Elements for Professional Web Applications
435 lines (372 loc) • 11.1 kB
JSX
import React from "react";
import ReactDOM from 'react-dom/client';
import { FormControl } from './formcontrol';
import { FormGroup } from './formgroup';
export { FormControl } from './formcontrol';
export { FormGroup } from './formgroup';
/**
Reactive Form Component with Advanced Validation
*/
export class Form extends React.Component {
// Gets the id of the React component.
get id() {
if (!this._id) {
this._id = 'Form' + Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
}
return this._id;
}
/** Sets or gets the form columns.
* Property type: number
*/
get columns() {
return this.nativeElement ? this.nativeElement.columns : undefined;
}
set columns(value) {
if (this.nativeElement) {
this.nativeElement.columns = value;
}
}
/** Sets or gets the form controls.
* Property type: Control[]
*/
get controls() {
return this.nativeElement ? this.nativeElement.controls : undefined;
}
set controls(value) {
if (this.nativeElement) {
this.nativeElement.controls = value;
}
}
/** Sets or Gets the labels position.
* Property type: {(value: string): void}
*/
get onStatusChanges() {
return this.nativeElement ? this.nativeElement.onStatusChanges : undefined;
}
set onStatusChanges(value) {
if (this.nativeElement) {
this.nativeElement.onStatusChanges = value;
}
}
/** Makes the form readonly.
* Property type: {(value: any): void}
*/
get onValueChanges() {
return this.nativeElement ? this.nativeElement.onValueChanges : undefined;
}
set onValueChanges(value) {
if (this.nativeElement) {
this.nativeElement.onValueChanges = value;
}
}
/** Shows / hides the colon after the labels.
* Property type: FormLabelPosition | string
*/
get labelPosition() {
return this.nativeElement ? this.nativeElement.labelPosition : undefined;
}
set labelPosition(value) {
if (this.nativeElement) {
this.nativeElement.labelPosition = value;
}
}
/** Shows / hides validation summary.
* Property type: boolean
*/
get readonly() {
return this.nativeElement ? this.nativeElement.readonly : undefined;
}
set readonly(value) {
if (this.nativeElement) {
this.nativeElement.readonly = value;
}
}
/** Gets the Form's status. Each member in the status has { dirty, untouched, disabled } properties.
* Property type: boolean
*/
get showColonAfterLabel() {
return this.nativeElement ? this.nativeElement.showColonAfterLabel : undefined;
}
set showColonAfterLabel(value) {
if (this.nativeElement) {
this.nativeElement.showColonAfterLabel = value;
}
}
/** Gets or Sets the Form value.
* Property type: boolean
*/
get showSummary() {
return this.nativeElement ? this.nativeElement.showSummary : undefined;
}
set showSummary(value) {
if (this.nativeElement) {
this.nativeElement.showSummary = value;
}
}
/** Automatically validates the form when it is created.
* Property type: any
*/
get status() {
return this.nativeElement ? this.nativeElement.status : undefined;
}
set status(value) {
if (this.nativeElement) {
this.nativeElement.status = value;
}
}
/** undefined
* Property type: any
*/
get value() {
return this.nativeElement ? this.nativeElement.value : undefined;
}
set value(value) {
if (this.nativeElement) {
this.nativeElement.value = value;
}
}
/** undefined
* Property type: boolean
*/
get validateOnLoad() {
return this.nativeElement ? this.nativeElement.validateOnLoad : undefined;
}
set validateOnLoad(value) {
if (this.nativeElement) {
this.nativeElement.validateOnLoad = value;
}
}
// Gets the properties of the React component.
get properties() {
return ["columns","controls","onStatusChanges","onValueChanges","labelPosition","readonly","showColonAfterLabel","showSummary","status","value","validateOnLoad"];
}
// Gets the events of the React component.
get eventListeners() {
return [];
}
/** Adds a control to the Form.
* @param {any} controlOptions. Control options. The control options description is available in the <em>controls</em> property.
*/
addControl(controlOptions){
if (this.nativeElement.isRendered) {
this.nativeElement.addControl(controlOptions);
}
else
{
this.nativeElement.whenRendered(() => {
this.nativeElement.addControl(controlOptions);
});
}
}
/** Gets a control by its name(dataField).
* @param {string} dataField. dataField of a FormControl or FormGroup
* @returns {Control}
*/
getControl(dataField) {
const result = this.nativeElement.getControl(dataField);
return result;
}
/** Inserts a control to the Form.
* @param {number} index. Control insert index
* @param {any} controlOptions. Control options. The control options description is available in the <em>controls</em> property.
*/
insertControl(index, controlOptions){
if (this.nativeElement.isRendered) {
this.nativeElement.insertControl(index, controlOptions);
}
else
{
this.nativeElement.whenRendered(() => {
this.nativeElement.insertControl(index, controlOptions);
});
}
}
/** Remove a control from the Form.
* @param {any} controlOptions. Control options. The control options description is available in the <em>controls</em> property.
*/
removeControl(controlOptions){
if (this.nativeElement.isRendered) {
this.nativeElement.removeControl(controlOptions);
}
else
{
this.nativeElement.whenRendered(() => {
this.nativeElement.removeControl(controlOptions);
});
}
}
/** Submits the form.
* @param {any} submitOptions?. Sets the submit options object. The object may have the following properties: <em>async</em>, <em>action</em>, <em>target</em>, <em>method</em>. <em>async</em> determines whether the form will be submitted asynchronously. <em>action</em> determines the submit url, <em>method</em> sets whether the submit is through 'GET' or 'POST'. <em>target</em> determines the submit target.
*/
submit(submitOptions){
if (this.nativeElement.isRendered) {
this.nativeElement.submit(submitOptions);
}
else
{
this.nativeElement.whenRendered(() => {
this.nativeElement.submit(submitOptions);
});
}
}
/** Clears the form.
*/
reset(){
if (this.nativeElement.isRendered) {
this.nativeElement.reset();
}
else
{
this.nativeElement.whenRendered(() => {
this.nativeElement.reset();
});
}
}
/** Validates the form.
*/
validate(){
if (this.nativeElement.isRendered) {
this.nativeElement.validate();
}
else
{
this.nativeElement.whenRendered(() => {
this.nativeElement.validate();
});
}
}
constructor(props) {
super(props);
this.componentRef = React.createRef();
}
componentDidRender(initialize) {
const that = this;
const props = {};
const events = {};
let styles = null;
const stringifyCircularJSON = obj => {
const seen = new WeakSet();
return JSON.stringify(obj, (k, v) => {
if (v !== null && typeof v === 'object') {
if (seen.has(v)) return;
seen.add(v);
}
if (k === 'Smart') {
return v;
}
return v;
});
};
for(let prop in that.props) {
if (prop === 'children') {
continue;
}
if (prop === 'style') {
styles = that.props[prop];
continue;
}
if (prop.startsWith('on') && that.properties.indexOf(prop) === -1) {
events[prop] = that.props[prop];
continue;
}
props[prop] = that.props[prop];
}
if (initialize) {
that.nativeElement = this.componentRef.current;
that.nativeElement.React = React;
that.nativeElement.ReactDOM = ReactDOM;
if (that.nativeElement && !that.nativeElement.isCompleted) {
that.nativeElement.reactStateProps = JSON.parse(stringifyCircularJSON(props));
}
}
if (initialize && that.nativeElement && that.nativeElement.isCompleted) {
// return;
}
for(let prop in props) {
if (prop === 'class' || prop === 'className') {
const classNames = props[prop].trim().split(' ');
if (that.nativeElement._classNames) {
const oldClassNames = that.nativeElement._classNames;
for(let className in oldClassNames) {
if (that.nativeElement.classList.contains(oldClassNames[className]) && oldClassNames[className] !== "") {
that.nativeElement.classList.remove(oldClassNames[className]);
}
}
}
that.nativeElement._classNames = classNames;
for(let className in classNames) {
if (!that.nativeElement.classList.contains(classNames[className]) && classNames[className] !== "") {
that.nativeElement.classList.add(classNames[className]);
}
}
continue;
}
if (props[prop] !== that.nativeElement[prop]) {
const normalizeProp = (str) => {
return str.replace(/-([a-z])/g, function (g) {
return g[1].toUpperCase();
});
}
if (prop === 'hover' || prop === 'active' || prop === 'focus' || prop === 'selected') {
that.nativeElement.setAttribute(prop, '');
}
const normalizedProp = normalizeProp(prop);
if (that.nativeElement[normalizedProp] === undefined) {
that.nativeElement.setAttribute(prop, props[prop]);
}
if (props[prop] !== undefined) {
if (typeof props[prop] === 'object' && that.nativeElement.reactStateProps && !initialize) {
if (stringifyCircularJSON(props[prop]) === stringifyCircularJSON(that.nativeElement.reactStateProps[normalizedProp])) {
continue;
}
}
that.nativeElement[normalizedProp] = props[prop];
}
}
}
for(let eventName in events) {
that[eventName] = events[eventName];
that.nativeElement[eventName.toLowerCase()] = events[eventName];
}
if (initialize) {
Smart.Render();
if (that.onCreate) {
that.onCreate();
}
that.nativeElement.whenRendered(() => {
if (that.onReady) {
that.onReady();
}
});
}
// setup styles.
if (styles) {
for(let styleName in styles) {
that.nativeElement.style[styleName] = styles[styleName];
}
}
}
componentDidMount() {
this.componentDidRender(true);
}
componentDidUpdate() {
this.componentDidRender(false);
}
componentWillUnmount() {
const that = this;
if (!that.nativeElement) {
return;
}
that.nativeElement.whenRenderedCallbacks = [];
for(let i = 0; i < that.eventListeners.length; i++){
const eventName = that.eventListeners[i];
that.nativeElement.removeEventListener(eventName.substring(2).toLowerCase(), that[eventName]);
}
}
render() {
return (
React.createElement("smart-form", { ref: this.componentRef, suppressHydrationWarning: true }, this.props.children)
)
}
}
export default Form;