Skip to content

Commit 21f8bbb

Browse files
committed
fix(material/badge): allow badge defaults to be configured (#33312)
Allows users to configure the defaults for badges for the entire app. Fixes #27844. (cherry picked from commit 2384aed)
1 parent 8c8d1a1 commit 21f8bbb

4 files changed

Lines changed: 81 additions & 7 deletions

File tree

goldens/material/badge/index.api.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,13 @@ import { AfterViewInit } from '@angular/core';
88
import * as i0 from '@angular/core';
99
import * as i1 from '@angular/cdk/a11y';
1010
import * as i2 from '@angular/cdk/bidi';
11+
import { InjectionToken } from '@angular/core';
1112
import { OnDestroy } from '@angular/core';
1213
import { OnInit } from '@angular/core';
1314

15+
// @public
16+
export const MAT_BADGE_CONFIG: InjectionToken<MatBadgeConfig>;
17+
1418
// @public
1519
export class MatBadge implements OnInit, AfterViewInit, OnDestroy {
1620
constructor();
@@ -46,6 +50,14 @@ export class MatBadge implements OnInit, AfterViewInit, OnDestroy {
4650
static ɵfac: i0.ɵɵFactoryDeclaration<MatBadge, never>;
4751
}
4852

53+
// @public
54+
export interface MatBadgeConfig {
55+
color?: ThemePalette;
56+
overlap?: boolean;
57+
position?: MatBadgePosition;
58+
size?: MatBadgeSize;
59+
}
60+
4961
// @public (undocumented)
5062
export class MatBadgeModule {
5163
// (undocumented)

src/material/badge/badge.spec.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
import {By} from '@angular/platform-browser';
1111
import {MatBadge, MatBadgeModule, MatBadgePosition, MatBadgeSize} from './index';
1212
import {ThemePalette} from '../core';
13+
import {MAT_BADGE_CONFIG, MatBadgeConfig} from './badge';
1314

1415
describe('MatBadge', () => {
1516
let fixture: ComponentFixture<any>;
@@ -265,6 +266,31 @@ describe('MatBadge', () => {
265266
.toBeFalse();
266267
});
267268
});
269+
270+
it('should be able to specify default values through DI', () => {
271+
TestBed.configureTestingModule({
272+
providers: [
273+
{
274+
provide: MAT_BADGE_CONFIG,
275+
useValue: {
276+
color: 'accent',
277+
overlap: false,
278+
position: 'below before',
279+
size: 'large',
280+
} satisfies MatBadgeConfig,
281+
},
282+
],
283+
});
284+
285+
const fixture = TestBed.createComponent(SimpleBadge);
286+
fixture.detectChanges();
287+
const badge = fixture.componentInstance.badgeInstance;
288+
289+
expect(badge.color).toBe('accent');
290+
expect(badge.overlap).toBe(false);
291+
expect(badge.position).toBe('below before');
292+
expect(badge.size).toBe('large');
293+
});
268294
});
269295

270296
/** Test component that contains a MatBadge. */
@@ -333,9 +359,20 @@ class PreExistingBadge {}
333359
class NestedBadge {}
334360

335361
@Component({
336-
template: `
337-
<ng-template matBadge="1">Notifications</ng-template>`,
362+
template: `<ng-template matBadge="1">Notifications</ng-template>`,
338363
imports: [MatBadgeModule],
339364
changeDetection: ChangeDetectionStrategy.Eager,
340365
})
341366
class BadgeOnTemplate {}
367+
368+
@Component({
369+
template: `
370+
<button matBadge="Hello">
371+
home
372+
</button>
373+
`,
374+
imports: [MatBadgeModule],
375+
})
376+
class SimpleBadge {
377+
@ViewChild(MatBadge) badgeInstance!: MatBadge;
378+
}

src/material/badge/badge.ts

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
ViewEncapsulation,
2323
DOCUMENT,
2424
AfterViewInit,
25+
InjectionToken,
2526
} from '@angular/core';
2627
import {_animationsDisabled, ThemePalette} from '../core';
2728
import {_CdkPrivateStyleLoader, _VisuallyHiddenLoader} from '@angular/cdk/private';
@@ -40,6 +41,24 @@ export type MatBadgePosition =
4041
/** Allowed size options for matBadgeSize */
4142
export type MatBadgeSize = 'small' | 'medium' | 'large';
4243

44+
/** Object that can be used to configure the default options for the badge component. */
45+
export interface MatBadgeConfig {
46+
/** Default position for badges. */
47+
position?: MatBadgePosition;
48+
49+
/** Default size for badges. */
50+
size?: MatBadgeSize;
51+
52+
/** Default color to apply to all badges. */
53+
color?: ThemePalette;
54+
55+
/** Whether badges should overlap by default. */
56+
overlap?: boolean;
57+
}
58+
59+
/** Injection token that can be used to configure the default options for the badge component. */
60+
export const MAT_BADGE_CONFIG = new InjectionToken<MatBadgeConfig>('MAT_BADGE_CONFIG');
61+
4362
const BADGE_CONTENT_CLASS = 'mat-badge-content';
4463

4564
/**
@@ -93,10 +112,10 @@ export class MatBadge implements OnInit, AfterViewInit, OnDestroy {
93112
this._setColor(value);
94113
this._color = value;
95114
}
96-
private _color: ThemePalette = 'primary';
115+
private _color: ThemePalette;
97116

98117
/** Whether the badge should overlap its contents or not */
99-
@Input({alias: 'matBadgeOverlap', transform: booleanAttribute}) overlap: boolean = true;
118+
@Input({alias: 'matBadgeOverlap', transform: booleanAttribute}) overlap: boolean;
100119

101120
/** Whether the badge is disabled. */
102121
@Input({alias: 'matBadgeDisabled', transform: booleanAttribute}) disabled: boolean = false;
@@ -105,7 +124,7 @@ export class MatBadge implements OnInit, AfterViewInit, OnDestroy {
105124
* Position the badge should reside.
106125
* Accepts any combination of 'above'|'below' and 'before'|'after'
107126
*/
108-
@Input('matBadgePosition') position: MatBadgePosition = 'above after';
127+
@Input('matBadgePosition') position: MatBadgePosition;
109128

110129
/** The content for the badge */
111130
@Input('matBadge')
@@ -128,7 +147,7 @@ export class MatBadge implements OnInit, AfterViewInit, OnDestroy {
128147
private _description!: string;
129148

130149
/** Size of the badge. Can be 'small', 'medium', or 'large'. */
131-
@Input('matBadgeSize') size: MatBadgeSize = 'medium';
150+
@Input('matBadgeSize') size: MatBadgeSize;
132151

133152
/** Whether the badge is hidden. */
134153
@Input({alias: 'matBadgeHidden', transform: booleanAttribute}) hidden: boolean = false;
@@ -148,10 +167,16 @@ export class MatBadge implements OnInit, AfterViewInit, OnDestroy {
148167
private _document = inject(DOCUMENT);
149168

150169
constructor() {
170+
const config = inject(MAT_BADGE_CONFIG, {optional: true});
151171
const styleLoader = inject(_CdkPrivateStyleLoader);
152172
styleLoader.load(_MatBadgeStyleLoader);
153173
styleLoader.load(_VisuallyHiddenLoader);
154174

175+
this._color = config?.color || 'primary';
176+
this.overlap = config?.overlap ?? true;
177+
this.position = config?.position || 'above after';
178+
this.size = config?.size || 'medium';
179+
155180
if (typeof ngDevMode === 'undefined' || ngDevMode) {
156181
const nativeElement = this._elementRef.nativeElement;
157182

src/material/badge/public-api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
*/
88

99
export * from './badge-module';
10-
export {MatBadge, MatBadgePosition, MatBadgeSize} from './badge';
10+
export {MatBadge, MatBadgePosition, MatBadgeSize, MAT_BADGE_CONFIG, MatBadgeConfig} from './badge';

0 commit comments

Comments
 (0)