AngularJS Components
AngularJS components provide a focused view boundary with an isolate scope and controller bindings. They are useful when maintaining code that should gradually move away from broad shared scopes.
How it works
The repair card owns its small template and a local label. Its default controller alias is $ctrl, while the page controller still uses vm. Keeping those names distinct makes the ownership visible. Components are not the same API as modern Angular decorators, and adding a component registration does not itself migrate an application to the modern framework.
Run the code
AngularJS 1.8.3 is a legacy framework whose official support ended in January 2022. These examples teach maintenance, not a recommendation for a new application. They need a separate local browser page; Bhylu has no AngularJS playground.
In an empty folder save the HTML below as components.html and the server as lab-server.mjs. Make a vendor folder and save the four pinned libraries there, retaining their MIT notices. With Node 22 or later run node lab-server.mjs components.html, then open http://127.0.0.1:8136/. Stop that lab before running a different lesson. The server supplies fixed read-only HTTP fixtures; no data is saved and it does not connect to SQL. No PHP, Apache or MySQL configuration changes are needed.
Example
<!doctype html>
<html lang="en" ng-app="repairLab" ng-strict-di>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>AngularJS Components</title>
<style>
:root {
font:
18px/1.55 system-ui,
sans-serif;
color: #0f3464;
background: #fff;
color-scheme: light;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
}
main {
max-width: 50rem;
margin: auto;
padding: 1.2rem;
}
h1 {
font-size: 1.65rem;
}
label {
display: block;
margin: 0.6rem 0;
}
input,
select,
textarea,
button {
font: inherit;
max-width: 100%;
padding: 0.35rem;
margin: 0.2rem;
}
button {
border: 1px solid #034fa0;
border-radius: 0.25rem;
background: #034fa0;
color: white;
}
button:disabled {
opacity: 0.55;
}
output,
[role="status"] {
display: block;
min-height: 1.5rem;
}
table {
border-collapse: collapse;
width: 100%;
}
td,
th {
padding: 0.4rem;
border: 1px solid #a5bbd4;
text-align: left;
}
pre {
white-space: pre-wrap;
overflow-wrap: anywhere;
}
:focus-visible {
outline: 3px solid #0078d4;
outline-offset: 3px;
}
[ng-cloak] {
display: none !important;
}
.marked {
font-weight: 700;
}
.error {
color: #a02424;
}
:root[data-theme="dark"] {
color: #d6e7fb;
background: #061d30;
color-scheme: dark;
}
:root[data-theme="dark"] .error {
color: #ffb4b4;
}
</style>
</head>
<body>
<main ng-controller="DeskController as vm" ng-cloak>
<h1>Community repair desk</h1>
<p>AngularJS 1.8.3 · Legacy maintenance lab · Local demonstration</p>
<repair-card></repair-card>
</main>
<script src="/vendor/angular.min.js"></script>
<script>
(function () {
"use strict";
var app = angular.module("repairLab", []);
app.component("repairCard", {
template: "<p data-result>{{ $ctrl.label }}</p>",
controller: [
function () {
this.label = "Repair card ready";
},
],
});
app.controller("DeskController", [function () {}]);
})();
</script>
</body>
</html>
Focus on the bindings and controller
This excerpt leaves out the document shell, styles and library files. Use the complete download to run it.
<repair-card></repair-card>
<script>
(function () {
"use strict";
var app = angular.module("repairLab", []);
app.component("repairCard", {
template: "<p data-result>{{ $ctrl.label }}</p>",
controller: [
function () {
this.label = "Repair card ready";
},
],
});
app.controller("DeskController", [function () {}]);
})();
</script>
Expected result
Repair card ready
AngularJS instantiates the registered component and renders its controller value. A reusable component should expose the inputs and callbacks a caller actually needs, not quietly reach into parent scopes. The next examples add those contracts and test the resulting interactions.