Skip to content
This repository was archived by the owner on Sep 5, 2024. It is now read-only.

Commit 0d238dd

Browse files
devversionThomasBurleson
authored andcommitted
fix(list): copy ng-show, ng-hide and ng-if to secondary item parent.
* Once a developer specifies a secondary item, which is not a button, but contains a `ng-click` on it, we automatically create a button, which holds the actual secondary item. We copy all necessary attributes from the secondary item to the new generated button. * Developers may have specified a ng-show, ng-hide, ng-if on the secondary item. But those attributes will stay on the secondary item, which is not correct. Those attributes should be copied to the new generated button, because we want to hide the complete *secondary item*. Fixes #8794. Closes #8796
1 parent 46cc7f4 commit 0d238dd

File tree

2 files changed

+57
-5
lines changed

2 files changed

+57
-5
lines changed

src/components/list/list.js

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -349,12 +349,21 @@ function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
349349
}
350350

351351
function wrapSecondaryItem(secondaryItem, container) {
352+
// If the current secondary item is not a button, but contains a ng-click attribute,
353+
// the secondary item will be automatically wrapped inside of a button.
352354
if (secondaryItem && !isButton(secondaryItem) && secondaryItem.hasAttribute('ng-click')) {
355+
353356
$mdAria.expect(secondaryItem, 'aria-label');
354357
var buttonWrapper = angular.element('<md-button class="md-secondary md-icon-button">');
355-
copyAttributes(secondaryItem, buttonWrapper[0]);
358+
359+
// Copy the attributes from the secondary item to the generated button.
360+
// We also support some additional attributes from the secondary item,
361+
// because some developers may use a ngIf, ngHide, ngShow on their item.
362+
copyAttributes(secondaryItem, buttonWrapper[0], ['ng-if', 'ng-hide', 'ng-show']);
363+
356364
secondaryItem.setAttribute('tabindex', '-1');
357365
buttonWrapper.append(secondaryItem);
366+
358367
secondaryItem = buttonWrapper[0];
359368
}
360369

@@ -368,16 +377,28 @@ function mdListItemDirective($mdAria, $mdConstant, $mdUtil, $timeout) {
368377
container.append(secondaryItem);
369378
}
370379

371-
function copyAttributes(item, wrapper) {
380+
/**
381+
* Copies attributes from a source element to the destination element
382+
* By default the function will copy the most necessary attributes, supported
383+
* by the button executor for clickable list items.
384+
* @param source Element with the specified attributes
385+
* @param destination Element which will retrieve the attributes
386+
* @param extraAttrs Additional attributes, which will be copied over.
387+
*/
388+
function copyAttributes(source, destination, extraAttrs) {
372389
var copiedAttrs = $mdUtil.prefixer([
373390
'ng-if', 'ng-click', 'ng-dblclick', 'aria-label', 'ng-disabled', 'ui-sref',
374391
'href', 'ng-href', 'target', 'ng-attr-ui-sref', 'ui-sref-opts'
375392
]);
376393

394+
if (extraAttrs) {
395+
copiedAttrs = copiedAttrs.concat($mdUtil.prefixer(extraAttrs));
396+
}
397+
377398
angular.forEach(copiedAttrs, function(attr) {
378-
if (item.hasAttribute(attr)) {
379-
wrapper.setAttribute(attr, item.getAttribute(attr));
380-
item.removeAttribute(attr);
399+
if (source.hasAttribute(attr)) {
400+
destination.setAttribute(attr, source.getAttribute(attr));
401+
source.removeAttribute(attr);
381402
}
382403
});
383404
}

src/components/list/list.spec.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,37 @@ describe('mdListItem directive', function() {
289289
expect(secondaryContainer.children()[0].nodeName).toBe('MD-BUTTON');
290290
});
291291

292+
it('should copy ng-show to the generated button parent of a clickable secondary item', function() {
293+
var listItem = setup(
294+
'<md-list-item ng-click="sayHello()">' +
295+
'<p>Hello World</p>' +
296+
'<md-icon class="md-secondary" ng-show="isShown" ng-click="goWild()"></md-icon>' +
297+
'</md-list-item>');
298+
299+
// First child is our button wrap
300+
var firstChild = listItem.children().eq(0);
301+
expect(firstChild[0].nodeName).toBe('DIV');
302+
303+
expect(listItem).toHaveClass('_md-button-wrap');
304+
305+
// It should contain three elements, the button overlay, inner content
306+
// and the secondary container.
307+
expect(firstChild.children().length).toBe(3);
308+
309+
var secondaryContainer = firstChild.children().eq(2);
310+
expect(secondaryContainer).toHaveClass('_md-secondary-container');
311+
312+
// The secondary container should contain the md-icon,
313+
// which has been transformed to an icon button.
314+
var iconButton = secondaryContainer.children()[0];
315+
316+
expect(iconButton.nodeName).toBe('MD-BUTTON');
317+
expect(iconButton.hasAttribute('ng-show')).toBe(true);
318+
319+
// The actual `md-icon` element, should not have the ng-show attribute anymore.
320+
expect(iconButton.firstElementChild.hasAttribute('ng-show')).toBe(false);
321+
});
322+
292323
it('moves multiple md-secondary items outside of the button', function() {
293324
var listItem = setup(
294325
'<md-list-item ng-click="sayHello()">' +

0 commit comments

Comments
 (0)