From 7563f9166560c3b48923b210d815d248f3603bcb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20Bolbo=C8=99enco?= Date: Wed, 27 Jun 2018 16:14:13 +0300 Subject: [PATCH] [ADF-3275] Select CardView item (#3530) * Select card view item * package json fix * package json fix * console.log removed * Usage of generic --- docs/core/card-view.component.md | 24 ++++ lib/core/card-view/card-view.module.ts | 8 +- .../card-view-selectitem.component.html | 13 ++ .../card-view-selectitem.component.spec.ts | 113 ++++++++++++++++++ .../card-view-selectitem.component.ts | 56 +++++++++ .../components/card-view.components.ts | 1 + ...rd-view-selectitem-properties.interface.ts | 29 +++++ .../interfaces/card-view.interfaces.ts | 1 + .../models/card-view-selectitem.model.spec.ts | 46 +++++++ .../models/card-view-selectitem.model.ts | 44 +++++++ lib/core/card-view/models/card-view.models.ts | 1 + lib/core/card-view/public-api.ts | 1 + .../services/card-item-types.service.ts | 2 + 13 files changed, 338 insertions(+), 1 deletion(-) create mode 100644 lib/core/card-view/components/card-view-selectitem/card-view-selectitem.component.html create mode 100644 lib/core/card-view/components/card-view-selectitem/card-view-selectitem.component.spec.ts create mode 100644 lib/core/card-view/components/card-view-selectitem/card-view-selectitem.component.ts create mode 100644 lib/core/card-view/interfaces/card-view-selectitem-properties.interface.ts create mode 100644 lib/core/card-view/models/card-view-selectitem.model.spec.ts create mode 100644 lib/core/card-view/models/card-view-selectitem.model.ts diff --git a/docs/core/card-view.component.md b/docs/core/card-view.component.md index 0172055ed0..006522e8a0 100644 --- a/docs/core/card-view.component.md +++ b/docs/core/card-view.component.md @@ -79,6 +79,12 @@ Defining properties from Typescript: value: [], key: 'key-value-pairs' }), + new CardViewSelectItemModel({ + label: 'Select box', + value: 'one', + options$: of([{ key: 'one', label: 'One' }, { key: 'two', label: 'Two' }]), + key: 'select' + }), ... ] ``` @@ -105,6 +111,7 @@ You define the property list, the [`CardViewComponent`](../core/card-view.compon - [**CardViewIntItemModel**](#card-int-item) - _for integer items_ - [**CardViewFloatItemModel**](#card-float-item) - _for float items_ - [**CardViewKeyValuePairsItemModel**](#card-key-values-pairs-item) - _for key-value-pairs items_ +- [**CardViewSelectItemModel**](#card-select-item) - _for select items_ Each of these types implements the [Card View Item interface](card-view-item.interface.md): @@ -309,6 +316,23 @@ const keyValuePairsItemProperty = new CardViewKeyValuePairsItemModel(options); | value\* | `[{ name: '', value: '' }, ...]` | | The original data value for the item | +#### Card Select Item + +[`CardViewSelectItemModel`](../../lib/core/card-view/models/card-view-selectitem.model.ts) is a property type for select properties. + +```ts +const selectItemProperty = new CardViewSelectItemModel(options); +``` + +| Name | Type | Default | Description | +| ---- | ---- | ------- | ----------- | +| label\* | string | | Item label | +| key\* | string | | Identifying key (important when editing the item) | +| editable | boolean | false | Toggles whether the item is editable | +| value | string | | The original data value for the item | +| options$\* | Observable | | The original data value for the item | + + ## See also diff --git a/lib/core/card-view/card-view.module.ts b/lib/core/card-view/card-view.module.ts index 303932e299..5f74fe526e 100644 --- a/lib/core/card-view/card-view.module.ts +++ b/lib/core/card-view/card-view.module.ts @@ -25,7 +25,8 @@ import { MatIconModule, MatInputModule, MatCheckboxModule, - MatNativeDateModule + MatNativeDateModule, + MatSelectModule } from '@angular/material'; import { MatDatetimepickerModule, MatNativeDatetimeModule } from '@mat-datetimepicker/core'; import { FlexLayoutModule } from '@angular/flex-layout'; @@ -39,6 +40,7 @@ import { CardViewItemDispatcherComponent } from './components/card-view-item-dis import { CardViewMapItemComponent } from './components/card-view-mapitem/card-view-mapitem.component'; import { CardViewTextItemComponent } from './components/card-view-textitem/card-view-textitem.component'; import { CardViewKeyValuePairsItemComponent } from './components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component'; +import { CardViewSelectItemComponent } from './components/card-view-selectitem/card-view-selectitem.component'; @NgModule({ imports: [ @@ -52,6 +54,7 @@ import { CardViewKeyValuePairsItemComponent } from './components/card-view-keyva MatInputModule, MatTableModule, MatIconModule, + MatSelectModule, MatButtonModule, MatDatetimepickerModule, MatNativeDatetimeModule @@ -63,6 +66,7 @@ import { CardViewKeyValuePairsItemComponent } from './components/card-view-keyva CardViewMapItemComponent, CardViewTextItemComponent, CardViewKeyValuePairsItemComponent, + CardViewSelectItemComponent, CardViewItemDispatcherComponent, CardViewContentProxyDirective ], @@ -71,6 +75,7 @@ import { CardViewKeyValuePairsItemComponent } from './components/card-view-keyva CardViewDateItemComponent, CardViewMapItemComponent, CardViewTextItemComponent, + CardViewSelectItemComponent, CardViewKeyValuePairsItemComponent ], exports: [ @@ -79,6 +84,7 @@ import { CardViewKeyValuePairsItemComponent } from './components/card-view-keyva CardViewDateItemComponent, CardViewMapItemComponent, CardViewTextItemComponent, + CardViewSelectItemComponent, CardViewKeyValuePairsItemComponent ] }) diff --git a/lib/core/card-view/components/card-view-selectitem/card-view-selectitem.component.html b/lib/core/card-view/components/card-view-selectitem/card-view-selectitem.component.html new file mode 100644 index 0000000000..458c28a946 --- /dev/null +++ b/lib/core/card-view/components/card-view-selectitem/card-view-selectitem.component.html @@ -0,0 +1,13 @@ +
{{ property.label | translate }}
+
+
{{ property.displayValue | async }}
+
+ + + + {{ option.label | translate }} + + + +
+
diff --git a/lib/core/card-view/components/card-view-selectitem/card-view-selectitem.component.spec.ts b/lib/core/card-view/components/card-view-selectitem/card-view-selectitem.component.spec.ts new file mode 100644 index 0000000000..ea15a42ff0 --- /dev/null +++ b/lib/core/card-view/components/card-view-selectitem/card-view-selectitem.component.spec.ts @@ -0,0 +1,113 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { CardViewSelectItemModel } from '../../models/card-view-selectitem.model'; +import { CardViewUpdateService } from '../../services/card-view-update.service'; +import { CardViewSelectItemComponent } from './card-view-selectitem.component'; +import { setupTestBed } from '../../../testing/setupTestBed'; +import { CoreTestingModule } from '../../../testing/core.testing.module'; +import { of } from 'rxjs/observable/of'; + +describe('CardViewSelectItemComponent', () => { + + let fixture: ComponentFixture; + let component: CardViewSelectItemComponent; + let cardViewUpdateService; + const mockData = [{ key: 'one', label: 'One' }, { key: 'two', label: 'Two' }, { key: 'three', label: 'Three' }]; + const mockDefaultProps = { + label: 'Select box label', + value: 'two', + options$: of(mockData), + key: 'key', + editable: true + }; + + setupTestBed({ + imports: [CoreTestingModule] + }); + + beforeEach(() => { + fixture = TestBed.createComponent(CardViewSelectItemComponent); + cardViewUpdateService = TestBed.get(CardViewUpdateService); + component = fixture.componentInstance; + component.property = new CardViewSelectItemModel(mockDefaultProps); + }); + + afterEach(() => { + fixture.destroy(); + }); + + describe('Rendering', () => { + it('should render the label', () => { + fixture.detectChanges(); + + const labelValue = fixture.debugElement.query(By.css('.adf-property-label')); + expect(labelValue).not.toBeNull(); + expect(labelValue.nativeElement.innerText).toBe('Select box label'); + }); + + it('should render readOnly value is editable property is FALSE', () => { + component.property = new CardViewSelectItemModel({ + ...mockDefaultProps, + editable: false + }); + + component.ngOnChanges(); + fixture.detectChanges(); + + const readOnly = fixture.debugElement.query(By.css('[data-automation-class="read-only-value"]')); + const selectBox = fixture.debugElement.query(By.css('[data-automation-class="select-box"]')); + + expect(readOnly).not.toBeNull(); + expect(selectBox).toBeNull(); + }); + + it('should render select box if editable property is TRUE', () => { + component.ngOnChanges(); + component.editable = true; + fixture.detectChanges(); + + const selectBox = fixture.debugElement.query(By.css('[data-automation-class="select-box"]')); + expect(selectBox).not.toBeNull(); + }); + + it('should update property on input blur', async(() => { + spyOn(cardViewUpdateService, 'update'); + + component.ngOnChanges(); + component.editable = true; + fixture.detectChanges(); + + const selectBox = fixture.debugElement.query(By.css('[data-automation-class="select-box"]')); + selectBox.nativeElement.click(); + fixture.detectChanges(); + + const option = fixture.debugElement.query(By.css(`mat-option[ng-reflect-value="${mockData[2].key}"]`)); + option.nativeElement.click(); + fixture.detectChanges(); + + fixture.whenStable().then(() => { + fixture.detectChanges(); + + expect(cardViewUpdateService.update).toHaveBeenCalled(); + expect(component.property.value).toBe(mockData[2].key); + }); + })); + }); +}); diff --git a/lib/core/card-view/components/card-view-selectitem/card-view-selectitem.component.ts b/lib/core/card-view/components/card-view-selectitem/card-view-selectitem.component.ts new file mode 100644 index 0000000000..87a080a658 --- /dev/null +++ b/lib/core/card-view/components/card-view-selectitem/card-view-selectitem.component.ts @@ -0,0 +1,56 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Component, Input, OnChanges } from '@angular/core'; +import { CardViewSelectItemModel } from '../../models/card-view-selectitem.model'; +import { CardViewUpdateService } from '../../services/card-view-update.service'; +import { Observable } from 'rxjs/Observable'; +import { CardViewSelectItemOption } from '../../interfaces/card-view.interfaces'; +import { MatSelectChange } from '@angular/material'; + +@Component({ + selector: 'adf-card-view-selectitem', + templateUrl: './card-view-selectitem.component.html' +}) +export class CardViewSelectItemComponent implements OnChanges { + @Input() property: CardViewSelectItemModel; + + @Input() editable: boolean = false; + + @Input() options$: Observable[]>; + + value: string; + + constructor(private cardViewUpdateService: CardViewUpdateService) {} + + ngOnChanges(): void { + this.value = this.property.value; + } + + isEditable(): boolean { + return this.editable && this.property.editable; + } + + getOptions(): Observable[]> { + return this.options$ || this.property.options$; + } + + onChange(event: MatSelectChange): void { + this.cardViewUpdateService.update(this.property, event.value); + this.property.value = event.value; + } +} diff --git a/lib/core/card-view/components/card-view.components.ts b/lib/core/card-view/components/card-view.components.ts index be4ab5d798..638ba6ffcb 100644 --- a/lib/core/card-view/components/card-view.components.ts +++ b/lib/core/card-view/components/card-view.components.ts @@ -21,4 +21,5 @@ export * from './card-view-dateitem/card-view-dateitem.component'; export * from './card-view-item-dispatcher/card-view-item-dispatcher.component'; export * from './card-view-mapitem/card-view-mapitem.component'; export * from './card-view-textitem/card-view-textitem.component'; +export * from './card-view-selectitem/card-view-selectitem.component'; export * from './card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component'; diff --git a/lib/core/card-view/interfaces/card-view-selectitem-properties.interface.ts b/lib/core/card-view/interfaces/card-view-selectitem-properties.interface.ts new file mode 100644 index 0000000000..3c6a2459e9 --- /dev/null +++ b/lib/core/card-view/interfaces/card-view-selectitem-properties.interface.ts @@ -0,0 +1,29 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CardViewItemProperties } from './card-view-item-properties.interface'; +import { Observable } from 'rxjs/Observable'; + +export interface CardViewSelectItemOption { + label: string; + key: T; +} + +export interface CardViewSelectItemProperties extends CardViewItemProperties { + value: string; + options$: Observable[]>; +} diff --git a/lib/core/card-view/interfaces/card-view.interfaces.ts b/lib/core/card-view/interfaces/card-view.interfaces.ts index 137ae05b8b..13b11ea022 100644 --- a/lib/core/card-view/interfaces/card-view.interfaces.ts +++ b/lib/core/card-view/interfaces/card-view.interfaces.ts @@ -23,3 +23,4 @@ export * from './card-view-dateitem-properties.interface'; export * from './card-view-boolitem-properties.interface'; export * from './card-view-textitem-pipe-property.interface'; export * from './card-view-keyvaluepairsitem-properties.interface'; +export * from './card-view-selectitem-properties.interface'; diff --git a/lib/core/card-view/models/card-view-selectitem.model.spec.ts b/lib/core/card-view/models/card-view-selectitem.model.spec.ts new file mode 100644 index 0000000000..d0100ffdba --- /dev/null +++ b/lib/core/card-view/models/card-view-selectitem.model.spec.ts @@ -0,0 +1,46 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { async } from '@angular/core/testing'; +import { CardViewSelectItemModel } from './card-view-selectitem.model'; +import { CardViewSelectItemProperties } from '../interfaces/card-view.interfaces'; +import { of } from 'rxjs/observable/of'; + +describe('CardViewSelectItemModel', () => { + let properties: CardViewSelectItemProperties; + const mockData = [{ key: 'one', label: 'One' }, { key: 'two', label: 'Two' }, { key: 'three', label: 'Three' }]; + + beforeEach(() => { + properties = { + label: 'Select box label', + value: 'two', + options$: of(mockData), + key: 'key', + editable: true + }; + }); + + describe('displayValue', () => { + it('should return the value if it is present', async(() => { + const itemModel = new CardViewSelectItemModel(properties); + + itemModel.displayValue.subscribe(value => { + expect(value).toBe(mockData[1].label); + }); + })); + }); +}); diff --git a/lib/core/card-view/models/card-view-selectitem.model.ts b/lib/core/card-view/models/card-view-selectitem.model.ts new file mode 100644 index 0000000000..d7f9fc3fd3 --- /dev/null +++ b/lib/core/card-view/models/card-view-selectitem.model.ts @@ -0,0 +1,44 @@ +/*! + * @license + * Copyright 2016 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { CardViewItem } from '../interfaces/card-view-item.interface'; +import { DynamicComponentModel } from '../../services/dynamic-component-mapper.service'; +import { CardViewBaseItemModel } from './card-view-baseitem.model'; +import { CardViewSelectItemProperties, CardViewSelectItemOption } from '../interfaces/card-view.interfaces'; +import { Observable } from 'rxjs/Observable'; +import { switchMap } from 'rxjs/operators'; +import { of } from 'rxjs/observable/of'; + +export class CardViewSelectItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel { + type: string = 'select'; + options$: Observable[]>; + + constructor(obj: CardViewSelectItemProperties) { + super(obj); + + this.options$ = obj.options$; + } + + get displayValue() { + return this.options$.pipe( + switchMap(options => { + const option = options.find(o => o.key === this.value); + return of(option ? option.label : ''); + }) + ); + } +} diff --git a/lib/core/card-view/models/card-view.models.ts b/lib/core/card-view/models/card-view.models.ts index e29adc1f4c..17a3506952 100644 --- a/lib/core/card-view/models/card-view.models.ts +++ b/lib/core/card-view/models/card-view.models.ts @@ -24,3 +24,4 @@ export * from './card-view-intitem.model'; export * from './card-view-mapitem.model'; export * from './card-view-textitem.model'; export * from './card-view-keyvaluepairs.model'; +export * from './card-view-selectitem.model'; diff --git a/lib/core/card-view/public-api.ts b/lib/core/card-view/public-api.ts index 0ae9787d11..d1aa834802 100644 --- a/lib/core/card-view/public-api.ts +++ b/lib/core/card-view/public-api.ts @@ -21,6 +21,7 @@ export { CardViewDateItemComponent, CardViewMapItemComponent, CardViewTextItemComponent, + CardViewSelectItemComponent, CardViewKeyValuePairsItemComponent } from './components/card-view.components'; diff --git a/lib/core/card-view/services/card-item-types.service.ts b/lib/core/card-view/services/card-item-types.service.ts index ba12c44678..713d729b30 100644 --- a/lib/core/card-view/services/card-item-types.service.ts +++ b/lib/core/card-view/services/card-item-types.service.ts @@ -19,6 +19,7 @@ import { Injectable, Type } from '@angular/core'; import { CardViewDateItemComponent } from '../components/card-view-dateitem/card-view-dateitem.component'; import { CardViewMapItemComponent } from '../components/card-view-mapitem/card-view-mapitem.component'; import { CardViewTextItemComponent } from '../components/card-view-textitem/card-view-textitem.component'; +import { CardViewSelectItemComponent } from '../components/card-view-selectitem/card-view-selectitem.component'; import { CardViewBoolItemComponent } from '../components/card-view-boolitem/card-view-boolitem.component'; import { CardViewKeyValuePairsItemComponent } from '../components/card-view-keyvaluepairsitem/card-view-keyvaluepairsitem.component'; import { DynamicComponentMapper, DynamicComponentResolveFunction, DynamicComponentResolver } from '../../services/dynamic-component-mapper.service'; @@ -30,6 +31,7 @@ export class CardItemTypeService extends DynamicComponentMapper { protected types: { [key: string]: DynamicComponentResolveFunction } = { 'text': DynamicComponentResolver.fromType(CardViewTextItemComponent), + 'select': DynamicComponentResolver.fromType(CardViewSelectItemComponent), 'int': DynamicComponentResolver.fromType(CardViewTextItemComponent), 'float': DynamicComponentResolver.fromType(CardViewTextItemComponent), 'date': DynamicComponentResolver.fromType(CardViewDateItemComponent),