lwc
lwc copied to clipboard
feat(template-compiler): lwc:if, lwc:elseif, lwc:else directives
Details
This PR ships the if-elseif-else directives into master. These directives are analogous to if-statements in Javascript and enable developers to express else if
and else
logic in their html templates to conditionally render parts of their template:
<template>
<template lwc:if={abra}>
Abra!
</template>
<template lwc:elseif={kadabra}>
Kadabra!
</template>
<template lwc:else>
Alakazam!
</template>
</template>
The above can be thought of as:
if (component.abra) {
// render "Abra!"
} else if (component.kadabra) {
// render "Kadabra!"
} else {
// render "Alakazam!"
}
Additionally, these directives can be applied to arbitrary elements:
<div lwc:if={renderDiv}>...</div>
<div lwc:elseif={altDiv}>...</div>
<div lwc:else>...</div>
and other components
<c-component lwc:if={renderComponent}></c-component>
<c-alternative lwc:elseif={renderAlt}></c-alternative>
<c-default lwc:else></c-default>
Here's a complex example with nested elements:
<template>
<template lwc:if={outer.if}>
<h1>outer if</h1>
</template>
<template lwc:elseif={outer.elseif1}>
<h1>outer elseif</h1>
</template>
<template lwc:elseif={outer.elseif2}>
<template lwc:if={inner.if}>
<h1>inner if</h1>
</template>
<template lwc:elseif={inner.elseif}>
<h1>inner elseif</h1>
</template>
<template lwc:elseif={inner.elseif2}>
<x-foo lwc:dynamic={trackedProp.foo}></x-foo>
</template>
<template lwc:else>
<h1>inner else</h1>
</template>
</template>
<template lwc:else>
<h1>outer else</h1>
</template>
</template>
Similar to if-statements in Javascript, elements with lwc:elseif
and lwc:else
must be immediately preceded by a sibling lwc:if
or lwc:elseif
. Each statement is evaluated only if the previous statements in its block evaluate false
, and only one of the branches in a block of statements will be rendered. Note that lwc:else
does not take an attribute value and will throw an error if one is provided.
With the introduction of these directives, if:true
and if:false
statements should be considered "legacy" and are now redundant. Documentation will need to be introduced to clearly communicate this change, and we should evaluate how to add warnings to our compiler to un-noisily communicate this moving forward.
High Level Summary of Implementation
- The template compiler's parser transforms sets of sibling
if-elseif-else
directives into a tree of nodes representing the different conditional branches. - The template compiler's parser keeps track of which slot names are valid/invalid in which branches of the conditional tree to maintain existing validation on duplicate slot names.
- The template compiler's codegen converts the
if-elseif-else
tree into ternary operators
Additional Documentation
RFC PR for tracking parser context PR for codegen implementation
Does this pull request introduce a breaking change?
- ✅ No, it does not introduce a breaking change.
Does this pull request introduce an observable change?
- ⚠️ Yes, it does include an observable change.
This is a new feature to be used by downstream developers.
GUS work item
The remaining issue with the diffing algo should be addressed by a combination of the Fragment VNodes work and ~~https://github.com/salesforce/lwc/pull/3042/commits/b9cfd81e4bfbdf19612456460d0e90322ac25ce2~~ https://github.com/salesforce/lwc/pull/3047. That PR uses the new Fragment VNodes to mark each if-elseif-else branch so that the diffing algo can patch them.
https://github.com/salesforce/lwc/pull/3047 is now ready to merge and should address the issues with the diffing algo by making use of the VFragments work.
/nucleus test
cc @jmsjtu if-else work just merged! 🎉