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
visiblestate not changing: it does change (just check withconsole.logafter 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 usingsetTimeoutfor example to change a value. To get around this, injectNgZoneinto your component, and usethis.zone.runto have angular detect the changes.Alternatively you may want to play around with
OnPushchange 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.