Hydrate and compute values reactively from other (server side rendered/generated) HTML signals via local script tags.
be-computed is very close in purpose to be-overloading. be-overloading focuses more on user-initiated event driven reactions. be-computed is more focused on observing peer elements (and/or the host) and calculating values based on these dependencies reactively.
Obscure note (ignore if it not understanding the context): This behavior probably doesn't make sense to be used where it makes sense to use the trans-render web component. For that reason, not separating the be-hive registration from the be-computed class.
In the examples below, we will encounter special symbols used in order to keep the statements small, as far as identifying which elements to pull in property values from, and observing those elements for property value changes:
Symbol | Meaning | Notes |
---|---|---|
/propName | "Hostish" | Attaches listeners to getters/setters on properties of "hostish". |
@propName | Name attribute | Listens for input events on form elements based on matching the name attribute. |
propName | Itemprop attribute | |
#propName | Id attribute | Matches element based on id within ShadowDOM realm. Listens for input events. |
-prop-name | Marker indicates prop | Matches elements based on finding the exact attribute starting with a dash. Attaches listeners to getters/setters. |
"Hostish" means:
- First, do a "closest" for an element with attribute itemscope, where the tag name has a dash in it. Do that search recursively.
- If no match found, use getRootNode().host.
<div itemscope>
<link itemprop=isHappy href=https://schema.org/True>
<link itemprop=isWealthy href=https://schema.org/False>
...
<link itemprop=isInNirvana
onload="isHappy && !isWealthy"
be-computed='from onload expression, passing in |isHappy, |isWealthy.'
>
</div>
What this does:
- Since the onload attribute expression doesn't start with export const ..., and doesn't start with an open parenthesis, be-computed wraps the expression like so:
export const expr = async ({isHappy, isWealthy}) => {
return isHappy && !isWealthy;
}
- Since the return statement returns a primitive, it applies the value to the adorned element, based on context. In this case, it sets:
<link itemprop=isInNirvana href=https://schema.org/True>
if the conditions are met, and attaches the be-value-added enhancement.
The value of the computation can be obtained via oLink.beEnhanced.beValueAdded.value.
<div itemscope>
<link itemprop=isHappy href=https://schema.org/True>
<link itemprop=isWealthy href=https://schema.org/False>
...
<script nomodule>
isHappy && !isWealthy
</script>
<link itemprop=isInNirvana be-computed='from previous script element expression, passing in |isHappy, |isWealthy.'>
</div>
Advantages of using script element -- less issues with characters that cause problems inside an attribute, may get better IDE support. Disadvantages -- a little further away, a little more verbose, if you need to move the element, need to remember to move the associated script element along with it.
<div itemscope>
<link itemprop=isHappy href=https://schema.org/True>
<link itemprop=isWealthy href=https://schema.org/False>
...
<link itemprop=isInNirvana
onload="isHappy && !isWealthy"
be-computed='from |isHappy, |isWealthy.'
>
</div>
<div itemscope>
<link itemprop=isHappy href=https://schema.org/True>
<link itemprop=isWealthy href=https://schema.org/False>
...
<script nomodule>
isHappy && !isWealthy
</script>
<link itemprop=isInNirvana be-computed='from |isHappy, |isWealthy.'>
</div>
<form itemscope>
<link itemprop=isHappy href=https://schema.org/True>
<input type=checkbox name=isWealthy>
<div contenteditable id=liberated>abc</div>
...
<link itemprop=isInNirvana
onload="isHappy && !isWealthy && liberated?.length > 17"
be-computed='from |isHappy, @isWealthy, #liberated.'
>
</form>
<form itemscope>
<link itemprop=isHappy href=https://schema.org/True>
<input type=checkbox name=isWealthy>
<div contenteditable id=liberated>abc</div>
...
<link itemprop=isInNirvana
onload="
({isHappy, isWealthy, liberated}) => {
console.log({isHappy, isWealthy, liberated});
return isHappy && !isWealthy && liberated?.length > 17;
}
"
be-computed='from |isHappy, @isWealthy, #liberated.'
>
</form>
Since the expression starts with open parenthesis, wrapping is more lightweight. Just adds export const default.
Specify export symbol
<form itemscope>
<link itemprop=isHappy href=https://schema.org/True>
<input type=checkbox name=isWealthy>
<div contenteditable id=liberated>abc</div>
...
<link itemprop=isInNirvana
onload="
export const calculateInNirvana = ({isHappy, isWealthy, liberated}) => {
console.log({isHappy, isWealthy, liberated});
return isHappy && !isWealthy && liberated?.length > 17;
}
"
be-computed='from onload export of calculateInNirvana, passing in |isHappy, @isWealthy, #liberated.'
>
</form>
This allows for multiple expressions that can be used by different enhancements.
<my-custom-element>
#shadow
<script nomodule>
myProp ** 2
</script>
<data itemprop=squared be-computed='from /numValue.'></data>
<be-hive></be-hive>
</my-custom-element>
The slash is optional, so this will also work:
<my-custom-element>
#shadow
<script nomodule>
myProp ** 2
</script>
<data itemprop=squared be-computed='from myProp.'>
<be-hive></be-hive>
</my-custom-element>
Value coming from marker
<form itemscope>
<my-custom-element -num-value></my-custom-element>
<meta itemprop=square
onload="numValue ** 2"
be-computed='from -num-value.'>
</form>
<form itemscope>
<link itemprop=isHappy href=https://schema.org/True>
<input type=checkbox name=isWealthy>
<div contenteditable id=liberated>abc</div>
...
<script nomodule>
({
prop1: isHappy && !isWealthy && liberated?.length > 17,
prop2: liberated?.blink()
})
</script>
<any-element itemprop=isInNirvana be-computed='from previous script element expression, passing in |isHappy, @isWealthy, #liberated, and assign result.'></any-element>
</form>
Detecting such expressions: Starts and ends with ({...}), no arrow. If need to use arrow functions inside, need to provide the context.
<form itemscope>
<link itemprop=isHappy href=https://schema.org/True>
<input type=checkbox name=isWealthy>
<div contenteditable id=liberated>abc</div>
...
<script nomodule>
{
prop1: isHappy && !isWealthy && liberated?.length > 17,
prop2: liberated?.blink()
}
</script>
<any-element itemprop=isInNirvana be-computed='from |isHappy, @isWealthy, #liberated, and assign result.'></any-element>
</form>
<form itemscope>
<link itemprop=isHappy href=https://schema.org/True>
<input type=checkbox name=isWealthy>
<div contenteditable id=liberated>abc</div>
...
<any-element itemprop=isInNirvana
onload="({
prop1: isHappy && !isWealthy && liberated?.length > 17,
prop2: liberated?.blink()
})"
be-computed='from onload expression, passing in |isHappy, @isWealthy, #liberated, and assign result.'></any-element>
</form>
<form itemscope>
<link itemprop=isHappy href=https://schema.org/True>
<input type=checkbox name=isWealthy>
<div contenteditable id=liberated>abc</div>
...
<any-element itemprop=isInNirvana
onload="
{
prop1: isHappy && !isWealthy && liberated?.length > 17,
prop2: liberated?.blink()
}
"
be-computed='from |isHappy, @isWealthy, #liberated, and assign result.'>
</any-element>
</form>
This would allow transforms to be based on.
We can assign the result of a computation to an enhancement, or the "stateProp" property of an enhancement (as defined in the static config property of the enhancement). So one prominent use case is assigning to local "scope" of an element:
<form itemscope>
<link itemprop=isHappy href=https://schema.org/True>
<input type=checkbox name=isWealthy>
<div contenteditable id=liberated>abc</div>
...
<div itemscope
onload="
{
prop1: isHappy && !isWealthy && liberated?.length > 17,
prop2: liberated?.blink()
}
"
be-computed='from |isHappy, @isWealthy, #liberated, and assign result to $0+beScoped.'>
</div>
</form>
Any web server that can serve static files will do, but...
- Install git.
- Fork/clone this repo.
- Install node.js.
- Open command window to folder where you cloned this repo.
-
npm install
-
npm run serve
- Open http://localhost:3030/demo/ in a modern browser.
> npm run test
import 'be-computed/be-computed.js';
<script type=module crossorigin=anonymous>
import 'https://esm.run/be-computed';
</script>