DEV Community

Benjamin RICHARD
Benjamin RICHARD

Posted on

Yet another Angular article, part 4 : Input

In my previous article, we modified the default project configuration. This time, we will create our first components and use Input/Output to bind them together.

In the second article, you created a HelloWorld component. Please delete the src/app/hello-world folder if it still exists in your project.

Next, create the HelloWorldForm and HelloWorld components:

  • ng generate component hello-world-form
  • ng generate component hello-world

Edit the main app.component.ts to use the new component:

@Component({
  selector: 'app-root',
  imports: [HelloWorldFormComponent],
  template: `
    <h1>Yet another angular article, part 4 : Input</h1>
    <app-hello-world-form />
  `,
})
export class App {}
Enter fullscreen mode Exit fullscreen mode

Edit src/app/hello-world-form/hello-world-form.component.ts like this :

import {
  ChangeDetectionStrategy,
  Component,
  signal,
  WritableSignal,
} from '@angular/core';
import { HelloWorldComponent } from '../hello-world/hello-world.component';

@Component({
  selector: 'app-hello-world-form',
  imports: [HelloWorldComponent],
  template: `
<input type="text" [value]="username()" (keyup)="setUsername($event)"/>
Hello {{ username() }}
`,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HelloWorldFormComponent {
  username: WritableSignal<string> = signal('');
  setUsername = (ev: Event) =>
    this.username.set((ev.target as HTMLInputElement).value);
}
Enter fullscreen mode Exit fullscreen mode

In HelloWorldFormComponent, we declare a signal 'username', and use it in the template string with the syntax username() because signals are functions. We use attribute data binding syntax in Angular templates with hooks like [value]="username()". Everything within the quotes is TypeScript code (no need to use the 'this' keyword). This binds TypeScript code to any kind of attributes.

We also add a setter bound to the input event onKeyup: (keyup)="setUsername($event)".

Parentheses around attributes signify Angular’s syntax to bind a DOM or component event to a method. The argument $event is the event's output.

Run the application and enter something in the input field. You should see Hello 'YOUR INPUT VALUE' to the right of the input field.

Now edit again the src/app/hello-worl/hello-world.component.ts like this :

imports: [HelloWorldComponent],
template: `
  <input type="text" [value]="username()" (keyup)="setUsername($event)"/>
  <app-hello-world [username]="username"></app-hello-world>
`,
Edit src/app/hello-worl/hello-world.component.ts like this :

import { ChangeDetectionStrategy, Component, input } from '@angular/core';

@Component({
  selector: 'app-hello-world',
  template: `Hello {{ username() }}`,
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class HelloWorldComponent {
  username = input('');
}
Enter fullscreen mode Exit fullscreen mode

In HelloWorldComponent, we declare an input 'username' and use it in the template string with the syntax {{ username() }}. We use input as a signal. This new syntax (since v18) declares an input with a default value of an empty string, making username a Signal.

Note: Inputs are ReadableSignals only, so you cannot change the signal’s value inside this component. To enable this (and use two-way binding, which is not best practice), you must use model instead of input. Model is a WritableSignal.

Run the application again. It should function as before, but now each component has a single responsibility.

If you need the input to be mandatory, use the required option: username = input.required(''). You can also transform the input by adding a function: username = input.required('', {transform: (value: string) => value.toUpperCase()}).

That’s all for input parts.

See you soon under ❄️

[note] all articles use command from Angular v19*

[demo] a sample project is available on StackBlitz

Top comments (0)