Skip to content

Commit

Permalink
fix(button-group): make routerLinkActive work on clr-button (#1689)
Browse files Browse the repository at this point in the history
CDE-2563
kevinbuhmann authored Jan 29, 2025

Verified

This commit was signed with the committer’s verified signature. The key has expired.
zakkak Foivos Zakkak
1 parent 22e8807 commit 04d4d09
Showing 9 changed files with 151 additions and 10 deletions.
8 changes: 5 additions & 3 deletions projects/angular/clarity.api.md
Original file line number Diff line number Diff line change
@@ -589,7 +589,7 @@ export class ClrBreadcrumbsModule {

// @public (undocumented)
export class ClrButton implements LoadingListener {
constructor(buttonInGroupService: ButtonInGroupService);
constructor(routerLinkActive: RouterLinkActive, buttonInGroupService: ButtonInGroupService);
// Warning: (ae-forgotten-export) The symbol "ButtonInGroupService" needs to be exported by the entry point index.d.ts
//
// (undocumented)
@@ -622,14 +622,16 @@ export class ClrButton implements LoadingListener {
// (undocumented)
get role(): string;
// (undocumented)
routerLinkActiveClasses: string;
// (undocumented)
templateRef: TemplateRef<ClrButton>;
// (undocumented)
get type(): string;
set type(value: string);
// (undocumented)
static ɵcmp: i0.ɵɵComponentDeclaration<ClrButton, "clr-button", never, { "inMenu": "clrInMenu"; "classNames": "class"; "name": "name"; "type": "type"; "id": "id"; "disabled": "disabled"; }, { "_click": "click"; }, never, ["*"], false, never>;
static ɵcmp: i0.ɵɵComponentDeclaration<ClrButton, "clr-button", never, { "routerLinkActiveClasses": "routerLinkActive"; "inMenu": "clrInMenu"; "classNames": "class"; "name": "name"; "type": "type"; "id": "id"; "disabled": "disabled"; }, { "_click": "click"; }, never, ["*"], false, never>;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<ClrButton, [{ optional: true; skipSelf: true; }]>;
static ɵfac: i0.ɵɵFactoryDeclaration<ClrButton, [{ optional: true; }, { optional: true; skipSelf: true; }]>;
}

// @public (undocumented)
66 changes: 65 additions & 1 deletion projects/angular/src/button/button-group/button.spec.ts
Original file line number Diff line number Diff line change
@@ -7,7 +7,14 @@

import { Component, DebugElement, ViewChild } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { Routes } from '@angular/router';
import { RouterTestingModule } from '@angular/router/testing';

import {
RouterLinkButtonGroupDemoRouteOneComponent,
RouterLinkButtonGroupDemoRouteThreeComponent,
RouterLinkButtonGroupDemoRouteTwoComponent,
} from '../../../../demo/src/app/button-group/angular/router-link/router-link-button-group';
import { ClrLoadingState } from '../../utils/loading/loading';
import { ClrLoadingModule } from '../../utils/loading/loading.module';
import { ButtonInGroupService } from '../providers/button-in-group.service';
@@ -54,13 +61,39 @@ export class ButtonViewTestComponent {
load = true;
}

@Component({
template: `
<clr-button-group>
<clr-button id="button-one" routerLink="route-one" routerLinkActive="btn-primary">1</clr-button>
<clr-button id="button-two" routerLink="route-two" routerLinkActive="btn-primary">2</clr-button>
<clr-button id="button-two" routerLink="route-three" routerLinkActive="btn-primary">3</clr-button>
</clr-button-group>
`,
})
class TestButtonWithRouterLinkActiveComponent {}

export default function (): void {
describe('Buttons', () => {
let fixture: ComponentFixture<any>;
let debugEl: DebugElement;
let componentInstance: any;
let buttons: HTMLButtonElement[];

const routes: Routes = [
{
path: 'route-one',
component: RouterLinkButtonGroupDemoRouteOneComponent,
},
{
path: 'route-two',
component: RouterLinkButtonGroupDemoRouteTwoComponent,
},
{
path: 'route-three',
component: RouterLinkButtonGroupDemoRouteThreeComponent,
},
];

describe('Typescript API', () => {
beforeEach(() => {
TestBed.configureTestingModule({
@@ -248,5 +281,36 @@ export default function (): void {
expect(newButtons[0].children.length).toBe(0);
});
});

describe('with routerLinkActive', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [ClrButtonGroupModule, RouterTestingModule.withRoutes(routes)],
declarations: [TestButtonWithRouterLinkActiveComponent],
});

fixture = TestBed.createComponent(TestButtonWithRouterLinkActiveComponent);
fixture.detectChanges();
debugEl = fixture.debugElement;
componentInstance = debugEl.componentInstance;
buttons = debugEl.nativeElement.querySelectorAll('button');
});

it('does not set the routerLinkActive classes when no button is active', async () => {
expect(buttons[0].classList.contains('btn-primary')).toBeFalse();
expect(buttons[1].classList.contains('btn-primary')).toBeFalse();
expect(buttons[2].classList.contains('btn-primary')).toBeFalse();
});

it('sets the routerLinkActive classes only on the active button', async () => {
buttons[0].click();
await fixture.whenStable();
fixture.detectChanges();

expect(buttons[0].classList.contains('btn-primary')).toBeTrue();
expect(buttons[1].classList.contains('btn-primary')).toBeFalse();
expect(buttons[2].classList.contains('btn-primary')).toBeFalse();
});
});
});
}
9 changes: 5 additions & 4 deletions projects/angular/src/button/button-group/button.ts
Original file line number Diff line number Diff line change
@@ -6,6 +6,7 @@
*/

import { Component, EventEmitter, Input, Optional, Output, SkipSelf, TemplateRef, ViewChild } from '@angular/core';
import { RouterLinkActive } from '@angular/router';

import { uniqueIdFactory } from '../../utils/id-generator/id-generator.service';
import { ClrLoadingState } from '../../utils/loading/loading';
@@ -34,6 +35,7 @@ import { ButtonInGroupService } from '../providers/button-in-group.service';
})
export class ClrButton implements LoadingListener {
@Output('click') _click = new EventEmitter<boolean>(false);
@Input('routerLinkActive') routerLinkActiveClasses: string;

@ViewChild('buttonProjectedRef', { static: true }) templateRef: TemplateRef<ClrButton>;

@@ -48,9 +50,8 @@ export class ClrButton implements LoadingListener {
private _id: string = uniqueIdFactory();

constructor(
@SkipSelf()
@Optional()
public buttonInGroupService: ButtonInGroupService
@Optional() private readonly routerLinkActive: RouterLinkActive,
@SkipSelf() @Optional() public buttonInGroupService: ButtonInGroupService
) {}

@Input('clrInMenu')
@@ -71,7 +72,7 @@ export class ClrButton implements LoadingListener {

@Input('class')
get classNames(): string {
return this._classNames;
return this.routerLinkActive?.isActive ? `${this._classNames} ${this.routerLinkActiveClasses}` : this._classNames;
}
set classNames(value: string) {
if (typeof value === 'string') {
Original file line number Diff line number Diff line change
@@ -22,7 +22,7 @@ export default function (): void {
testButton = button;
});

const mockButton: ClrButton = new ClrButton(null);
const mockButton: ClrButton = new ClrButton(null, null);
mockButton.inMenu = true;

buttonInGroupService.updateButtonGroup(mockButton);
Original file line number Diff line number Diff line change
@@ -28,11 +28,12 @@ import { Component } from '@angular/core';
<li><a [routerLink]="['./move-button-in-menu']">Move Button In Menu</a></li>
<li><a [routerLink]="['./move-multiple-buttons-in-menu']">Move Multiple Buttons In Menu</a></li>
<li><a [routerLink]="['./move-all-in-menu']">Move All Buttons In Menu</a></li>
<li><a [routerLink]="['./projection-update-test-1']">Projection Update Test 1</a></li>
<li><a [routerLink]="['./router-link']">Router Link</a></li>
</ul>
</div>
<div class="clr-col-12 clr-col-md-4">
<ul>
<li><a [routerLink]="['./projection-update-test-1']">Projection Update Test 1</a></li>
<li><a [routerLink]="['./projection-update-test-2']">Projection Update Test 2</a></li>
<li><a [routerLink]="['./projection-update-test-3']">Projection Update Test 3</a></li>
<li><a [routerLink]="['./projection-update-test-4']">Projection Update Test 4</a></li>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!--
~ Copyright (c) 2016-2025 Broadcom. All Rights Reserved.
~ The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
~ This software is released under MIT license.
~ The full license information can be found in LICENSE in the root directory of this project.
-->

<h4>Router Link</h4>

<div class="clr-example">
<clr-button-group>
<clr-button routerLink="route-one" routerLinkActive="btn-primary">1</clr-button>
<clr-button routerLink="route-two" routerLinkActive="btn-primary">2</clr-button>
<clr-button routerLink="route-three" routerLinkActive="btn-primary">3</clr-button>
</clr-button-group>
</div>

<router-outlet></router-outlet>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2016-2025 Broadcom. All Rights Reserved.
* The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
* This software is released under MIT license.
* The full license information can be found in LICENSE in the root directory of this project.
*/

import { Component } from '@angular/core';

@Component({
templateUrl: './router-link-button-group.html',
styleUrls: ['../../button-group.demo.scss'],
})
export class RouterLinkButtonGroupDemo {}

@Component({
template: 'route-one works!',
})
export class RouterLinkButtonGroupDemoRouteOneComponent {}

@Component({
template: 'route-two works!',
})
export class RouterLinkButtonGroupDemoRouteTwoComponent {}

@Component({
template: 'route-three works!',
})
export class RouterLinkButtonGroupDemoRouteThreeComponent {}
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ import { ProjectionUpdateTest3Demo } from './angular/projection-update-test-3/pr
import { ProjectionUpdateTest4Demo } from './angular/projection-update-test-4/projection-update-test-4';
import { ProjectionUpdateTest5Demo } from './angular/projection-update-test-5/projection-update-test-5';
import { ProjectionUpdateTest6Demo } from './angular/projection-update-test-6/projection-update-test-6';
import { RouterLinkButtonGroupDemo } from './angular/router-link/router-link-button-group';
import { ButtonGroupDemo } from './button-group.demo';
import { ROUTING } from './button-group.demo.routing';
import { StaticButtonGroupBasicStructureDemo } from './static/basic-structure/basic-structure';
@@ -57,6 +58,7 @@ import { ButtonGroupTypes } from './static/types/button-group-types';
ProjectionUpdateTest4Demo,
ProjectionUpdateTest5Demo,
ProjectionUpdateTest6Demo,
RouterLinkButtonGroupDemo,
LoadingButtonGroupDemo,

StaticButtonGroupBasicStructureDemo,
24 changes: 24 additions & 0 deletions projects/demo/src/app/button-group/button-group.demo.routing.ts
Original file line number Diff line number Diff line change
@@ -24,6 +24,12 @@ import { ProjectionUpdateTest3Demo } from './angular/projection-update-test-3/pr
import { ProjectionUpdateTest4Demo } from './angular/projection-update-test-4/projection-update-test-4';
import { ProjectionUpdateTest5Demo } from './angular/projection-update-test-5/projection-update-test-5';
import { ProjectionUpdateTest6Demo } from './angular/projection-update-test-6/projection-update-test-6';
import {
RouterLinkButtonGroupDemo,
RouterLinkButtonGroupDemoRouteOneComponent,
RouterLinkButtonGroupDemoRouteThreeComponent,
RouterLinkButtonGroupDemoRouteTwoComponent,
} from './angular/router-link/router-link-button-group';
import { ButtonGroupDemo } from './button-group.demo';
import { StaticButtonGroupBasicStructureDemo } from './static/basic-structure/basic-structure';
import { ButtonGroupStaticDemo } from './static/button-group-static';
@@ -78,6 +84,24 @@ const ROUTES: Routes = [
{ path: 'projection-update-test-4', component: ProjectionUpdateTest4Demo },
{ path: 'projection-update-test-5', component: ProjectionUpdateTest5Demo },
{ path: 'projection-update-test-6', component: ProjectionUpdateTest6Demo },
{
path: 'router-link',
component: RouterLinkButtonGroupDemo,
children: [
{
path: 'route-one',
component: RouterLinkButtonGroupDemoRouteOneComponent,
},
{
path: 'route-two',
component: RouterLinkButtonGroupDemoRouteTwoComponent,
},
{
path: 'route-three',
component: RouterLinkButtonGroupDemoRouteThreeComponent,
},
],
},
],
},
],

0 comments on commit 04d4d09

Please sign in to comment.