Skip to content

Instantly share code, notes, and snippets.

@bootrino
Created April 14, 2020 23:47
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bootrino/65ed6a749799c37862e26562e1e06cf3 to your computer and use it in GitHub Desktop.
Save bootrino/65ed6a749799c37862e26562e1e06cf3 to your computer and use it in GitHub Desktop.
djangoForm.jsx
import React, {useState, useEffect, useContext} from 'react';
import {StateContextApplication} from "./StateContextApplication";
let booleanAttributes = [
"allowfullscreen",
"allowpaymentrequest",
"async",
"autofocus",
"autoplay",
"checked",
"controls",
"default",
"defer",
"disabled",
"formnovalidate",
"hidden",
"ismap",
"itemscope",
"loop",
"multiple",
"muted",
"nomodule",
"novalidate",
"open",
"readonly",
"required",
"reversed",
"selected",
"typemustmatch"
];
export const domElementToReactElementSpecific = (domElement, childReactElementArray, propsIn) => {
// note the rules of boolean attribtes:
// https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes#Boolean_Attributes
// IMPORTANT!! BIG PROBLEM SOLVED
// - not lowercasing the tagName means defaultValue does not work
const tagName = domElement.tagName.toLowerCase();
let propsOut = {};
childReactElementArray = childReactElementArray || [];
var attributes = domElement.attributes;
for (var i = 0, len = attributes.length; i < len; i++) {
if (booleanAttributes.indexOf(attributes[i].name) !== -1) {
propsOut[attributes[i].name] = true;
} else {
propsOut[attributes[i].name] = attributes[i].value;
}
}
delete propsOut.style; // we are not taking any styling from Django and it causes errors
// an element with a value is a controlled component
delete propsOut.value;
propsOut["defaultValue"] = domElement.value;
// overwrite element props with those supplied as arguments
propsOut = {...propsOut, ...propsIn};
if (tagName === 'option') {
// note here the innerText of the option tag goes into the children field of createelement
return React.createElement(tagName, {...propsOut, value: domElement.value}, domElement.innerText);
}
if (tagName === 'input') {
// react says:
// input is a void element tag and must neither have `children` nor
// use `dangerouslySetInnerHTML`.
return React.createElement(tagName, propsOut);
}
return React.createElement(tagName, propsOut, childReactElementArray);
};
export const domElementToReactElement = (domElement, props) => {
// IMPORTANT!! BIG PROBLEM SOLVED
// - not lowercasing the tagName means defaultValue does not work
const tagName = domElement.tagName.toLowerCase();
let childReactElementArray = [];
if (tagName === 'select') {
// select elements have zero or more options child elements
for (var i = 0, len = domElement.childElementCount; i < len; ++i) {
let optionElement = domElement.children[i];
if (optionElement.hasAttribute('selected')) {
// in ReactJS, the selected value of a select HTML element is defined as a "value"
// attribute on the select element NOT on the option attribute, as is standard with HTML
// so here if we find this option has the selected attribute then set that value on select
// i think also react drops the "selected" attribute from the options elements
domElement.setAttribute('value', optionElement.value);
}
childReactElementArray.push(domElementToReactElementSpecific(domElement.children[i]));
}
}
let element = domElementToReactElementSpecific(domElement, childReactElementArray, props);
return element;
};
export const setDjangoFormFieldValue = (elementId, responseDOM, value) => {
if (!responseDOM) {
alert('cannot set field value, no responseDOM');
}
let element = responseDOM.getElementById(elementId);
if (!element) {
alert('cannot set field value, no responseDOM element', elementId);
}
// to set value, you MUST set the value attribute
element.setAttribute("value", value);
};
export const GenericElement = (elementId, responseDOM, props, reRenderOnChange) => {
const {getapplicationstate, setapplicationstate} = useContext(StateContextApplication);
if (!responseDOM) {
return null;
}
responseDOM.getElementById(elementId);
let domel = responseDOM.getElementById(elementId);
if (domel === undefined) {
return null;
}
props = {
...props,
key: elementId,
onChange: (e) => {
console.log(e)
responseDOM.getElementById(elementId).value = e.target.value;
if (reRenderOnChange === true) {
// rerender the application when this field changes value...
const randomMS = Math.floor(Date.now() / 1000);
setapplicationstate({...getapplicationstate, "rerender": randomMS});
}
}
};
return domElementToReactElement(domel, props);
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment