Counter (Standalone Component)
Requirements
Use a standalone Angular component as the root component. Display the current count value. Provide "+", "-", and "Reset" buttons. Disable the decrement button when the count is 0.
Expected behavior
Clicking "+" increases the count by 1. Clicking "-" decreases the count by 1, but never below 0. Clicking "Reset" sets the count back to 0.
Implementation notes
Use a regular class property (e.g. count = 0) to store state.Use template event bindings like (click)="..."for button actions.No need for child components, signals, or advanced patterns in this starter.
Solution idea
This exercise requires a single piece of state: the number of times the user has interacted with the counter. Store it in a component property (e.g. count = 0) on a standalone root component. Use three buttons wired with Angular event bindings to increment, decrement, and reset that state. Guard the decrement so the value never drops below zero and expose a simple derived flag to control the disabled state of the "-" button.
Solution
Overview
This exercise requires a single piece of state: the number of times the user has interacted with the counter. Store it in a component property (e.g. count = 0) on a standalone root component. Use three buttons wired with Angular event bindings to increment, decrement, and reset that state. Guard the decrement so the value never drops below zero and expose a simple derived flag to control the disabled state of the "-" button.
**Test cases**
- Click "+" once → count becomes
1. - Click "+" multiple times → count increases by 1 on each click.
- With count at
0, "-" is disabled and clicking it does nothing. - From a positive value, clicking "-" decreases the count by 1, but never below
0. - From a positive value, clicking "Reset" sets count back to
0and disables "-" again.
Standalone component with internal state and guarded decrement
Use a single standalone AppComponent that holds the count state.
- Declare
count = 0as a class property. - Add methods
inc(),dec(), andreset().
- inc() increments count by 1.
- dec() decrements only when count is greater than 0.
- reset() sets count to 0.
- Bind the methods to the buttons with
(click)in the template. - Bind the disabled state of the decrement button to a derived check, e.g.
isZerogetter returningcount === 0.
This keeps the implementation minimal while showing how to wire state, events, and disabled UI in a standalone Angular component.
Files
{
"name": "angular-counter-solution",
"private": true
}
{
"compilerOptions": {
"target": "es2022",
"strict": true,
"noEmitOnError": false
}
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Angular SDK • Counter (solution)</title>
</head>
<body>
<app-root></app-root>
</body>
</html>
import 'zone.js';
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent).catch(console.error);
:root {
color-scheme: dark;
}
html, body {
margin: 0;
height: 100%;
background: #0a0a0a;
}
body {
font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif;
}
.panel {
background: #0b1020;
border: 1px solid #1f2937;
border-radius: 12px;
padding: 16px;
}
.value {
font-size: 48px;
line-height: 1;
font-weight: 800;
text-align: center;
margin-bottom: 12px;
}
.actions {
display: flex;
gap: 8px;
justify-content: center;
}
button {
background: #a3e635;
color: #111;
border: none;
border-radius: 10px;
padding: 10px 14px;
font-weight: 700;
cursor: pointer;
}
button[disabled] {
opacity: .5;
cursor: not-allowed;
}
button.ghost {
background: transparent;
color: #e5e7eb;
border: 1px solid #374151;
}
<main style="min-height:100vh; background:#0a0a0a; color:#e5e7eb; display:grid; place-items:center; padding:24px;">
<section style="width:100%; max-width:420px; display:grid; gap:16px;">
<h1 style="margin:0; font-size:20px; font-weight:700;">Counter (Solution)</h1>
<div class="panel">
<div class="value">{{ count }}</div>
<div class="actions">
<button (click)="dec()" [disabled]="isZero" aria-label="decrement">−</button>
<button (click)="inc()" aria-label="increment">+</button>
<button (click)="reset()" class="ghost" aria-label="reset">Reset</button>
</div>
</div>
</section>
</main>
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule],
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
count = 0;
get isZero(): boolean {
return this.count === 0;
}
inc(): void {
this.count++;
}
dec(): void {
if (!this.isZero) {
this.count--;
}
}
reset(): void {
this.count = 0;
}
}
Notes & Pitfalls
- Allowing the count to go below 0 when handling the decrement.
- Forgetting to bind the disabled state of the decrement button, which makes the UX unclear.
- Mutating state in the template instead of through clear component methods.
- Using a standalone component with `standalone: true` and `imports` instead of NgModule.
- Using a derived getter (`isZero`) for simple view logic instead of duplicating conditions.
- Keeping all state and logic colocated in the root component for a small exercise.
Similar questions
Guides
Preparing for interviews? Use Frontend Coding Challenges first, then move into a concrete Study Plan before targeted Company Prep.