JSONX Manual


Using advanced props

JSONX is created so you can create react elements and components with only JSON. Advanced props allow for your components to interact with dynamic data for example:

There are five kinds of Advanced Props (Traverse, Evaluation, Format, Display and Utility props):

1. Traverse Props

(resourceprops/asyncprops, windowprops, thisprops, thisstate, thiscontext)

Traversed Props are used to assign props values from different objects. For example if you wanted to set the alt text of an image tag from the url of the window, because JXM objects are JSON it’s impossible to get the dynamic value window.location.href and assign it to the alt prop.

//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, for accessing window.location.href you want to traverse the window property and assign the href property from window.location to the JXM.props.alt property.

Traversing the window object is possibly by using the windowprops traverse prop. The other traverse props are:

To properly reference window.location.href the following JXM Object would work

const JXM = {
 component:'img',
 props:{
   src:'path/to/some/image',
 },
 windowprops:{
   alt:['location','href']
 }
}

Traverse props assign properties to JXM.props object by defining what property you want to set on JXM.props as the traverse prop name and passing an array to the property value you want. So for a window’s location (window.location.href) the property value is accessed by an array to the href ['location','href'] where you omit the transverse object from the array path.

Some sample use cases are:

// 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 are properties that are computed and resolve values onto the JXM.props property. They are helpful because in order to interact with dyanamic data and stateful information, they provide a way to describe declaratively how to assign properties onto the JXM.props property.

_children

The _children evaluation property is used to override the value of JXM.children and is usually only used when you want to dynamically set the value of the children property from an advanced property.

//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 are properties used to evaluate strings and set the value the property value on a JXM Object.

__dangerouslyEvalAllProps will evaluate a string as a function and assign the returned value of the function to the props property of a JXM object. Note: If passing the value as a string, remember this value has to be an expression, so either a (({jsonx})=>({})) or (function({jsonx}){}). There is one parameter passed into the function, it’s the current value of the JXM Object on the jsonx property

__dangerouslyEvalProps is used to evaluate the string value and assign it to the JXM.props value, the string must be a valid javascript expression (Tip, if evaluting an object remember to wrap it ({some:‘obj’, }) ). If __dangerouslyEvalProps is a function, it will assign the value of the function called with one parameter {jsonx}.

__dangerouslyBindEvalProps is used to assign functions to JXM object props values. This is usually for onClick and onChange functions. Each property of __dangerouslyBindEvalProps has to be a function, because it’s attempts to assign the value as a function with this bound to it.

The reason why these functions exist are because there are instances where JSONX is delivered via JSON and JavaScript functions are not valid JSON values. This is typically used sparingly when JXM is sent server side. In practice there are many ways to pass functions as values (especially if they are bound to JSONX, then you can always reference functions by access properties off of this by using thiscontext).

Example Evaluation Props

__spreadComponent and __spread

__dangerouslyInsertFunctionComponents and __dangerouslyInsertClassComponents

__dangerouslyInsertComponents, __dangerouslyInsertReactComponents, __dangerouslyInsertJSONXComponents

__windowComponents, __windowComponentProps,

__functionProps (legacy)

The evaluation prop __functionProps is another way to assign a function value to a property in JXM.props. There are two ways of using __functionProps, one way for predefined functions and another way for dynamic functions. Using __functionProps may be deprecated in the future.

predefined functions (legacy)

__functionProps can assign values from functions that exist on this.props (e.g. using something like react-router and accessing this.props.reduxRouter.push) or functions that exist on the window object (like window.console.log).

Properties are assigned by using the value of the function by access the propery as a string, prefixed with “func:”. Function props merge onto jsonx.props after evaluating each functon string.

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 a string in a much less elegant way than using __dangerouslyEvalProps or __dangerouslyBindEvalProps. It’s very cumbersome but you define the string of the function body JXM.__inline[name-of-func] and reference the function on __functionProps by prefixing the function with func:inline (e.g. JXM.__functionProps[func:inline[name-of-function]]). You can also use the __functionargs advanced props to bind JXM.prop properties to parameters of the inline function.

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 are properties that are used to convert JXM.children values to strings. Format Props are used because the children parameter of React.createElement can only be a string or an array of React Elements.

___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). You can set the timezone of the ISO string by using the ___FromLuxonTimeZone format Prop. See luxon formatting options from 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)

Utility props generally do not mutate JXM.props but are used augment the expected behaviour of JSONX.

debug

The debug flag outputs the value of the JXM object where JXM.debug === true and the value of all of the computed advanced props as well.

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"}
    }
  }
}*/

passprops

The passprops flag passess the props from the parent JXM object to each JXM.children JXM Object except for the JXM.props.style property.

const JXM = {
  component: 'div',
  props:{
    type:'radio',
    style:{
      background:'red'
    }
  },
  passprops:true,
  children:[
    {
      component:'input',
    }
  ]
};

/* computes:
const JXM = {
  component: 'div',
  props:{
    type:'radio',
    style:{
      background:'red'
    }
  },
  passprops:true,
  children:[
    {
      component:'input',
      props:{
        type:'radio',
      },
    }
  ]
};
*/

___template

The ___template advanced prop (should really only be used server side but works in the browser too) will load JXM objects from an external file (or URL client side - note in the browser this is a synchronous request).


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 are properties that are used to determine if a React Element rendered from a JXM Object should be rendered. Display props enable conditional logic based of the value of props to determine if an element should be shown.

comparisonprops and comparisonorprops

The display prop comparisionprops is used to contionally show elements if all of the comparisions are truthy. comparisonprops works by comparing an array of left and right side values, if they are all true, the component is rendered. If JXM.comparisonorprops is set to true then only one condition needs to be true in order to render the component.

The comparison values can either be literal values or the value can be a reference to any JXM.props value. References to values in JXM.props are accessed in the same way you would use traverse props, where the prop being traversed is JXM.props.

//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


JSONX Manual