AngularJS (Angular 1.x) uses a different approach to web components than modern frameworks like React, Vue, and Angular 2+. However, you can still use web components in AngularJS by manually bootstrapping them.
Let us write a web component with one property and event:
<!-- my-component.html --> <template> <div> <p>My name is <strong>{{name}}</strong></p> <button @click="handleClick">Click me!</button> </div> </template> <script> class MyComponent extends HTMLElement { constructor() { super(); this.attachShadow({ mode: 'open' }); this.shadowRoot.innerHTML = ` <style> /* Your component styles here */ </style> <slot></slot> `; this.name = ''; } connectedCallback() { this.name = this.getAttribute('name') || ''; this.render(); } static get observedAttributes() { return ['name']; } attributeChangedCallback(name, oldValue, newValue) { if (name === 'name' && oldValue !== newValue) { this.name = newValue; this.render(); } } render() { this.shadowRoot.innerHTML = ` <style> /* Your component styles here */ </style> <div> <p>My name is <strong>${this.name}</strong></p> <button>Click me!</button> </div> `; } handleClick() { const event = new CustomEvent('my-event', { detail: { message: `Hello from ${this.name}!` } }); this.dispatchEvent(event); } } customElements.define('my-component', MyComponent); </script>
The same web component can be write in Stencil JS and LitElement. Here is the code:
import { Component, h, Event, EventEmitter, Prop } from '@stencil/core'; @Component({ tag: 'my-component', styleUrl: 'my-component.css', shadow: true, }) export class MyComponent { @Prop() name: string = ''; @Event() myEvent: EventEmitter<string>; handleClick() { this.myEvent.emit(`Hello from ${this.name}!`); } render() { return ( <div> <p>My name is <strong>{this.name}</strong></p> <button onClick={() => this.handleClick()}>Click me!</button> </div> ); } }
LitElement
import { LitElement, html, css } from 'lit'; export class MyComponent extends LitElement { static get properties() { return { name: { type: String }, }; } static get styles() { return css` /* Your component styles here */ `; } constructor() { super(); this.name = ''; } handleClick() { const event = new CustomEvent('my-event', { detail: { message: `Hello from ${this.name}!` } }); this.dispatchEvent(event); } render() { return html` <div> <p>My name is <strong>${this.name}</strong></p> <button @click=${() => this.handleClick()}>Click me!</button> </div> `; } } customElements.define('my-component', MyComponent);
1. Import the web component's script in your AngularJS app. You can do this in your index.html file:
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>AngularJS and Web Components</title>
<script src="my-component.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.8.2/angular.min.js"></script>
<script src="app.js"></script>
</head>
<body ng-app="myApp">
<div ng-controller="MyController">
<my-component name="name" on-my-event="handleEvent(event)"></my-component>
</div>
...
</body>
</html>
2. Define a new AngularJS module and controller for your app:
// app.js
angular.module('myApp', [])
.directive('myComponent', function() {
return {
restrict: 'E',
scope: {
name: '=',
onMyEvent: '&',
},
link: function(scope, element) {
const component = element[0];
component.addEventListener('my-event', function(event) {
scope.onMyEvent({ event: event });
scope.$apply();
});
scope.$watch('name', function(newValue) {
component.name = newValue;
component.render();
});
},
};
})
.controller('MyController', function($scope) {
$scope.handleEvent = function(event) {
console.log(event.detail.message);
};
});
This directive creates an isolate scope with two-way binding for the name property and a callback function for the my-event event. In the link function, we add an event listener to the web component and update the component's name property whenever it changes in the AngularJS scope. We also call the onMyEvent function in the AngularJS scope when the my-event event is triggered.
Comments
Post a Comment