> For the complete documentation index, see [llms.txt](https://odilbeks-organization.gitbook.io/angular-ustoz-shogirt/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://odilbeks-organization.gitbook.io/angular-ustoz-shogirt/modern-component-api-input-output-model.md).

# Modern Component API - input(), output(), model()

### Mundarija

#### 1. **Eski vs Yangi API:**

* @Input/@Output vs input()/output()
* Afzalliklar va farqlar

#### 2. **input() signal:**

* Oddiy input
* Required input
* Transform
* Alias

#### 3. **output():**

* Oddiy output
* Ma'lumot bilan output
* Type-safe

#### 4. **model() - Two-way binding:**

* Sodda sintaksis
* Required model
* Amaliy misollar

#### 5. **Amaliy loyihalar:**

* Todo List (to'liq)
* Search va Filter sistema
* Reusable komponentlar

#### 6. **Best Practices:**

* Type safety
* Required usage
* Clean code

{% embed url="<https://youtu.be/2dpzNqTw9Ss?t=2526>" %}

{% embed url="<https://youtu.be/BZnXUKQ8w-U>" %}

***

### 1. Eski vs Yangi usul

#### 1.1 Eski usul (@Input/@Output)

```tsx
// ❌ Eski usul (hali ham ishlaydi)
import { Component, Input, Output, EventEmitter } from '@angular/core';

@Component({
  selector: 'app-counter',
  template: `<button (click)="increment()">{{ count }}</button>`
})
export class CounterComponent {
  @Input() count: number = 0;
  @Output() countChange = new EventEmitter<number>();

  increment() {
    this.count++;
    this.countChange.emit(this.count);
  }
}
```

#### 1.2 Yangi usul (input/output)

```tsx
// ✅ Yangi usul (Angular 17+)
import { Component, input, output } from '@angular/core';

@Component({
  selector: 'app-counter',
  template: `<button (click)="increment()">{{ count() }}</button>`
})
export class CounterComponent {
  count = input<number>(0);            // Input signal
  countChange = output<number>();      // Output

  increment() {
    const newValue = this.count() + 1;
    this.countChange.emit(newValue);
  }
}
```

**Afzalliklari:**

* ✅ Qisqaroq kod
* ✅ Type-safe
* ✅ Signal-based (reactive)
* ✅ Zamonaviy

***

### 2. input() - Yangi Input

#### 2.1 Oddiy input

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

@Component({
  selector: 'app-user-card',
  template: `
    <div class="user-card">
      <h3>{{ name() }}</h3>
      <p>{{ email() }}</p>
      <p>Yosh: {{ age() }}</p>
    </div>
  `
})
export class UserCardComponent {
  // Oddiy input'lar (signal)
  name = input<string>('');           // Default: ''
  email = input<string>('');
  age = input<number>(0);             // Default: 0
}
```

**Ishlatish:**

```html
<app-user-card
  name="Ali Valiyev"
  email="ali@example.com"
  [age]="25">
</app-user-card>
```

#### 2.2 Required input (majburiy)

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

@Component({
  selector: 'app-product-card',
  template: `
    <div class="product">
      <h3>{{ title() }}</h3>
      <p>{{ price() }} so'm</p>
      <!-- Optional -->
      @if (description()) {
        <p>{{ description() }}</p>
      }
    </div>
  `
})
export class ProductCardComponent {
  // Majburiy input'lar
  title = input.required<string>();
  price = input.required<number>();

  // Ixtiyoriy input
  description = input<string>();
}
```

**Ishlatish:**

```html
<!-- ✅ To'g'ri -->
<app-product-card
  title="Kitob"
  [price]="50000">
</app-product-card>

<!-- ❌ Xato - title va price majburiy! -->
<app-product-card></app-product-card>
```

#### 2.3 Transform input

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

@Component({
  selector: 'app-badge',
  template: `
    <span class="badge">{{ count() }}</span>
  `
})
export class BadgeComponent {
  // Transform: string → number
  count = input(0, {
    transform: (value: string | number) => {
      return typeof value === 'string' ? parseInt(value, 10) : value;
    }
  });
}
```

**Ishlatish:**

```html
<!-- String yuborilsa ham number ga aylanadi -->
<app-badge count="42"></app-badge>
<app-badge [count]="42"></app-badge>
```

#### 2.4 Alias (boshqa nom)

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

@Component({
  selector: 'app-student',
  template: `<p>{{ studentName() }}</p>`
})
export class StudentComponent {
  // 'name' nomida qabul qiladi, lekin ichida 'studentName'
  studentName = input<string>('', { alias: 'name' });
}
```

**Ishlatish:**

```html
<app-student name="Ali"></app-student>
```

***

### 3. output() - Yangi Output

#### 3.1 Oddiy output

```tsx
import { Component, output } from '@angular/core';

@Component({
  selector: 'app-button',
  template: `
    <button (click)="handleClick()">
      {{ label }}
    </button>
  `
})
export class ButtonComponent {
  label = 'Click me';

  // Output
  clicked = output<void>();

  handleClick() {
    this.clicked.emit();
  }
}
```

**Ishlatish:**

```html
<app-button (clicked)="onButtonClick()"></app-button>
```

```tsx
export class ParentComponent {
  onButtonClick() {
    console.log('Button clicked!');
  }
}
```

#### 3.2 Output ma'lumot bilan

```tsx
import { Component, input, output } from '@angular/core';

@Component({
  selector: 'app-search-box',
  template: `
    <input
      type="text"
      [value]="query()"
      (input)="onInput($event)"
      placeholder="Qidirish...">
  `
})
export class SearchBoxComponent {
  query = input<string>('');

  // Output - qidiruv so'zini yuboradi
  search = output<string>();

  onInput(event: Event) {
    const value = (event.target as HTMLInputElement).value;
    this.search.emit(value);
  }
}
```

**Ishlatish:**

```html
<app-search-box (search)="onSearch($event)"></app-search-box>
```

```tsx
export class ParentComponent {
  onSearch(query: string) {
    console.log('Searching for:', query);
  }
}
```

#### 3.3 Murakkab ma'lumot

```tsx
import { Component, output } from '@angular/core';

interface FormData {
  name: string;
  email: string;
  age: number;
}

@Component({
  selector: 'app-user-form',
  template: `
    <form (ngSubmit)="handleSubmit()">
      <input [(ngModel)]="formData.name" name="name">
      <input [(ngModel)]="formData.email" name="email">
      <input [(ngModel)]="formData.age" name="age" type="number">
      <button type="submit">Yuborish</button>
    </form>
  `
})
export class UserFormComponent {
  formData: FormData = {
    name: '',
    email: '',
    age: 0
  };

  // Output - FormData yuboradi
  formSubmit = output<FormData>();

  handleSubmit() {
    this.formSubmit.emit(this.formData);
  }
}
```

**Ishlatish:**

```html
<app-user-form (formSubmit)="onFormSubmit($event)"></app-user-form>
```

```tsx
export class ParentComponent {
  onFormSubmit(data: FormData) {
    console.log('Form data:', data);
  }
}
```

***

### 4. model() - Two-way Binding

#### 4.1 model() nima?

**model()** - bu input va output ikkalasini birlashtirgan yangi usul (two-way binding uchun).

**Eski usul:**

```tsx
// ❌ Eski - 2 ta kod
@Input() value: string = '';
@Output() valueChange = new EventEmitter<string>();
```

{% hint style="info" %}
Ushbu usul yordamida custom Two-way Data-binding qilinar edi. Bu xuddi `[(ngModel)]` ga o’xshaydi. Amalda o’zingiz bu ishni qilib ko’ring!
{% endhint %}

**Yangi usul:**

```tsx
// ✅ Yangi - 1 ta kod
value = model<string>('');
```

#### 4.2 Oddiy misol

```tsx
import { Component, model } from '@angular/core';

@Component({
  selector: 'app-custom-input',
  template: `
    <div class="custom-input">
      <label>{{ label }}</label>
      <input
        type="text"
        [value]="value()"
        (input)="onInput($event)">
    </div>
  `
})
export class CustomInputComponent {
  label = 'Ism:';

  // model - two-way binding
  value = model<string>('');

  onInput(event: Event) {
    const newValue = (event.target as HTMLInputElement).value;
    this.value.set(newValue);
  }
}
```

**Ishlatish (two-way):**

```html
<app-custom-input [(value)]="userName"></app-custom-input>
<p>Siz kiritdingiz: {{ userName }}</p>
```

```tsx
export class ParentComponent {
  userName = signal('');
}
```

#### 4.3 Number input

```tsx
import { Component, model } from '@angular/core';

@Component({
  selector: 'app-counter-input',
  template: `
    <div class="counter">
      <button (click)="decrement()">-</button>
      <span>{{ count() }}</span>
      <button (click)="increment()">+</button>
    </div>
  `
})
export class CounterInputComponent {
  count = model<number>(0);

  increment() {
    this.count.update(c => c + 1);
  }

  decrement() {
    this.count.update(c => Math.max(0, c - 1));
  }
}
```

**Ishlatish:**

```html
<app-counter-input [(count)]="quantity"></app-counter-input>
<p>Miqdor: {{ quantity() }}</p>
```

#### 4.4 Required model

```tsx
import { Component, model } from '@angular/core';

@Component({
  selector: 'app-checkbox',
  template: `
    <label>
      <input
        type="checkbox"
        [checked]="checked()"
        (change)="toggle()">
      {{ label }}
    </label>
  `
})
export class CheckboxComponent {
  label = 'Roziman';

  // Required model
  checked = model.required<boolean>();

  toggle() {
    this.checked.update(c => !c);
  }
}
```

**Ishlatish:**

```html
<app-checkbox [(checked)]="isAgreed" label="Shartlarga roziman"></app-checkbox>
```

***

### 5. Amaliy misol: Todo List

#### 5.1 TodoItem Component

```tsx
import { Component, input, output } from '@angular/core';

export interface Todo {
  id: number;
  text: string;
  completed: boolean;
}

@Component({
  selector: 'app-todo-item',
  template: `
    <div class="todo-item" [class.completed]="todo().completed">
      <input
        type="checkbox"
        [checked]="todo().completed"
        (change)="toggleChange.emit(todo().id)">
      <span>{{ todo().text }}</span>
      <button (click)="deleteClick.emit(todo().id)">O'chirish</button>
    </div>
  `,
  styles: [`
    .todo-item {
      display: flex;
      gap: 10px;
      padding: 10px;
      border: 1px solid #ddd;
      border-radius: 5px;
      margin-bottom: 5px;
    }
    .todo-item.completed span {
      text-decoration: line-through;
      color: #999;
    }
  `]
})
export class TodoItemComponent {
  // Input
  todo = input.required<Todo>();

  // Outputs
  toggleChange = output<number>();
  deleteClick = output<number>();
}
```

#### 5.2 TodoList Component

```tsx
import { Component, signal } from '@angular/core';

@Component({
  selector: 'app-todo-list',
  template: `
    <div class="todo-list">
      <h2>Todo List</h2>

      <!-- Add form -->
      <div class="add-form">
        <input
          type="text"
          [(ngModel)]="newTodoText"
          (keyup.enter)="addTodo()"
          placeholder="Yangi vazifa...">
        <button (click)="addTodo()">Qo'shish</button>
      </div>

      <!-- Todo items -->
      @for (todo of todos(); track todo.id) {
        <app-todo-item
          [todo]="todo"
          (toggleChange)="toggleTodo($event)"
          (deleteClick)="deleteTodo($event)">
        </app-todo-item>
      } @empty {
        <p class="empty">Vazifalar yo'q</p>
      }

      <!-- Stats -->
      <div class="stats">
        <p>Jami: {{ todos().length }}</p>
        <p>Bajarilgan: {{ completedCount() }}</p>
        <p>Faol: {{ activeCount() }}</p>
      </div>
    </div>
  `
})
export class TodoListComponent {
  todos = signal<Todo[]>([]);
  newTodoText = '';
  private nextId = 1;

  // Computed
  completedCount = computed(() =>
    this.todos().filter(t => t.completed).length
  );

  activeCount = computed(() =>
    this.todos().filter(t => !t.completed).length
  );

  addTodo() {
    if (this.newTodoText.trim()) {
      this.todos.update(todos => [...todos, {
        id: this.nextId++,
        text: this.newTodoText,
        completed: false
      }]);
      this.newTodoText = '';
    }
  }

  toggleTodo(id: number) {
    this.todos.update(todos =>
      todos.map(t => t.id === id ? { ...t, completed: !t.completed } : t)
    );
  }

  deleteTodo(id: number) {
    this.todos.update(todos => todos.filter(t => t.id !== id));
  }
}
```

***

### 6. Amaliy misol: Search va Filter

#### 6.1 SearchBox Component

```tsx
import { Component, model } from '@angular/core';

@Component({
  selector: 'app-search-box',
  template: `
    <div class="search-box">
      <input
        type="text"
        [value]="query()"
        (input)="onInput($event)"
        placeholder="Qidirish...">
      @if (query()) {
        <button (click)="clear()">✕</button>
      }
    </div>
  `,
  styles: [`
    .search-box {
      display: flex;
      gap: 5px;
      padding: 10px;
      border: 2px solid #667eea;
      border-radius: 8px;
    }
    input {
      flex: 1;
      border: none;
      outline: none;
      font-size: 16px;
    }
    button {
      background: none;
      border: none;
      cursor: pointer;
      font-size: 20px;
    }
  `]
})
export class SearchBoxComponent {
  // Two-way binding
  query = model<string>('');

  onInput(event: Event) {
    const value = (event.target as HTMLInputElement).value;
    this.query.set(value);
  }

  clear() {
    this.query.set('');
  }
}
```

#### 6.2 FilterSelect Component

```tsx
import { Component, input, model } from '@angular/core';

@Component({
  selector: 'app-filter-select',
  template: `
    <div class="filter-select">
      <label>{{ label() }}</label>
      <select
        [value]="value()"
        (change)="onChange($event)">
        @for (option of options(); track option.value) {
          <option [value]="option.value">
            {{ option.label }}
          </option>
        }
      </select>
    </div>
  `,
  styles: [`
    .filter-select {
      display: flex;
      flex-direction: column;
      gap: 5px;
    }
    select {
      padding: 8px;
      border: 2px solid #ddd;
      border-radius: 5px;
      font-size: 14px;
    }
  `]
})
export class FilterSelectComponent {
  // Input
  label = input<string>('Filter');
  options = input<Array<{value: string, label: string}>>([]);

  // Model (two-way)
  value = model<string>('');

  onChange(event: Event) {
    const newValue = (event.target as HTMLSelectElement).value;
    this.value.set(newValue);
  }
}
```

#### 6.3 Parent Component

```tsx
import { Component, signal, computed } from '@angular/core';

interface Student {
  id: number;
  name: string;
  grade: number;
  subject: string;
}

@Component({
  selector: 'app-students-filter',
  template: `
    <div class="students-filter">
      <h2>Talabalar</h2>

      <div class="filters">
        <app-search-box [(query)]="searchQuery"></app-search-box>

        <app-filter-select
          label="Sinf"
          [options]="gradeOptions"
          [(value)]="selectedGrade">
        </app-filter-select>

        <app-filter-select
          label="Fan"
          [options]="subjectOptions"
          [(value)]="selectedSubject">
        </app-filter-select>
      </div>

      <div class="results">
        <p>Topildi: {{ filteredStudents().length }} ta</p>

        @for (student of filteredStudents(); track student.id) {
          <div class="student-card">
            <h3>{{ student.name }}</h3>
            <p>{{ student.grade }}-sinf | {{ student.subject }}</p>
          </div>
        } @empty {
          <p class="empty">Talabalar topilmadi</p>
        }
      </div>
    </div>
  `
})
export class StudentsFilterComponent {
  // State
  searchQuery = signal('');
  selectedGrade = signal('all');
  selectedSubject = signal('all');

  students = signal<Student[]>([
    { id: 1, name: 'Ali Valiyev', grade: 10, subject: 'Matematika' },
    { id: 2, name: 'Gulnora Karimova', grade: 11, subject: 'Fizika' },
    { id: 3, name: 'Sardor Rahimov', grade: 10, subject: 'Matematika' },
    { id: 4, name: 'Dilnoza Azizova', grade: 11, subject: 'Kimyo' }
  ]);

  // Options for filters
  gradeOptions = [
    { value: 'all', label: 'Hammasi' },
    { value: '10', label: '10-sinf' },
    { value: '11', label: '11-sinf' }
  ];

  subjectOptions = [
    { value: 'all', label: 'Hammasi' },
    { value: 'Matematika', label: 'Matematika' },
    { value: 'Fizika', label: 'Fizika' },
    { value: 'Kimyo', label: 'Kimyo' }
  ];

  // Computed - filtered students
  filteredStudents = computed(() => {
    let result = this.students();

    // Search
    const query = this.searchQuery().toLowerCase();
    if (query) {
      result = result.filter(s => s.name.toLowerCase().includes(query));
    }

    // Grade filter
    const grade = this.selectedGrade();
    if (grade !== 'all') {
      result = result.filter(s => s.grade === Number(grade));
    }

    // Subject filter
    const subject = this.selectedSubject();
    if (subject !== 'all') {
      result = result.filter(s => s.subject === subject);
    }

    return result;
  });
}
```

***

### 7. Eski vs Yangi - Taqqoslash

#### 7.1 Input

```tsx
// ❌ Eski
@Input() name: string = '';

// ✅ Yangi
name = input<string>('');

// ❌ Eski (required)
@Input({ required: true }) name!: string;

// ✅ Yangi (required)
name = input.required<string>();
```

#### 7.2 Output

```tsx
// ❌ Eski
@Output() clicked = new EventEmitter<void>();

// ✅ Yangi
clicked = output<void>();

// ❌ Eski (ma'lumot bilan)
@Output() valueChange = new EventEmitter<string>();

// ✅ Yangi (ma'lumot bilan)
valueChange = output<string>();
```

#### 7.3 Two-way Binding

```tsx
// ❌ Eski
@Input() value: string = '';
@Output() valueChange = new EventEmitter<string>();

// ✅ Yangi
value = model<string>('');
```

***

### 8. Best Practices

#### ✅ Yaxshi:

**1. input.required() ishlatish**

```tsx
// ✅ Majburiy input'lar uchun
id = input.required<number>();
title = input.required<string>();
```

**2. model() two-way binding uchun**

```tsx
// ✅ Two-way binding sodda
value = model<string>('');

// Ishlatish:
// <component [(value)]="data"></component>
```

**3. Aniq type berish**

```tsx
// ✅ Type safety
count = input<number>(0);
user = input<User | null>(null);
items = input<Item[]>([]);
```

**4. outputga type berish**

```tsx
// ✅ Type-safe output
itemSelected = output<Item>();
formSubmit = output<FormData>();
```

#### ❌ Yomon:

**1. Majburiy input uchun default**

```tsx
// ❌ Yomon - required ishlatish kerak
id = input<number>(0);  // 0 default bo'lmasligi kerak

// ✅ Yaxshi
id = input.required<number>();
```

**2. Any type**

```tsx
// ❌ Yomon
data = input<any>();

// ✅ Yaxshi
data = input<DataType>();
```

***

### 9. Xulosa

#### ✅ Yangi API afzalliklari:

**input():**

* Signal-based
* Type-safe
* Required support
* Transform support

**output():**

* Sodda sintaksis
* Type-safe
* EventEmitter yo'q

**model():**

* Two-way binding sodda
* Bir qatorda
* Signal-based

#### ✅ Qachon ishlatish:

| Feature        | Eski                     | Yangi            |
| -------------- | ------------------------ | ---------------- |
| Input          | @Input()                 | input()          |
| Required Input | @Input({required: true}) | input.required() |
| Output         | @Output() EventEmitter   | output()         |
| Two-way        | @Input + @Output         | model()          |

***

### 10. Nazorat Savollari

1. **input() va @Input() farqi nima?**
2. **input.required() nima uchun ishlatiladi?**
3. **output() qanday ishlaydi?**
4. **model() nima va nima uchun kerak?**
5. **input() signal qaytaradimi?**
6. **Transform input nima?**
7. **Alias nima uchun kerak?**
8. **model.required() bormi?**
9. **output() ma'lumot yuborishi mumkinmi?**
10. **Yangi API qaysi Angular versiyasidan?**

***

### 11. Test Savollari (14 ta)

**1. input() sintaksisi:**

A) `new Input<string>()`

B) `@Input() name: string`

C) `input.create<string>()`

D) `input<string>()`

**Javob: D**

***

**2. Required input:**

A) `input.required<string>()`

B) `input<string>({required: true})`

C) `@Input({required: true})`

**Javob: A**

***

**3. input() qiymatini o'qish:**

* A) `name.value`
* B) `name()`
* C) `name.get()`
* D) `name.read()`

**Javob: B**

***

**4. output() sintaksisi:**

* A) `output<void>()`
* B) `@Output() new EventEmitter()`
* C) `output.create()`
* D) `new Output()`

**Javob: A**

***

**5. output() emit:**

* A) `output.emit(value)`
* B) `output.send(value)`
* C) `output.fire(value)`
* D) `output(value)`

**Javob: A**

***

**6. model() nima?**

A) Faqat Input

B) Faqat Output

C) Input + Output

D) Signal

**Javob: C**

***

**7. model() ishlatish:**

A) `{{value}}`

B) `[value]="data"`

C) `(value)="data"`

D) `[(value)]="data"`

**Javob: D**

***

**8. input() signal mi?**

* A) Ha
* B) Yo'q
* C) Ba'zan
* D) Faqat required

**Javob: A**

***

**9. Transform input:**

A) `input(0, {transform: fn})`

B) `input.transform(fn)`

C) `@Input({transform: fn})`

D) A va C

**Javob: D**

***

**10. Alias:**

A) `input('', {alias: 'name'})`

B) `input.alias('name')`

C) `@Input('name')`

**Javob: A**

***

**11. model.required:**

A) `model<T>({required: true})`

B) `model.required<T>()`

C) `model` da required yo'q

**Javob: A**

***

**12. output type:**

A) `output: string`

B) `output.type<string>()`

C) `output<string>()`

D) `@Output() type: string`

**Javob: C**

***

**13. inputga default qiymat berish:**

* A) `input<number>(0)`
* B) `input(0)`
* C) A va B to'g'ri
* D) Default qiymat berib bo’lmaydi

**Javob: C**

***

**14. input() readonlymi yoki?**

* A) Ha, har doim
* B) Yo'q
* C) Faqat parent'da
* D) Faqat child'da

**Javob: A**

> [QuizBot](https://t.me/QuizBot?start=lu8l8UVw)

***

### 12. Amaliy Topshiriqlar

#### Topshiriq 1: Rating Component

* input: maxRating (5 yulduz)
* model: rating (two-way)
* output: ratingChange
* Click bo'yicha yulduzlar

***

#### Topshiriq 2: Pagination Component

* input.required: totalItems
* input: pageSize (default: 10)
* model: currentPage
* output: pageChange
* Previous/Next tugmalar

***

#### Topshiriq 3: Dropdown Component

* input.required: options
* input: placeholder
* model: selectedValue
* Custom styling

***

#### Topshiriq 4: Color Picker

* model: color (hex)
* input: presetColors
* output: colorSelected
* Preview box


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://odilbeks-organization.gitbook.io/angular-ustoz-shogirt/modern-component-api-input-output-model.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
