diff --git a/src/lib/badge/badge.spec.ts b/src/lib/badge/badge.spec.ts index 8933239d52c1..a06737df9b5a 100644 --- a/src/lib/badge/badge.spec.ts +++ b/src/lib/badge/badge.spec.ts @@ -11,10 +11,12 @@ describe('MatBadge', () => { let badgeDebugElement: DebugElement; beforeEach(fakeAsync(() => { - TestBed.configureTestingModule({ - imports: [MatBadgeModule], - declarations: [BadgeTestApp], - }).compileComponents(); + TestBed + .configureTestingModule({ + imports: [MatBadgeModule], + declarations: [BadgeTestApp, PreExistingBadge, NestedBadge], + }) + .compileComponents(); fixture = TestBed.createComponent(BadgeTestApp); testComponent = fixture.debugElement.componentInstance; @@ -184,6 +186,20 @@ describe('MatBadge', () => { expect(badgeContent.hasAttribute('aria-label')).toBe(false); }); + it('should clear any pre-existing badges', () => { + const preExistingFixture = TestBed.createComponent(PreExistingBadge); + preExistingFixture.detectChanges(); + + expect(preExistingFixture.nativeElement.querySelectorAll('.mat-badge-content').length).toBe(1); + }); + + it('should not clear badge content from child elements', () => { + const preExistingFixture = TestBed.createComponent(NestedBadge); + preExistingFixture.detectChanges(); + + expect(preExistingFixture.nativeElement.querySelectorAll('.mat-badge-content').length).toBe(2); + }); + }); /** Test component that contains a MatBadge. */ @@ -214,3 +230,27 @@ class BadgeTestApp { badgeDescription: string; badgeDisabled = false; } + + +@Component({ + template: ` + + home +
Pre-existing badge
+
+ ` +}) +class PreExistingBadge { +} + + +@Component({ + template: ` + + home + Something + + ` +}) +class NestedBadge { +} diff --git a/src/lib/badge/badge.ts b/src/lib/badge/badge.ts index 6a396ccf344f..42aca1cfa044 100644 --- a/src/lib/badge/badge.ts +++ b/src/lib/badge/badge.ts @@ -177,9 +177,12 @@ export class MatBadge extends _MatBadgeMixinBase implements OnDestroy, CanDisabl const rootNode = this._renderer || this._document; const badgeElement = rootNode.createElement('span'); const activeClass = 'mat-badge-active'; + const contentClass = 'mat-badge-content'; + // Clear any existing badges which may have persisted from a server-side render. + this._clearExistingBadges(contentClass); badgeElement.setAttribute('id', `mat-badge-content-${this._id}`); - badgeElement.classList.add('mat-badge-content'); + badgeElement.classList.add(contentClass); badgeElement.textContent = this.content; if (this._animationMode === 'NoopAnimations') { @@ -232,4 +235,18 @@ export class MatBadge extends _MatBadgeMixinBase implements OnDestroy, CanDisabl } } + /** Clears any existing badges that might be left over from server-side rendering. */ + private _clearExistingBadges(cssClass: string) { + const element = this._elementRef.nativeElement; + let childCount = element.children.length; + + // Use a reverse while, because we'll be removing elements from the list as we're iterating. + while (childCount--) { + const currentChild = element.children[childCount]; + + if (currentChild.classList.contains(cssClass)) { + element.removeChild(currentChild); + } + } + } }