Our Angular-Elements webcomponent should have the two methods openModal()
and closeModal()
that can be used as custom-element inside React, Vue or any other library to change the visibility state.
This simple javascript usage should be possible:
<my-modal id="modal"></my-modal>
<button id="openModal" onclick="openModal()">open</button>
<button id="closeModal" onclick="closeModal()">close</button>
<script>
const modal = document.getElementById("modal");
function openModal() {
modal.openModal();
}
function closeModal() {
modal.closeModal();
}
</script>
The internal attribute visible
should be set to true
or false
so that it can be used by the template.
@Component({
selector: 'my-modal',
template: `<p>Attribute visible: {{visible}}</p>`,
styles: []
})
export class MyModalComponent {
// Without `@Input` changes to the variable within `openModal()`
// and `closeModal()` will not effect the components state!
visible = false;
// Without the `@Input()` here, angular-elements will not
// map the `openModal()` to our custom-element.
@Input()
public openModal(): void {
console.log("Open Modal")
this.visible = true;
}
@Input()
public closeModal(): void {
console.log("Close Modal")
this.visible = false;
}
}
Questions:
- Why we need to decorate our public component methods (
openModal()
andcloseModal()
with@Input()
) even if we are not using them as Input-Parameter? - Why we need to decorate the
visible
-Flag with@Input
? This is pretty bad because we expose internal state and furthermore it looks like to be a valid approach?
@Input()
s are designed for properties, not functions. For your use case you can simply use a getter and return a function there.As for the
visible
state not changing: it does change (just check withconsole.log
after the change). However, the change is not detected by angular's change detection, since the call comes out of angulars context. You'd experience the same issue when usingsetTimeout
for example to change a value. To get around this, injectNgZone
into your component, and usethis.zone.run
to have angular detect the changes.Alternatively you may want to play around with
OnPush
change detection. You'd use Subjects and Observables and a "push" pipe (variant of async pipe) as implemented in this package: https://github.com/rx-angular/rx-angularOf course if it's something as simple as changing a boolean flag, you might as well just expose that property as an
@Input()
, this way it would be bindable in the host application.