---
title: "How to Simplify Angular Component Communication with model() and Signals"
date: "2024-09-29"
slug: "how-to-simplify-angular-component-communication-with-model-and-signals"
author: "Dany Paredes"
canonical: "https://danywalls.com/how-to-simplify-angular-component-communication-with-model-and-signals"
description: "I was very busy in September, but now I'm working on creating a workshop about signals and developing ideas on how signals can simplify our code. Recently, I've been using @Input() and @Output for component communication. However, Angular 17 introduc..."
---

I was very busy in September, but now I'm working on creating a workshop about signals and developing ideas on how signals can simplify our code. Recently, I've been using @Input() and @Output for component communication. However, Angular 17 introduced [input signals](https://angular.dev/guide/signals/inputs) for communication, which work well but the Angular Team is also working on [`model` signals](https://angular.dev/guide/signals/model), a great alternative for bidirectional communication between components with less code. Let's explore it!

> Note:  The `model` is in **developer preview** but we can play with it today!

But you might ask, why do I need another way to communicate if I have input and output? That's a good question. Let me show you with a real-world example.

We want to show a list of movies and rate each one. To make it easy to rate my movies, I will use [**Kendo UI for Angular Rating**](https://www.telerik.com/kendo-angular-ui/rating) and implementing **input/output signals** for bidirectional data binding, then migrate to **model()**, an easy approach.

Let’s do it!

### **Setup Project**

I will use the latest version of Angular. The easiest way is by running the following command in the terminal. Answer yes for default questions.

```bash
npx -p @angular/cli signal-model-rating-kendo
Need to install the following packages:
@angular/cli@18.2.6
Ok to proceed? (y) y
.....
```

Next, move to the project folder `cd signal-model-rating-kendo` and use Kendo UI Schematics to install Kendo Input Rating.

```bash

ng add @progress/kendo-angular-inputs
✔ Determining Package Manager
  › Using package manager: npm
✔ Searching for compatible package version
  › Found compatible package version: @progress/kendo-angular-inputs@16.10.0.
✔ Loading package information from registry
✔ Confirming installation
✔ Installing package
UPDATE package.json (1656 bytes)
UPDATE angular.json (3071 bytes)
```

### **The Rating Using Input/Output Signals**

First, let's create a custom component to rate movies using Kendo UI's `kendo-rating` component. We'll bind the movie's rating using **input/output signals** to demonstrate bidirectional data binding.

```bash
ng g c movie-rating
signal-model-rating-kendo % ng g c componentes/movie-rating
CREATE src/app/componentes/movie-rating/movie-rating.component.scss (0 bytes)
CREATE src/app/componentes/movie-rating/movie-rating.component.html (27 bytes)
CREATE src/app/componentes/movie-rating/movie-rating.component.spec.ts (628 bytes)
CREATE src/app/componentes/movie-rating/movie-rating.component.ts (258 bytes)
```

Let’s use the `kendo-rating` component and set the value by using the **input signal** that will receive and emits the new rating value using the **output** when user updates the rating

Open the `movie-rating.component.ts` file. First, import the RatingComponent from `@progress/kendo-angular-inputs`. Next, declare the `rating` property as **input** to get the value and `ratingChange` as **output** to emit the event.

```typescript

import { Component, input, output } from '@angular/core';
import { RatingComponent } from '@progress/kendo-angular-inputs';

@Component({
  selector: 'app-movie-rating',
  standalone: true,
  imports: [RatingComponent],
  templateUrl: './movie-rating.component.html',
  styleUrl: './movie-rating.component.scss',
})
export class MovieRatingComponent {
  rating = input(4);
  ratingChange = output<number>();

  onRatingChange(newRating: number) {
    this.ratingChange.emit(newRating);
  }
}
```

In the template, we use the `kendo-rating` component, bind the `value` property with the `rating`() signal, and listen to the `valueChange` event to trigger the `onRatingChange` event. The final code looks like:

```xml
<kendo-rating [value]="rating()" (valueChange)="onRatingChange($event)">
</kendo-rating>
```

Perfect, now it's time to connect the movie list with our movie-rating component. Let's do it!

## Communicate The Movie Rating

Open the `app.component.ts`, declare a type `Movie` with the following properties:

```typescript
interface Movie {
  title: string;
  rating: number;
}
```

We create a mock list of movies to use in the component.

```typescript
movies = signal<Movie[]>([
    { title: 'Inception', rating: 4 },
    { title: 'Interstellar', rating: 5 },
    { title: 'The Dark Knight', rating: 5 },
    { title: 'Dunkirk', rating: 3 },
  ]);
```

The most important step is to import the `MovieRatingComponent` into the `app.component.ts`. The final code looks like:

```typescript
import { Component, signal } from '@angular/core';
import { RouterOutlet this } from '@angular/router';
import { MovieRatingComponent } from './componentes/movie-rating/movie-rating.component';

interface Movie {
  title: string;
  rating: number;
}

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, MovieRatingComponent],
  templateUrl: './app.component.html',
  styleUrl: './app.component.scss',
})
export class AppComponent {
  movies = signal<Movie[]>([
    { title: 'Inception', rating: 4 },

    { title: 'Interstellar', rating: 5 },

    { title: 'The Dark Knight', rating: 5 },

    { title: 'Dunkirk', rating: 3 },
  ]);
}
```

In the app.component.html we use the @for to iterate over movies list, show the movie title, rate and the movie-rating component to allow the user vote.

Using `[(rating)]` two way binding we can get the value when it emits.

```xml
@for (movie of movies(); track movie) {
  <h3>{{ movie.title }}</h3>

  <app-movie-rating [(rating)]="movie.rating"></app-movie-rating>

  <p>Current rating: {{ movie.rating }} stars</p>
}
```

Save changes and run `ng serve` to have our app show the list of movies and their ratings. Go to `http://localhost:4200` in your browser, and you'll see the list of movies with the rating feature working.

![](/images/posts/how-to-simplify-angular-component-communication-with-model-and-signals/e7380430-689c-4_66672.gif)

We successfully implemented bidirectional binding using the **input/output signals**, but this requires manually handling the input and emitting the output.

If I told you we can do it with less code using `model()`? 😎

## Moving to Model

Before we start, why do I want to move to `model()`? Well, `model()` automatically creates both an input and an output, making it easier to manage two-way bindings without manually emitting events. So, with a small change in `MovieRatingComponent` to use `model()` instead of the input/output, we can achieve the same result without using `output` signals.

Let’s do it, first import `model` from `@angular/core`

```typescript
import { Component, model } from '@angular/core';
import { RatingComponent } from '@progress/kendo-angular-inputs';
```

Change the type of `input` to `model`. The model is a writable signal, so we can update it using the `update` method.

```typescript
import { Component, model } from '@angular/core';
import { RatingComponent } from '@progress/kendo-angular-inputs';

@Component({
  selector: 'app-movie-rating',
  standalone: true,
  imports: [RatingComponent],
  templateUrl: './movie-rating.component.html',
  styleUrl: './movie-rating.component.scss',
})
export class MovieRatingComponent {
  rating = model(4);

  onRatingChange(newRating: number) {
    this.rating.update(() => newRating);
  }
}
```

It automatically emits the value when the signal changes. We no longer need the `output` for bidirectional communication because the model creates an output for us with the change appended to the name. In our case, it is `ratingChange`.

```typescript
<app-movie-rating [(rating)]="movie.rating" (ratingChange)="onRatingChange($event)"></app-movie-rating>
```

Open `http://localhost:4200` in your browser to see the list of movies with their ratings. It works the same way with less code! Yeah!

![](/images/posts/how-to-simplify-angular-component-communication-with-model-and-signals/0b203084-f50d-4_66672.gif)

### **WAIT A SECOND!** Want to dive even deeper into Angular Signals?

I highly recommend the [**Angular Signals Masterclass eBook**](https://angularexperts.io/products/ebook-signals) by [Kevin Kreuzer](https://www.youtube.com/@nivekDev). It’s the best way to learn everything about Signals in one place, with clear examples to guide you.

Grab a [**free preview**](https://angularexperts.io/products/ebook-signals) to get a taste of the awesome insights inside! And when you're ready to go all in, unlock the [**full version**](https://kreuzercode.gumroad.com/l/angular-signals-masterclass) for the complete Signals deep dive.

[![](/images/posts/how-to-simplify-angular-component-communication-with-model-and-signals/40eac492-76d4-4_66673.png)](https://angularexperts.io/products/ebook-signals)

Now you know my secret to learning about Signals. 😎 Let’s continue!

### Ok but Why we have input and model are not the same ?

Well, you can use `input()` and `model()` to communicate with your components, but the magic of `model()` is that it creates an input and an output for our property.

Before pick one keep in mind the following points:

* `Model()`: This automatically creates both an input and an output for a property, allowing for bidirectional data binding with far less code. It’s a writable signal, meaning it can be updated and emits changes to subscribers without needing manual event handling.
    
* `Input/Output Signals`: These require manual handling of input values and emitting output events to get two-way binding.
    

**Remember**: The `model()` simplifies communication but doesn’t support [transformation functions](https://danywalls.com/transform-inputs-properties-in-angular-easy), which might be necessary in more complex scenarios. For these cases, using `input/output` signals may be a better option.

## **Recap**

We learned how to implement bidirectional data binding using **input/output signals** in Angular and then saw how the new `model()` feature can simplify this process with less code.

We started by building a movie rating component using **input/output signals**, where we manually handled data binding and event emissions. While this approach works well, it requires more boilerplate code to manage the communication between components, then, we switched to the `model()` approach, which simplifies the code by automatically handling both input and output bindings.

* [https://github.com/danywalls/signal-model-rating-kendo](https://github.com/danywalls/signal-model-rating-kendo)
    
* [https://angular.dev/guide/signals/inputs](https://angular.dev/guide/signals/inputs)
    
* [https://angular.dev/guide/signals/model](https://angular.dev/guide/signals/model)
    

Happy coding!
