Using Advanced Props
Advanced props let JSONX definitions read dynamic data, format output, render conditionally, and generate component props. Use them when a static JSONX object is not enough.
- Reference stateful properties dynamically.
- Format children before rendering.
- Insert JSONX templates.
- Create function or component props when the input is trusted.
There are six groups of advanced props:
- 1. Traverse Props - used to traverse data passed into elements or other dynamic/stateful data and assign values as props
- 1.1 resourceprops/asyncprops - assign dynamic data to props
- 1.2 windowprops - assign window variables to props
- 1.3 thisstate - assign stateful data to props
- 1.4 thiscontext - assign data bound to
thisto props - 1.5 thisprops - re-assign prop values
- 2. Evaluation Props - used to create function properties or component properties and assign values as props. Treat these as trusted-input features.
- 2.1 __dangerouslyEvalProps - evaluate strings as props
- 2.2 __dangerouslyBindEvalProps - evaluate strings to generate props that are functions bound to
this - 2.3 __dangerouslyEvalAllProps - evaluate all props from a string
- 2.4 __dangerouslyInsertFunctionComponents - use JSONX to generate a function component as a prop
- 2.5 __dangerouslyInsertClassComponents - use JSONX to generate a class component as a prop
- 2.6 __dangerouslyInsertComponents - assign React elements to props using JSONX
- 2.7 __dangerouslyInsertReactComponents - assign React elements to props
- 2.8 __dangerouslyInsertJSONXComponents - assign React elements to props
- 2.9 _children - dynamically override the
childrenprop - 2.10 __functionProps (legacy) - the old way to assign functions to props
- 2.11 __windowComponents - assign window components to props
- 2.12 __windowComponentProps - assign props from window components
- 2.13 __spreadComponent - component mapped over
__spreaddata - 2.14 __spread - data used to generate props from an array (e.g. if you have a list)
- 3. Format Props - used to format children props, for example, converting number formats or formatting dates
- 3.1 ___stringifyChildren - convert
childrenprop to string using JSON.stringify - 3.2 ___toStringChildren - convert
childrenprop to string using .toString() - 3.3 ___toNumeral - format number values as strings assigned to
childrenprop using Numeral JS - 3.4 ___JSDatetoLuxonString - format date values as strings assigned to
childrenprop using Luxon - 3.5 ___ISOtoLuxonString - format iso date values as strings assigned to
childrenprop using Luxon - 3.6 ___FromLuxonTimeZone - format date values as strings assigned to
childrenprop using Luxon
- 3.1 ___stringifyChildren - convert
- 4. Utility Props - used to perform functional tasks like inserting external JXM references (template support), or sharing props across components
- 4.1 __template - insert jxm objects from external files
- 4.2 passprops - pass props from parent to children elements
- 4.3 debug - output computed advanced props and debugging information to the console
- 4.4 test - output computed advanced props and debugging information as a string
- 5. Display Props - used to decide whether or not to render elements
- 5.1 comparisonprops - conditionally render elements based on prop values
- 5.2 comparisonorprops - conditionally render elements flag to use ‘or’ logic instead of ‘and’ logic
- 6. Applied Props - used to modify other JSONX properties
- 6.1 useformregister - insert React Hook Form registration on a JSONX component
- 6.2 useremoveprops - remove props from component, usually used with passprops
- 6.3 useincludeprops - include only defined props, usually used with passprops
Do not run untrusted JSONX definitions with evaluation props enabled.
1. Traverse Props
(resourceprops/asyncprops, windowprops, thisprops, thisstate, thiscontext)
Traverse props assign prop values from other objects. For example, you might want an image alt prop to use the current browser URL. Because JXM objects are derived from JSON, window.location.href cannot be read directly inside the static props object.
//assume window.location.href = http://example.com
const JXM = {
component:'img',
props:{
src:'path/to/some/image',
alt: // ??? http://example.com
}
};
This is where traverse props are useful. The path reads window.location.href and assigns that value to JXM.props.alt.
Traversing the window object is possible by using the window props traverse prop. The other traverse props are:
- resourceprops - traverse asynchronous properties passed to components when using JSONX programmatically
- asyncprops - an alias for
resourceprops - windowprops - traverse properties on
window - thisprops - traverse properties on
this.props - thisstate - traverse properties on
this.state - thiscontext - traverse properties on
this
To reference window.location.href, use this JXM object:
const JXM = {
component:'img',
props:{
src:'path/to/some/image',
},
windowprops:{
alt:['location','href']
}
}
Traverse props assign values to JXM.props. The traverse prop key is the prop you want to set. The value is the path to read from the source object. For window.location.href, the path is ["location", "href"]; the source object itself is not included in the path.
Some sample use cases are:
resourcepropstraverses the resources object passed to JSONX methods.asyncpropsis an alias.thispropstraversesthis.props.thisstatetraversesthis.state.thiscontexttraverses the currentthiscontext.windowpropstraverses the globalwindowobject.
// programmatic example
import * as jsonx from "jsonx";
async function main() {
const response = await fetch("/path/to/userdata");
const asyncUserData = await response.json();
/*
asyncUserData = {
user: {
name: 'jsonx',
description: 'react without javascript',
},
stats: {
logins: 102,
comments: 3,
},
authentication: 'OAuth2',
};
*/
const JXM = {
component: "div",
props: {
id: "generatedJSONX",
className: "jsonx"
},
resourceprops: {
auth: ["authentication"],
username: ["user", "name"]
},
children: [
{
component: "p",
props: {
style: {
color: "red",
fontWeight: "bold"
}
},
asyncprops: {
title: ["user", "description"]
},
children: "hello world"
}
]
};
//render something silly
jsonx.jsonxRender(JXM, asyncUserData);
/*
Renders this JXM object:
JXM = {
component: 'div',
props: {
id: 'generatedJSONX',
className:'jsonx',
auth: 'OAuth2',
username: 'jsonx',
},
children: [
{
component: 'p',
props: {
style: {
color: 'red',
fontWeight:'bold',
},
title:'react without javascript',
},
children:'hello world',
},
],
};
*/
}
main();
Example Traverse Props
2. Evaluation Props
(__dangerouslyEvalProps, __dangerouslyBindEvalProps, __dangerouslyEvalAllProps, __dangerouslyInsertFunctionComponents, __dangerouslyInsertClassComponents, __dangerouslyInsertComponents, __dangerouslyInsertReactComponents, __dangerouslyInsertJSONXComponents, _children, __functionProps (legacy), __windowComponents , __windowComponentProps, __spreadComponent, __spread)
Evaluation props compute values and merge them onto JXM.props. They are useful when JSONX needs to describe how dynamic data, state, or functions become props. Use these only with trusted JSONX input.
_children
The _children evaluation property overrides JXM.children. Use it when an advanced prop should provide the rendered children.
//current URL: http://example.com
const JXMWindowLocation = {
component: "p",
windowprops: {
_children: ["location", "href"]
}
};
// computes: { component:'p', children:'http://example.com', }
__dangerouslyEvalProps, __dangerouslyBindEvalProps, and __dangerouslyEvalAllProps
The evaluation properties __dangerouslyEvalProps, __dangerouslyBindEvalProps, and __dangerouslyEvalAllProps evaluate strings or functions and assign the result to a JXM object.
__dangerouslyEvalAllProps evaluates a string as a function and assigns the return value to props.
Note: When the value is a string, it must be an expression such as (({ jsonx }) => ({})) or (function({ jsonx }) { return {}; }). JSONX passes the current JXM object through the jsonx property.
__dangerouslyEvalProps evaluates each string value and assigns the result to JXM.props. The string must be a valid JavaScript expression. If you evaluate an object literal, wrap it in parentheses: ({ some: "obj" }). If __dangerouslyEvalProps is a function, JSONX calls it with { jsonx }.
__dangerouslyBindEvalProps assigns functions to JXM prop values. This is usually for onClick and onChange handlers. Each value must resolve to a function because JSONX binds the function to the current this context.
These props exist for cases where JSONX is delivered as JSON and JavaScript functions cannot be included directly. Use them sparingly. In many cases, it is better to register functions in code and reference them through thiscontext or another traverse prop.
Example Evaluation Props
__spreadComponent and __spread
__spreadComponent maps one JSONX component over the data in JXM.__spread. Each item in the JXM.__spread array is passed into the child component as JXM.__item. JXM.__spread is usually assigned with a traverse prop.
const JXM = {
component: 'ul',
props:{
__spread: [
{
name:'bob smith',
email:'bob.smith@email.com'
},
{
name:'jane doe',
email:'jane.doe@email.com'
},
{
name:'billy bob',
email:'billy.bob@email.com'
},
],
},
__spreadComponent:{
component:'li',
thisprops:{
_children:['__item','name']
}
},
};
/* => {
component:'ul', children: [
{
component:'li', children:'bob smith',
},
{
component:'li', children:'jane doe',
},
{
component:'li', children:'billy bob',
}
]
};*/
Example Evaluation Props
__dangerouslyInsertFunctionComponents, __dangerouslyInsertClassComponents, __dangerouslyInsertComponents, __dangerouslyInsertReactComponents, __dangerouslyInsertJSONXComponents, __windowComponents, and __windowComponentProps
Component evaluation props assign React elements or components to props. This pattern is common in charting libraries, where a chart accepts a custom label, tick, or tooltip component as a prop.
The most common pattern is a function component passed as a prop. Passing function or class components through JSONX requires the generated component helpers. Read Creating React Components and Component Libraries for more information.
Example Evaluation Props
__functionProps (legacy)
The evaluation prop __functionProps is a legacy way to assign functions to JXM.props. Prefer the newer evaluation props for new work.
predefined functions (legacy)
__functionProps can assign functions that exist on this.props, such as this.props.reduxRouter.push, or functions that exist on window, such as window.console.log.
Properties are assigned by reading a function path from a string prefixed with func:. Function props merge onto jsonx.props after each function string resolves.
const JXM = {
component: "button",
props: {
name: "test"
},
__functionProps: {
onclick: "func:this.props.onClick", // if there's already a defined onClick Function
printPage: "func:window.print",
nav: "func:this.props.reduxRouter.push"
}
};
inline functions (legacy)
__functionProps can also generate functions from strings. This legacy approach is more cumbersome than __dangerouslyEvalProps or __dangerouslyBindEvalProps. Define the function body at JXM.__inline[name], then reference it from __functionProps with func:inline.name. Use __functionargs to bind JXM.props values to inline function arguments.
const JXM = {
component: "button",
props: {
name: "test"
},
__functionargs: {
onClick: ["name"]
},
__inline: {
onClick: ` window.alert("the name of this component from the prop is:" +arguments[0])`
},
__functionProps: {
onClick: "func:inline.onClick"
}
};
Example Evaluation Props __functionProps
3. Format Props
(___stringifyChildren, ___toStringChildren, ___toNumeral, ___JSDatetoLuxonString, ___ISOtoLuxonString, ___FromLuxonTimeZone)
Format props convert JXM.children values to strings. They are useful when raw values need display formatting before React receives them as children.
___stringifyChildren
The ___stringifyChildren format property converts the JXM.children property to a string by using JSON.stringify.
const JXM = {
component: "div",
children: { "some-non-string": "data" },
___stringifyChildren: true
}; // => { component:'div', children: '{"some-non-string":"data"}' };
___toStringChildren
The ___toStringChildren format property converts the JXM.children property to a string by calling toString().
const JXM = {
component: "div",
children: [1, 2, 3, 4],
___toStringChildren: true
}; // => { component:'div', children: '1,2,3,4' };
___toNumeral
The ___toNumeral format property converts the JXM.children property to a string by calling numeral(JXM.children).format(JXM.___toNumeral). See numeral formatting options on numeraljs.com.
const JXM = {
component: "div",
children: 15204.39084,
___toNumeral: "0,0.00"
}; // => { component:'div', children: '15,204.39' };
___JSDatetoLuxonString
The ___JSDatetoLuxonString format property converts the JXM.children property to a string by calling Luxon.DateTime.fromJSDate(JXM.children).toFormat(JXM.___JSDatetoLuxonString). See luxon formatting options from the luxon formatting docs.
const JXM = {
component: "div",
children: new Date("2020-03-03"),
___JSDatetoLuxonString: "LLL d, yyyy"
}; // => { component:'div', children: 'Mar 3, 2020' };
___ISOtoLuxonString & ___FromLuxonTimeZone
The ___ISOtoLuxonString format property converts the JXM.children property to a string by calling Luxon.DateTime.fromISO(JXM.children).toFormat(JXM.___ISOtoLuxonString). Set the time zone with the ___FromLuxonTimeZone format prop. See Luxon formatting options in the Luxon formatting docs.
const JXM_NY = {
component: "div",
children: "2020-03-03T14:30:00.000Z",
___ISOtoLuxonString: "ff",
___FromLuxonTimeZone: "America/New_York"
}; // => { component:'div', children: 'Mar 3, 2020, 9:30 AM' };
const JXM_LA = {
component: "div",
children: "2020-03-03T14:30:00.000Z",
___ISOtoLuxonString: "ff",
___FromLuxonTimeZone: "America/Los_Angeles"
}; // => { component:'div', children: 'Mar 3, 2020, 6:30 AM' };
Example Format Props
4. Utility Props
(__template, passprops, debug, test)
Utility props support rendering behavior without directly becoming regular React props.
debug
The debug flag logs the JXM object and computed advanced props when JXM.debug === true.
const JXM = {
component: 'div',
children: 'Debug JXM Data',
__dangerouslyEvalAllProps:`(
()=>({ style:{ color:"blue" } })
)`,
debug:true,
};
//outputs to console:
/* {
jsonx: {
component: "div",
children: "Debug JXM Data",
__dangerouslyEvalAllProps: "(()=>({ style:{ color:"blue" } }))"
debug: true
},
{
computedProps: {
style: {color: "blue"}
}
}
}*/
test
The test flag outputs the calculated render data as a string when JXM.test === true.
const JXM = {
component: 'div',
children: 'Test JXM Data',
test:true,
};
//outputs as a string component:
/* {
element: "div",
children: "Debug JXM Data",
test: true
}*/
passprops
The passprops flag passes props from the parent JXM object to each child JXM object except JXM.props.style.
const JXM = {
component: 'div',
props:{
type:'radio',
size:'large',
extraOne:'ok',
title:'my radio',
style:{
background:'red'
}
},
passprops:true,
children:[
{
component:'input',
}
]
};
/* computes:
const JXM = {
component: 'div',
props:{
type:'radio',
size:'large',
extraOne:'ok',
title:'my radio',
style:{
background:'red'
}
},
passprops:true,
children:[
{
component:'input',
props:{
type:'radio',
size:'large',
extraOne:'ok',
title:'my radio',
},
}
]
};
*/
You can pass only selected props by listing the prop names.
const JXM = {
component: 'div',
props:{
type:'radio',
size:'large',
title:'my radio',
style:{
background:'red'
}
},
passprops:['type','title'],
children:[
{
component:'input',
}
]
};
/* computes:
const JXM = {
component: 'div',
props:{
type:'radio',
size:'large',
extraOne:'ok',
title:'my radio',
style:{
background:'red'
}
},
passprops:['type','title'],
children:[
{
component:'input',
props:{
type:'radio',
title:'my radio',
},
}
]
};
*/
___template
The ___template advanced prop loads JXM objects from an external file. It is mainly useful on the server. It can also load a URL in the browser, but that browser request is synchronous.
const JXM = {
component:'div',
___template:'path/to/some/jxm/json/file'
}
// path/to/some/jxm/json/file = { component: "section", children: "from external template"}
/* computes:
{
component:'div',
children:[{ component: "section", children: "from external template"}]
}
*/
Example Utility Props
5. Display Props
(comparisonprops, comparisonorprops)
Display props determine whether a React element rendered from a JXM object should be shown. They add conditional rendering based on prop values.
comparisonprops and comparisonorprops
The display prop comparisonprops conditionally renders elements when comparisons pass. By default, every comparison must be true. If JXM.comparisonorprops is true, only one comparison needs to be true.
Comparison values can be literal values or references to JXM.props values. References use the same path-array format as traverse props, with JXM.props as the source object.
//and conditions
jsonx = {
component: "div",
children: "evals to false, so it will not render",
comparisonprops: [
{
left: ["bigNum"],
operation: "lte",
right: ["smallNum"]
}, // false (10000 <= 100)
{
left: ["smallNum"],
operation: "<=",
right: ["bigNum"]
} // true (100 <= 10000)
] // false and true === false, so it won't render
};
//or conditions
jsonx = {
component: "div",
children: "evals to true, so this will render",
comparisonorprops: true,
comparisonprops: [
{
left: ["truthy"],
operation: "eq",
right: ["falsey"]
}, // = false
{
left: ["smallNum"],
operation: "eq",
right: ["smallNum"]
} // true
] // false or true === true, so render element
};
// All comparison operations
switch (opscompares.operation) {
case "eq":
case "==":
return opscompares.left == opscompares.right;
case "dneq":
case "!=":
case "!":
return opscompares.left !== opscompares.right;
case "dnseq":
case "!==":
return opscompares.left !== opscompares.right;
case "seq":
case "===":
return opscompares.left === opscompares.right;
case "lt":
case "<":
return opscompares.left < opscompares.right;
case "lte":
case "<=":
return opscompares.left <= opscompares.right;
case "gt":
case ">":
return opscompares.left > opscompares.right;
case "gte":
case ">=":
return opscompares.left >= opscompares.right;
case "dne":
case "undefined":
case "null":
return opscompares.left === undefined || opscompares.left === null;
case "!null":
case "!undefined":
case "exists":
default:
//'exists'
return opscompares.left !== undefined && opscompares.left !== null;
}
Example Display Props
6. Applied Props
(useformregister, useremoveprops, useincludeprops)
Applied props are helper properties that modify other JSONX properties.
useformregister
The applied prop useformregister passes a React Hook Form register function to a component. It avoids manually wiring the form reference.
jsonx = {
component: "input",
props:{
name:'firstName',
},
useformregister: true,
};
// is equivalent to
jsonx = {
component: "input",
props:{
name:'firstName',
},
thiscontext:{
ref: ['reactHookForm', 'register']
},
};
useremoveprops
The applied prop useremoveprops removes a list of props from the JXM object. It is usually used with passprops when child components should not receive every parent prop.
jsonx = {
component: "input",
props:{
name:'firstName',
removeThis:true,
extraProp:'remove me',
},
useremoveprops: ['removeThis','extraProp'],
};
// is equivalent to
jsonx = {
component: "input",
props:{
name:'firstName',
},
};
useincludeprops
The applied prop useincludeprops removes all props from the JXM object except the listed props. It is usually used with passprops when a child component should receive only a small prop set.
jsonx = {
component: "input",
props:{
name:'firstName',
removeThis:true,
extraProp:'remove me',
keepMe:'just this prop',
},
useincludeprops: ['keepMe'],
};
// is equivalent to
jsonx = {
component: "input",
props:{
keepMe:'just this prop',
},
};