fix(badge): duplicate leftover badge after server-side render (#15417)

Fixes badges being left over if the current page was rendered via Angular Universal. This can cause issues, because the ids on the badges can clash.
This commit is contained in:
Kristiyan Kostadinov
2019-03-08 17:59:11 +01:00
committed by Joey Perrott
parent ddeeb18b0b
commit c5a32c214e
2 changed files with 62 additions and 5 deletions
+44 -4
View File
@@ -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: `
<span matBadge="Hello">
home
<div class="mat-badge-content">Pre-existing badge</div>
</span>
`
})
class PreExistingBadge {
}
@Component({
template: `
<span matBadge="Hello">
home
<span matBadge="Hi">Something</span>
</span>
`
})
class NestedBadge {
}
+18 -1
View File
@@ -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);
}
}
}
}