Skip to content

Commit

Permalink
feat(edit-content): add remove functionality to category chips (#29216)
Browse files Browse the repository at this point in the history
### Proposed Changes
* Sync selected categories with categoryFieldControl with an effect
* Implement onRemove event in Chips component

### Checklist
- [x] Tests
- [x] Translations
- [x] Security Implications Contemplated (add notes if applicable)

### Additional Info


https://github.com/user-attachments/assets/8155b40b-3b7a-458c-af0b-0f3429212c45

---------

Co-authored-by: Arcadio Quintero <[email protected]>
  • Loading branch information
nicobytes and oidacra authored Jul 15, 2024
1 parent d5ad0d6 commit 61105d1
Show file tree
Hide file tree
Showing 6 changed files with 99 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
[removable]="true"
[label]="category.value"
tooltipPosition="top"
styleClass="p-chip-sm" />
styleClass="p-chip-sm"
(onRemove)="remove.emit(category.key)" />
} @if ($showAllBtn()) {
<button
(click)="toogleShowAll()"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
import { byTestId, createComponentFactory, Spectator } from '@ngneat/spectator/jest';

import { ButtonModule, ButtonDirective } from 'primeng/button';
import { ChipModule, Chip } from 'primeng/chip';
Expand Down Expand Up @@ -85,15 +85,33 @@ describe('DotCategoryFieldChipsComponent', () => {

describe('toogleShowAll', () => {
it('should set showAll to true', () => {
spectator.setInput('max', 2);
spectator.component.$showAll.set(true);
spectator.detectChanges();
const showBtn = spectator.query(byTestId('show-btn'));
spectator.click(showBtn);
expect(spectator.component.$showAll()).toBe(false);
});

it('should set showAll to false', () => {
spectator.setInput('max', 2);
spectator.component.$showAll.set(false);
spectator.component.toogleShowAll();
spectator.detectChanges();
const showBtn = spectator.query(byTestId('show-btn'));
spectator.click(showBtn);
expect(spectator.component.$showAll()).toBe(true);
});
});

it('should set showAll to false', () => {
describe('onRemove', () => {
it('should call the output', () => {
const removeSpy = jest.spyOn(spectator.component.remove, 'emit');
spectator.setInput('max', 2);
spectator.component.$showAll.set(true);
spectator.component.toogleShowAll();
expect(spectator.component.$showAll()).toBe(false);
spectator.detectChanges();
const chips = spectator.queryAll(Chip);
chips[0].onRemove.emit();
expect(removeSpy).toHaveBeenCalledWith(CATEGORIES_KEY_VALUE[0].key);
});
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { ChangeDetectionStrategy, Component, computed, inject, input, signal } from '@angular/core';
import {
ChangeDetectionStrategy,
Component,
computed,
EventEmitter,
inject,
input,
Output,
signal
} from '@angular/core';

import { ButtonModule } from 'primeng/button';
import { ChipModule } from 'primeng/chip';
Expand All @@ -20,7 +29,10 @@ import { DotCategoryFieldKeyValueObj } from '../../models/dot-category-field.mod
standalone: true,
imports: [ButtonModule, ChipModule, TooltipModule],
templateUrl: './dot-category-field-chips.component.html',
changeDetection: ChangeDetectionStrategy.OnPush
changeDetection: ChangeDetectionStrategy.OnPush,
host: {
class: 'dot-category-field__categories'
}
})
export class DotCategoryFieldChipsComponent {
/**
Expand Down Expand Up @@ -96,6 +108,12 @@ export class DotCategoryFieldChipsComponent {

return null;
});
/**
* Represents the output 'remove' which is of type 'EventEmitter<string>'.
*
* @memberof DotCategoryFieldChipsComponent
*/
@Output() remove = new EventEmitter<string>();
/**
* Method to toogle the show all categories.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
@if (store.selected().length) {
<div class="dot-category-field__categories" data-testId="category-chip-list">
<dot-category-field-chips [categories]="store.selected()" />
</div>
<dot-category-field-chips
data-testId="category-chip-list"
[categories]="store.selected()"
(remove)="store.removeSelected($event)" />

}

<div class="dot-category-field__select">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const FAKE_FORM_GROUP = new FormGroup({

describe('DotEditContentCategoryFieldComponent', () => {
let spectator: Spectator<DotEditContentCategoryFieldComponent>;
let store: InstanceType<typeof CategoryFieldStore>;

const createComponent = createComponentFactory({
component: DotEditContentCategoryFieldComponent,
Expand All @@ -51,6 +52,7 @@ describe('DotEditContentCategoryFieldComponent', () => {
field: CATEGORY_FIELD_MOCK
}
});
store = spectator.inject(CategoryFieldStore, true);

spectator.detectChanges();
});
Expand Down Expand Up @@ -80,6 +82,15 @@ describe('DotEditContentCategoryFieldComponent', () => {
it('should display the category list with chips when there are categories', () => {
expect(spectator.query(byTestId('category-chip-list'))).not.toBeNull();
});

it('should categoryFieldControl has the values loaded on the store', () => {
const categoryValue = spectator.component.categoryFieldControl.value;

expect(categoryValue).toEqual([
'1f208488057007cedda0e0b5d52ee3b3',
'cb83dc32c0a198fd0ca427b3b587f4ce'
]);
});
});

describe('Interactions', () => {
Expand Down Expand Up @@ -118,8 +129,6 @@ describe('DotEditContentCategoryFieldComponent', () => {
});

it('should remove DotEditContentCategoryFieldSidebarComponent when `closedSidebar` emit', fakeAsync(() => {
const formMock = spectator.inject(ControlContainer, true).control as FormGroup;
const setValueSpy = jest.spyOn(formMock.get(CATEGORY_FIELD_VARIABLE_NAME), 'setValue');
const selectBtn = spectator.query(byTestId('show-sidebar-btn')) as HTMLButtonElement;

expect(selectBtn).not.toBeNull();
Expand All @@ -141,12 +150,40 @@ describe('DotEditContentCategoryFieldComponent', () => {
// Check if the button is enabled again
expect(selectBtn.disabled).toBe(false);

// Check if the form is updated
// Check if the form has the correct value
const categoryValue = spectator.component.categoryFieldControl.value;

expect(setValueSpy).toHaveBeenCalledWith([
expect(categoryValue).toEqual([
'1f208488057007cedda0e0b5d52ee3b3',
'cb83dc32c0a198fd0ca427b3b587f4ce'
]);
}));

it('should set categoryFieldControl value when adding a new category', () => {
store.addSelected({
key: '1234',
value: 'test'
});

spectator.flushEffects();

const categoryValue = spectator.component.categoryFieldControl.value;

expect(categoryValue).toEqual([
'1f208488057007cedda0e0b5d52ee3b3',
'cb83dc32c0a198fd0ca427b3b587f4ce',
'1234'
]);
});

it('should set categoryFieldControl value when removing a category', () => {
store.removeSelected('1f208488057007cedda0e0b5d52ee3b3');

spectator.flushEffects();

const categoryValue = spectator.component.categoryFieldControl.value;

expect(categoryValue).toEqual(['cb83dc32c0a198fd0ca427b3b587f4ce']);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
Component,
ComponentRef,
DestroyRef,
effect,
inject,
input,
OnInit,
Expand Down Expand Up @@ -117,6 +118,13 @@ export class DotEditContentCategoryFieldComponent implements OnInit {
this.setSidebarListener();
}

constructor() {
effect(() => {
const categoryValues = this.store.selectedCategoriesValues();
this.categoryFieldControl.setValue(categoryValues);
});
}

ngOnInit(): void {
this.store.load(this.field(), this.contentlet());
}
Expand All @@ -125,17 +133,12 @@ export class DotEditContentCategoryFieldComponent implements OnInit {
this.#componentRef.instance.closedSidebar
.pipe(takeUntilDestroyed(this.#destroyRef), delay(CLOSE_SIDEBAR_CSS_DELAY_MS))
.subscribe(() => {
this.updateCategoryFieldControl();
// enable the show sidebar button
this.disableSelectCategoriesButton.set(false);
this.removeDotCategoryFieldSidebarComponent();
});
}

private updateCategoryFieldControl(): void {
this.categoryFieldControl.setValue(this.store.selectedCategoriesValues());
}

private removeDotCategoryFieldSidebarComponent() {
this.sidebarHost.viewContainerRef.clear();
}
Expand Down

0 comments on commit 61105d1

Please sign in to comment.