Created
April 14, 2020 23:47
-
-
Save bootrino/65ed6a749799c37862e26562e1e06cf3 to your computer and use it in GitHub Desktop.
djangoForm.jsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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