Skip to content

feat(list): add new '<mat-action-list>' #12415

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

Merged
merged 5 commits into from
Sep 11, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/demo-app/list/list-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,15 @@ <h2>Nav lists</h2>
</mat-nav-list>
</div>

<div>
<h2>Action list</h2>
<mat-action-list>
<button mat-list-item *ngFor="let link of links" (click)="alertItem(link.name)">
{{link.name}}
</button>
</mat-action-list>
</div>

<div>
<h2>Selection list</h2>

Expand Down
1 change: 0 additions & 1 deletion src/demo-app/list/list-demo.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
border: 1px solid rgba(0, 0, 0, 0.12);
width: 350px;
margin: 20px 20px 0 0;

}
h2 {
margin-top: 20px;
Expand Down
4 changes: 4 additions & 0 deletions src/demo-app/list/list-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,8 @@ export class ListDemo {
this.selectedOptions = values;
this.modelChangeEventCount++;
}

alertItem(msg: string) {
alert(msg);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe use a snack bar instead?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A snack bar will look nicer. It can be done later in my opinion. I am new to angular, so try to do small check in without taking too long to deal with merge conflict etc.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This app is only for our own development, so it doesn't really matter what the action does.

}
}
14 changes: 14 additions & 0 deletions src/lib/list/list.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,20 @@ element in an `<mat-list-item>`.
</mat-nav-list>
```

### Action lists

Use the `<mat-action-list>` element when each item in the list performs some _action_. Each item
in an action list is a `<button>` element.

Simple action lists can use the `mat-list-item` attribute on button tag elements directly:

```html
<mat-action-list>
<button mat-list-item (click)="save()"> Save </button>
<button mat-list-item (click)="undo()"> Undo </button>
</mat-action-list>
```

### Selection lists
A selection list provides an interface for selecting values, where each list item is an option.

Expand Down
16 changes: 16 additions & 0 deletions src/lib/list/list.scss
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,22 @@ $mat-list-item-inset-divider-offset: 72px;
}
}

mat-action-list {
//remove the native button look and make it look like a list item
button {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this apply to all buttons for any .mat-list-item not just the ones under a mat-action-list?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we talked, we added mat-action-list specifically for action list to make it more clear, so the idea is to let user use it under mat-action-list.

background: none;
color: inherit;
border: none;
font: inherit;
outline: inherit;
}

.mat-list-item {
cursor: pointer;
outline: inherit;
}
}

.mat-list-option:not(.mat-list-item-disabled) {
cursor: pointer;
outline: none;
Expand Down
46 changes: 46 additions & 0 deletions src/lib/list/list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ describe('MatList', () => {
ListWithMultipleItems,
ListWithManyLines,
NavListWithOneAnchorItem,
ActionListWithoutType,
ActionListWithType
],
});

Expand Down Expand Up @@ -144,6 +146,30 @@ describe('MatList', () => {
items.forEach(item => expect(item._isRippleDisabled()).toBe(true));
});

it('should create an action list', () => {
const fixture = TestBed.createComponent(ActionListWithoutType);
fixture.detectChanges();

const items = fixture.componentInstance.listItems;
expect(items.length).toBeGreaterThan(0);
});

it('should set default type attribute to button for action list', () => {
const fixture = TestBed.createComponent(ActionListWithoutType);
fixture.detectChanges();

const listItemEl = fixture.debugElement.query(By.css('.mat-list-item'));
expect(listItemEl.nativeElement.getAttribute('type')).toBe('button');
});

it('should not change type attribute if it is already specified', () => {
const fixture = TestBed.createComponent(ActionListWithType);
fixture.detectChanges();

const listItemEl = fixture.debugElement.query(By.css('.mat-list-item'));
expect(listItemEl.nativeElement.getAttribute('type')).toBe('submit');
});

it('should allow disabling ripples for the whole nav-list', () => {
let fixture = TestBed.createComponent(NavListWithOneAnchorItem);
fixture.detectChanges();
Expand Down Expand Up @@ -195,6 +221,26 @@ class NavListWithOneAnchorItem extends BaseTestList {
disableListRipple: boolean = false;
}

@Component({template: `
<mat-action-list>
<button mat-list-item>
Paprika
</button>
</mat-action-list>`})
class ActionListWithoutType extends BaseTestList {
@ViewChildren(MatListItem) listItems: QueryList<MatListItem>;
}

@Component({template: `
<mat-action-list>
<button mat-list-item type="submit">
Paprika
</button>
</mat-action-list>`})
class ActionListWithType extends BaseTestList {
@ViewChildren(MatListItem) listItems: QueryList<MatListItem>;
}

@Component({template: `
<mat-list>
<mat-list-item>
Expand Down
12 changes: 10 additions & 2 deletions src/lib/list/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ export class MatNavList extends _MatListMixinBase implements CanDisableRipple {}

@Component({
moduleId: module.id,
selector: 'mat-list',
selector: 'mat-list, mat-action-list',
exportAs: 'matList',
templateUrl: 'list.html',
host: {'class': 'mat-list'},
Expand Down Expand Up @@ -100,7 +100,7 @@ export class MatListSubheaderCssMatStyler {}
/** An item within a Material Design list. */
@Component({
moduleId: module.id,
selector: 'mat-list-item, a[mat-list-item]',
selector: 'mat-list-item, a[mat-list-item], button[mat-list-item]',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll need to add documentation for the new list variant to list.md

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last thing that occurred to me just now- we should default all buttons with mat-list-item to have type="button". By default, <button> elements are type="submit", which you would never really want in an action list.

exportAs: 'matListItem',
host: {
'class': 'mat-list-item',
Expand All @@ -127,6 +127,14 @@ export class MatListItem extends _MatListItemMixinBase implements AfterContentIn
@Optional() private _navList: MatNavList) {
super();
this._isNavList = !!_navList;

// If no type attributed is specified for <button>, set it to "button".
// If a type attribute is already specified, do nothing.
const element = this._getHostElement();
if (element.nodeName && element.nodeName.toLowerCase() === 'button'
&& !element.hasAttribute('type')) {
element.setAttribute('type', 'button');
}
}

ngAfterContentInit() {
Expand Down