-
Notifications
You must be signed in to change notification settings - Fork 6.8k
fix(material/badge): correctly apply badge description #23562
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
10c26e6
to
b342398
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with a few nits.
src/material/badge/badge.ts
Outdated
} | ||
|
||
this._content = newContentNormalized; | ||
this._hasContent = !!newContentNormalized; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this a little redundant considering that we can check this._content
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point, now that it always normalizes the content this is unnecessary. Removed.
@@ -84,22 +85,20 @@ export class MatBadge extends _MatBadgeBase implements OnDestroy, OnChanges, Can | |||
@Input('matBadgePosition') position: MatBadgePosition = 'above after'; | |||
|
|||
/** The content for the badge */ | |||
@Input('matBadge') content: string | number | undefined | null; | |||
@Input('matBadge') | |||
get content(): string | number | undefined | null { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could pull the string | number | undefined | null
into a type so we don't have to repeat it in 3 places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ack, I'm going to leave as-is for now.
b342398
to
45f8086
Compare
45f8086
to
3abc4a1
Compare
I've made a small change to this PR so that the badge element isn't added to the DOM until |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will work 👍 .
It could be less confusing for a reader of this code to understand when we need to create the badge element. I have suggestions in the above comments, but that is not a big enough problem to be a blocker for me.
src/material/badge/badge.ts
Outdated
// ViewEngine only: when creating a badge through the Renderer, Angular remembers its index. | ||
// We have to destroy it ourselves, otherwise it'll be retained in memory. | ||
if (this._renderer.destroyNode) { | ||
this._renderer.destroyNode!(this._badgeElement); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: this non-null assert shouldn't be necessary since we truthy checked it in the if-statement's condition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
// on which the badge is attached won't necessarily be in the DOM until this point. | ||
this._clearExistingBadges(); | ||
|
||
if (this.content && !this._badgeElement) { | ||
this._badgeElement = this._createBadgeElement(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO: it's confusing that _updateContent
sometimes handles creating the badge element, and sometimes the caller handles it. I spent a few minutes head scratching and thinking through the event lifecycle to figure this out.
From the method's description: /** Update the text content of the badge. */
. In this situation it would make more sense for _updateContent
to do that one thing, and not do anything else. It's up to the caller to make sure the badge element is created.
I suggest making the caller handle creating the badge element, or making _updateContent
create the badge element in all situations, or making a _createBadgeElementIfNotExists
(final name depends on bike shedding) method to handle creating the badge element in a single place.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that the logic could be organized more cleanly here, but I want to avoid refactoring any more than I've already done here. As a middle ground, I've renamed _updateContent
to _updateRenderedContent`, which I think does a better job of capturing that it may create a DOM element if it doesn't already exist.
src/material/badge/badge.ts
Outdated
private _updateHostAriaDescription(newDescription: string, oldDescription: string): void { | ||
// ensure content available before setting label | ||
const content = this._updateTextContent(); | ||
/** Update the text content of the badge. */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and also create the badge element for when
OnChanges
happens
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to
/** Update the text content of the badge element in the DOM, creating the element if necessary. */
Previously, `MatBadge` was applying the provided description as an `aria-label` to the badge content element, which is a child element of the badge host. Then it was _also_ applying an `aria-describedby` to that same content element. The end result is that the badge was being treated mainly as text content for a control, which isn't really the best way to convey its complmentary nature. This behavior was causing problems in NVDA, where the badge content was overriding the host button's label. This change makes the badge content itself `aria-hidden` and applies the badge description to the badge's _host_ element via `aria-describedby` and completely removes any setting of `aria-label`. It also makes a handful of minor cleanup refactorings.
3abc4a1
to
d31965e
Compare
Previously, `MatBadge` was applying the provided description as an `aria-label` to the badge content element, which is a child element of the badge host. Then it was _also_ applying an `aria-describedby` to that same content element. The end result is that the badge was being treated mainly as text content for a control, which isn't really the best way to convey its complmentary nature. This behavior was causing problems in NVDA, where the badge content was overriding the host button's label. This change makes the badge content itself `aria-hidden` and applies the badge description to the badge's _host_ element via `aria-describedby` and completely removes any setting of `aria-label`. It also makes a handful of minor cleanup refactorings. (cherry picked from commit f5883db)
…ar#23562)" This reverts commit 6b71169. Reverts this badge fix because it relies on a querySelector API that is not supported in IE11. Related to angular#23736
This issue has been automatically locked due to inactivity. Read more about our automatic conversation locking policy. This action has been performed automatically by a bot. |
Previously,
MatBadge
was applying the provided description as anaria-label
to the badge content element, which is a child element of the badge host. Then it was also applying anaria-describedby
to that same content element. The end result is that the badge was being treated mainly as text content for a control, which isn't really the best way to convey its complementary nature. This behavior was causing problems in NVDA, where the badge content was overriding the host button's label.This change makes the badge content itself
aria-hidden
and applies the badge description to the badge's host element viaaria-describedby
and completely removes any setting ofaria-label
. It also makes a handful of minor cleanup refactorings.cc @zarend @amysorto