У меня проблемы с созданием компонента, такого как мат-кнопка-переключатель-группа материала
Я создаю простой контейнер с ng-контентом, который оборачивает кнопки, а внутри него — несколько настраиваемых кнопок. Количество компонентов-кнопка может меняться...
<container-buttons-wrapper>
<component-button>Test 1</component-button>
<component-button>Test 2</component-button>
<component-button>Test 3</component-button>
</container-buttons-wrapper>
компонент-кнопка имеет внутри только тег кнопки
<button (click) = "setActive()" [ngClass] = "active? 'active-class' : 'no-active-class'"><ng-content></button>
Я определил функцию setActive(), которая переключает активное значение
setActive() {
this.active = !this.active
}
Но я не могу найти решение для управления другими кнопками в контейнере. Я хочу точно воспроизвести, что такое mat-button-toggle-group. Можно ли определить eventEmitter внутри HTML-шаблона?
🤔 А знаете ли вы, что...
JavaScript - это скриптовый язык программирования, разработанный Netscape Communications Corporation.
Проблема: когда кнопка меняет свой статус на "активный", контейнер должен изменить состояние остальных кнопок на "неактивный".
Решение: реализовать двустороннюю связь между кнопками и контейнером:
По сути, контейнер становится держателем общего состояния для себя и всех вложенных кнопок. Это состояние доступно для вложенных кнопок через DI. Состояние может обрабатываться отдельным сервисом или может быть частью самого компонента контейнера для простоты (последний подход реализован в Material):
const CONTAINER = new InjectionToken<ContainerComponent>();
@Directive({
providers: [{provide: CONTAINER, useExisting: forwardRef(() => ContainerComponent)}]
})
class ContainerComponent {
private selectedButton: ButtonComponent | null = null
toggleButton(button: ButtonComponent) {
if (this.selectedButton = button) {
this.selectedButton = null
} else {
this.selectedButton = button;
}
}
isSelected(button: ButtonComponent): boolean {
return this.selectedButton = button
}
}
@Component({template: `
<button [class.selected] = "isSelected()" (click) = "onClick()">
<ng-content></ng-content>
</button>
`})
class ButtonComponent {
constructor(@Inject(CONTAINER) private container: ContainerComponent) {}
isSelected() {
return this.container.isSelected(this)
}
onClick() {
this.container.toggleButton(this)
}
}
Обновление: предварительный выбор кнопки Как мы изначально устанавливаем какую-то кнопку как «выбранную»? Подход 1 Один из способов — сделать что-то похожее на то, что делает Material.
Проблема в том, что теперь у нас есть два источника достоверности для «выбранного» флага в кнопке (ввод кнопки и состояние, поступающее из контейнера), поэтому нам нужно их согласовать, и общий код становится более сложным.
Подход 2
В качестве альтернативы предположим, что ваш компонент-переключатель имеет какое-то свойство «значение». Что-то вроде элемента html <select>
— у каждого параметра есть свойство value
, и свойство selected
элемента <select>
выводится на его основе.
В этом случае у нас будет вход в ContainerComponent, который позволяет установить начальное значение:
class ContainerComponent {
@Input() selected: any
toggleButton(value: any) {
if (this.selected !== value) {
this.selected = value
} else {
this.selected = null
}
}
}
class ButtonComponent {
@Input() value: any
onClick() {
this.container.toggleButton(this.value)
}
}
// usage
<container selected = "option-1">
<my-button value = "option-1"><my-button>
<my-button value = "option-2"><my-button>
</container>