Привет, Хабр! Представляю вашему вниманию перевод статьи «Different Ways to Pass Inputs to a Component in Angular» автора Netanel Basal.
В этой статье, мы разберём три разных способа передачи данных в компонент. В следующем примере мы будем использовать select как главный компонент, но методы, используемые в нём релевантны и в других компонентах.
Создадим компонент select, который получает следующие входные данные — size и placement.
Первый метод, с которым мы все знакомы — использование декорантора Input.
И этот код отлично работает, за исключением того, что он не такой гибкий. Например нам нужно задать переменной size значение large для любого select в нашем приложении. Таким образом мы должны разрешить клиетну переписать любой input на глобальном уровне.
Для этого мы можем использовать функцию внедрения зависимостей Angular.
Для начала нам нужно создать конфигурацию провайдера. Этот провайдер может быть использован как token, type, а также задавать значения по умолчанию для каждого input. Используем это в нашем компоненте select:
Теперь мы можем переписать выбранные inputs на уровне нашего приложения:
Но это не всё. Так же мы можем использовать это для передачи различных inputs на уровне компонентов. Например у нас есть компонент, который мы используем несколько раз в приложении. В каждом случае нам нужно использовать величину small:
Мы можем добавить это в компонет providers и эта величина будет использована для всех компонентов, объявленных и дочерних в шаблонах. Но мы всё ещё можем переписать эту переменную, напрямую следующим образом:
Такую же стратегию применяют для lazy modules потому что она создают новую инъекцию.
Предположим у нас есть компоненты с множеством входных данных. Мы устанавливаем одинаковые значения для большинства из них. В примере это будет выглядеть так:
Мы можем повторять эти значения, но можем создать директиву, которая передаст необходимые значения всех переменных:
И мы можем использовать эту директиву где нам нужно:
В этой статье, мы разберём три разных способа передачи данных в компонент. В следующем примере мы будем использовать select как главный компонент, но методы, используемые в нём релевантны и в других компонентах.
Создадим компонент select, который получает следующие входные данные — size и placement.
Использование Inputs
Первый метод, с которым мы все знакомы — использование декорантора Input.
@Component({
selector: 'app-select',
template: `
<p><b>Size</b> {{ size }}</p>
<p><b>Placement:</b> {{ placement }}</p>
`
})
export class SelectComponent {
@Input() size: 'sm' | 'md' | 'lg' = 'md';
@Input() placement: 'top' | 'bottom' | 'right' | 'left' = 'bottom'
}
И этот код отлично работает, за исключением того, что он не такой гибкий. Например нам нужно задать переменной size значение large для любого select в нашем приложении. Таким образом мы должны разрешить клиетну переписать любой input на глобальном уровне.
Использование зависимости Injection
Для этого мы можем использовать функцию внедрения зависимостей Angular.
import { InjectionToken, Injectable } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class SelectConfig {
size: 'sm' | 'md' | 'lg' = 'md'
placement: 'top' | 'bottom' | 'right' | 'left' = 'bottom';
}
export function setSelectConfig(config: Partial<SelectConfig>) {
return {
...new SelectConfig(),
...config
}
}
Для начала нам нужно создать конфигурацию провайдера. Этот провайдер может быть использован как token, type, а также задавать значения по умолчанию для каждого input. Используем это в нашем компоненте select:
@Component({
selector: 'app-select',
template: `
<p><b>Size</b> {{ size }}</p>
<p><b>Placement:</b> {{ placement }}</p>
`
})
export class SelectComponent {
@Input() size: SelectConfig['size'];
@Input() placement: SelectConfig['placement'];
constructor(private config: SelectConfig) {
this.size = config.size;
this.placement = config.placement;
}
}
Теперь мы можем переписать выбранные inputs на уровне нашего приложения:
@NgModule({
providers: [
{
provide: SelectConfig,
useValue: setSelectConfig({
size: 'lg'
})
}
]
bootstrap: [AppComponent]
})
export class AppModule { }
Но это не всё. Так же мы можем использовать это для передачи различных inputs на уровне компонентов. Например у нас есть компонент, который мы используем несколько раз в приложении. В каждом случае нам нужно использовать величину small:
@Component({
selector: 'app-todos-page',
template: `<app-select></app-select>`,
providers: [
{
provide: SelectConfig,
useValue: setSelectConfig({
size: 'sm'
})
}
]
})
export class TodosPageComponent {}
Мы можем добавить это в компонет providers и эта величина будет использована для всех компонентов, объявленных и дочерних в шаблонах. Но мы всё ещё можем переписать эту переменную, напрямую следующим образом:
@Component({
selector: 'app-todos-page',
template: `
<app-select></app-select>
<app-select size="lg"></app-select>
`,
providers: [
{
provide: SelectConfig,
useValue: setSelectConfig({
size: 'sm'
})
}
]
})
export class TodosPageComponent {}
Такую же стратегию применяют для lazy modules потому что она создают новую инъекцию.
Использование Directives
Предположим у нас есть компоненты с множеством входных данных. Мы устанавливаем одинаковые значения для большинства из них. В примере это будет выглядеть так:
<!-- It can be in the same template or in different places in the app -->
<app-select size="lg" position="right" inputThree="someValue"></app-select>
<app-select size="lg" position="right" inputThree="someValue"></app-select>
<app-select size="lg" position="right inputThree="someValue"></app-select>
<app-select size="lg" position="right" inputThree="someValue"></app-select>
<app-select size="lg" position="right" inputThree="someValue"></app-select>
Мы можем повторять эти значения, но можем создать директиву, которая передаст необходимые значения всех переменных:
@Directive({
selector: '[selectConfigOne]',
providers: [{
provide: SelectConfig,
useValue: setSelectConfig({
size: 'lg',
placement: 'right',
inputThree: 'someValue'
})
}]
})
export class SelectConfigOneDirective {}
И мы можем использовать эту директиву где нам нужно:
<h1>Using Inputs</h1>
<app-select size="lg"></app-select>
<app-select placement="top"></app-select>
<h1>Using a Directive</h1>
<app-select selectConfigOne></app-select>
<app-todos-page></app-todos-page>