Fudgel supports binding to expressions in templates. This allows you to insert dynamic values, call functions, and conditionally render content based on the state of your controller.
Most JavaScript syntax works in expressions. It looks like JavaScript and it has access to properties on the controller as well as variables that are defined in various directives. There are several examples on this page along with a list of all operations that are allowed.
Bindings are automatically updated when the controller's top-level properties change. This is a shallow compare, so object references need to change or use a utility function to manually trigger updates.
Each expression is evaluated in the context of a scope. Scopes
are layered on top of the controller's properties. In this
example, the controller's name will be shown first.
*for
(a directive)
creates a new scope for each child element, so the
name
property will be set to the value of the
name
variable in the loop. This allows you to
access properties from the controller as well as variables
defined in directives.
Controller Name: {{ name }}, color {{color}}
Text interpolation allows you to insert dynamic values into the HTML content. The expressions are wrapped in double curly braces.
Hello, {{ name }}!
Attributes can be set to a string with an expression, but the
behavior is different when it is set to true
and
false
. When the value is true
, the
attribute will be added to the element. When it is
false
, the attribute will be removed. This allows
for conditional attributes.
You can bind to events using the @event
syntax. The
expression should resolve to a function call, but it isn't
required. This allows you to call methods on your controller
when an event occurs.
Directives discusses this in more
detail.
Change Count: {{ changeCount }}
`, }, class { changeCount = 0; change() { this.changeCount += 1; } });
Properties can be bound using the prop
directive.
This allows you to set properties on the custom element
instance. The value can be a string, number, object, or any
other type. Learn more about
directives for more details.
"Hello"
, 'World'
,
"escaped characters: \b \f \n \r \t \v"
42
, 3.14
,
3e-10
true
, false
,
null
, ['arrays', true]
,
{"an":"object", ['works']: true}
myVar
,
myProp.childProp
, myProp[3]
,
myProp['childProp']
,
myProp?.childProp
!myVar
, +myVar
,
-myVar
, ~myVar
||
, ??
,
&&
, |
, ^
,
&
, ==
, !=
,
===
, !==
, <
,
>
, <=
, >=
,
<<
, >>
,
>>>
, +
, -
,
*
, /
, %
,
**
myFunc(arg1, 'arg2', 3)
typeof
, in
,
instanceof
Templates should not create complex logic or behaviors. They also should not alter the values in scope, create new functions, or be forced to deal with flow-control statements. Templates should only be used as a bridge to show information to the user, to pass extra information along as an attribute or property, or to bind events to event handlers.
The point of the template is to keep things simple and let the controller do the heavy lifting. Several of the following items are not allowed based on this principle. Others are not allowed because there is no succinct way to implement them while also supporting strict Content-Security-Policy directives.
method1(); method2()
,
method1(), method2()
function test() {}
,
() => {}
due to difficulty implementing
under strict Content-Security-Policy
async
, await
-
requires function creation
...
- no easy way to
implement while also avoiding Content-Security-Policy
issues
=
, +=
,
-=
, etc.
++
,
--
delete propName