mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
[REGRESSION-AFTER-CLI] Fixing --prod mode (#2633)
* FormRenderingService refactoring * Move common part to core and use in card view * Add documentation
This commit is contained in:
committed by
Eugenio Romano
parent
34f51e3558
commit
e1e9c735b4
@@ -45,7 +45,7 @@ Displays a configurable property list renderer.
|
|||||||
|
|
||||||
## Details
|
## Details
|
||||||
|
|
||||||
You define the property list, the CardViewComponent does the rest. Each property represents a card view item (a row) in the card view component. At the time of writing two different kind of card view item (property type) is supported out of the box ([text](#card-text-item) item and [date](#card-date-item) item) but you can define your own custom types as well.
|
You define the property list, the CardViewComponent does the rest. Each property represents a card view item (a row) in the card view component. At the time of writing three a few kind of card view item (property type) is supported out of the box (e.g: [text](#card-text-item) item and [date](#card-date-item) item) but you can define your own custom types as well.
|
||||||
|
|
||||||
### Editing
|
### Editing
|
||||||
|
|
||||||
@@ -171,13 +171,16 @@ Card item components are loaded dynamically, which makes you able to define your
|
|||||||
|
|
||||||
Let's consider you want to have a **stardate** type to display Captain Picard's birthday (47457.1). For this, you need to do the following steps.
|
Let's consider you want to have a **stardate** type to display Captain Picard's birthday (47457.1). For this, you need to do the following steps.
|
||||||
|
|
||||||
#### 1. Define the model for the custom type
|
#### 1. Define the Model for the custom type
|
||||||
|
|
||||||
Your model has to extend the CardViewBaseItemModel and implement the CardViewItem interface.
|
Your model has to extend the **CardViewBaseItemModel** and implement the **CardViewItem** and **DynamicComponentModel** interface.
|
||||||
*(You can check how the CardViewTextItemModel is implemented for further guidance.)*
|
*(You can check how the CardViewTextItemModel is implemented for further guidance.)*
|
||||||
|
|
||||||
```js
|
```js
|
||||||
export class CardViewStarDateItemModel extends CardViewBaseItemModel implements CardViewItem {
|
import { CardViewBaseItemModel, CardViewItem, DynamicComponentModel } from 'ng2-alfresco-core';
|
||||||
|
|
||||||
|
export class CardViewStarDateItemModel extends CardViewBaseItemModel implements
|
||||||
|
CardViewItem, DynamicComponentModel {
|
||||||
type: string = 'star-date';
|
type: string = 'star-date';
|
||||||
|
|
||||||
get displayValue() {
|
get displayValue() {
|
||||||
@@ -190,13 +193,9 @@ export class CardViewStarDateItemModel extends CardViewBaseItemModel implements
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The most important part of this model is the value of the **type** attribute. This is how the Card View component will be able to recognise which component is needed to render it dynamically.
|
#### 2. Define the Component for the custom type
|
||||||
|
|
||||||
The type is a **hyphen-separated-lowercase-words** string (just like how I wrote it). This will be converted to a PascalCase (or UpperCamelCase) string to find the right component. In our case the Card View component will look for the CardView**StarDate**ItemComponent.
|
Create your custom card view item component. Defining the selector is not important, being it a dinamically loaded component, so you can give any selector name to it, but it makes sense to follow the angular standards.
|
||||||
|
|
||||||
#### 2. Define the component for the custom type
|
|
||||||
|
|
||||||
As discussed in the previous step the only important thing here is the naming of your component class ( **CardViewStarDateItemComponent**). Since the selector is not used in this case, you can give any selector name to it, but it makes sense to follow the angular standards.
|
|
||||||
|
|
||||||
```js
|
```js
|
||||||
@Component({
|
@Component({
|
||||||
@@ -242,6 +241,27 @@ For Angular to be able to load your custom component dynamically, you have to re
|
|||||||
export class MyModule {}
|
export class MyModule {}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### 4. Bind your custom component to the custom model type, enabling Angular's dynamic component loader to find it.
|
||||||
|
|
||||||
|
For mapping each type to their Component, there is the **CardItemTypeService**. This service extends the **DynamicComponentMapper** abstract class.
|
||||||
|
This CardItemTypeService is responible for the type resolution, it contains all the default components (e.g.: text, date, etc...) also. In order to make your component available, you need to extend the list of possible components.
|
||||||
|
|
||||||
|
You can extend this list the following way:
|
||||||
|
|
||||||
|
```js
|
||||||
|
@Component({
|
||||||
|
...
|
||||||
|
providers: [ CardItemTypeService ] // If you don't want to pollute the main instance of the CardItemTypeService service
|
||||||
|
...
|
||||||
|
})
|
||||||
|
export class SomeParentComponent {
|
||||||
|
|
||||||
|
constructor(private cardItemTypeService: CardItemTypeService) {
|
||||||
|
cardItemTypeService.setComponentTypeResolver('star-date', () => CardViewStarDateItemComponent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
<!-- Don't edit the See also section. Edit seeAlsoGraph.json and run config/generateSeeAlso.js -->
|
<!-- Don't edit the See also section. Edit seeAlsoGraph.json and run config/generateSeeAlso.js -->
|
||||||
<!-- seealso start -->
|
<!-- seealso start -->
|
||||||
## See also
|
## See also
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { DynamicComponentResolver } from 'ng2-alfresco-core';
|
||||||
import {
|
import {
|
||||||
AttachWidgetComponent,
|
AttachWidgetComponent,
|
||||||
FormFieldModel,
|
FormFieldModel,
|
||||||
@@ -22,7 +23,7 @@ import {
|
|||||||
UnknownWidgetComponent,
|
UnknownWidgetComponent,
|
||||||
UploadWidgetComponent
|
UploadWidgetComponent
|
||||||
} from './../components/widgets/index';
|
} from './../components/widgets/index';
|
||||||
import { DefaultTypeResolver, FormRenderingService } from './form-rendering.service';
|
import { FormRenderingService } from './form-rendering.service';
|
||||||
|
|
||||||
describe('FormRenderingService', () => {
|
describe('FormRenderingService', () => {
|
||||||
|
|
||||||
@@ -88,9 +89,9 @@ describe('FormRenderingService', () => {
|
|||||||
expect(
|
expect(
|
||||||
() => service.setComponentTypeResolver(
|
() => service.setComponentTypeResolver(
|
||||||
null,
|
null,
|
||||||
DefaultTypeResolver.fromType(UnknownWidgetComponent)
|
DynamicComponentResolver.fromType(UnknownWidgetComponent)
|
||||||
)
|
)
|
||||||
).toThrowError('fieldType is null or not defined');
|
).toThrowError('type is null or not defined');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should require type resolver instance to set resolver for type', () => {
|
it('should require type resolver instance to set resolver for type', () => {
|
||||||
@@ -106,13 +107,13 @@ describe('FormRenderingService', () => {
|
|||||||
expect(
|
expect(
|
||||||
() => service.setComponentTypeResolver(
|
() => service.setComponentTypeResolver(
|
||||||
FormFieldTypes.TEXT,
|
FormFieldTypes.TEXT,
|
||||||
DefaultTypeResolver.fromType(UnknownWidgetComponent)
|
DynamicComponentResolver.fromType(UnknownWidgetComponent)
|
||||||
)
|
)
|
||||||
).toThrowError('already mapped, use override option if you intend replacing existing mapping.');
|
).toThrowError('already mapped, use override option if you intend replacing existing mapping.');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should override existing resolver with explicit flag', () => {
|
it('should override existing resolver with explicit flag', () => {
|
||||||
let customResolver = DefaultTypeResolver.fromType(UnknownWidgetComponent);
|
let customResolver = DynamicComponentResolver.fromType(UnknownWidgetComponent);
|
||||||
service.setComponentTypeResolver(FormFieldTypes.TEXT, customResolver, true);
|
service.setComponentTypeResolver(FormFieldTypes.TEXT, customResolver, true);
|
||||||
expect(service.getComponentTypeResolver(FormFieldTypes.TEXT)).toBe(customResolver);
|
expect(service.getComponentTypeResolver(FormFieldTypes.TEXT)).toBe(customResolver);
|
||||||
});
|
});
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Injectable, Type } from '@angular/core';
|
import { Injectable, Type } from '@angular/core';
|
||||||
|
import { DynamicComponentMapper, DynamicComponentResolveFunction, DynamicComponentResolver } from 'ng2-alfresco-core';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
AmountWidgetComponent,
|
AmountWidgetComponent,
|
||||||
@@ -41,30 +42,33 @@ import {
|
|||||||
} from './../components/widgets/index';
|
} from './../components/widgets/index';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class FormRenderingService {
|
export class FormRenderingService extends DynamicComponentMapper {
|
||||||
|
|
||||||
private types: { [key: string]: ComponentTypeResolver } = {
|
protected defaultValue: Type<{}> = UnknownWidgetComponent;
|
||||||
'text': DefaultTypeResolver.fromType(TextWidgetComponent),
|
protected types: { [key: string]: DynamicComponentResolveFunction } = {
|
||||||
'string': DefaultTypeResolver.fromType(TextWidgetComponent),
|
'text': DynamicComponentResolver.fromType(TextWidgetComponent),
|
||||||
'integer': DefaultTypeResolver.fromType(NumberWidgetComponent),
|
'string': DynamicComponentResolver.fromType(TextWidgetComponent),
|
||||||
'multi-line-text': DefaultTypeResolver.fromType(MultilineTextWidgetComponentComponent),
|
'integer': DynamicComponentResolver.fromType(NumberWidgetComponent),
|
||||||
'boolean': DefaultTypeResolver.fromType(CheckboxWidgetComponent),
|
'multi-line-text': DynamicComponentResolver.fromType(MultilineTextWidgetComponentComponent),
|
||||||
'dropdown': DefaultTypeResolver.fromType(DropdownWidgetComponent),
|
'boolean': DynamicComponentResolver.fromType(CheckboxWidgetComponent),
|
||||||
'date': DefaultTypeResolver.fromType(DateWidgetComponent),
|
'dropdown': DynamicComponentResolver.fromType(DropdownWidgetComponent),
|
||||||
'amount': DefaultTypeResolver.fromType(AmountWidgetComponent),
|
'date': DynamicComponentResolver.fromType(DateWidgetComponent),
|
||||||
'radio-buttons': DefaultTypeResolver.fromType(RadioButtonsWidgetComponent),
|
'amount': DynamicComponentResolver.fromType(AmountWidgetComponent),
|
||||||
'hyperlink': DefaultTypeResolver.fromType(HyperlinkWidgetComponent),
|
'radio-buttons': DynamicComponentResolver.fromType(RadioButtonsWidgetComponent),
|
||||||
'readonly-text': DefaultTypeResolver.fromType(DisplayTextWidgetComponentComponent),
|
'hyperlink': DynamicComponentResolver.fromType(HyperlinkWidgetComponent),
|
||||||
'typeahead': DefaultTypeResolver.fromType(TypeaheadWidgetComponent),
|
'readonly-text': DynamicComponentResolver.fromType(DisplayTextWidgetComponentComponent),
|
||||||
'people': DefaultTypeResolver.fromType(PeopleWidgetComponent),
|
'typeahead': DynamicComponentResolver.fromType(TypeaheadWidgetComponent),
|
||||||
'functional-group': DefaultTypeResolver.fromType(FunctionalGroupWidgetComponent),
|
'people': DynamicComponentResolver.fromType(PeopleWidgetComponent),
|
||||||
'dynamic-table': DefaultTypeResolver.fromType(DynamicTableWidgetComponent),
|
'functional-group': DynamicComponentResolver.fromType(FunctionalGroupWidgetComponent),
|
||||||
'container': DefaultTypeResolver.fromType(ContainerWidgetComponent),
|
'dynamic-table': DynamicComponentResolver.fromType(DynamicTableWidgetComponent),
|
||||||
'group': DefaultTypeResolver.fromType(ContainerWidgetComponent),
|
'container': DynamicComponentResolver.fromType(ContainerWidgetComponent),
|
||||||
'document': DefaultTypeResolver.fromType(DocumentWidgetComponent)
|
'group': DynamicComponentResolver.fromType(ContainerWidgetComponent),
|
||||||
|
'document': DynamicComponentResolver.fromType(DocumentWidgetComponent)
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
this.types['upload'] = (field: FormFieldModel): Type<{}> => {
|
this.types['upload'] = (field: FormFieldModel): Type<{}> => {
|
||||||
if (field) {
|
if (field) {
|
||||||
let params = field.params;
|
let params = field.params;
|
||||||
@@ -76,47 +80,4 @@ export class FormRenderingService {
|
|||||||
return UnknownWidgetComponent;
|
return UnknownWidgetComponent;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
getComponentTypeResolver(fieldType: string, defaultValue: Type<{}> = UnknownWidgetComponent): ComponentTypeResolver {
|
|
||||||
if (fieldType) {
|
|
||||||
return this.types[fieldType] || DefaultTypeResolver.fromType(defaultValue);
|
|
||||||
}
|
|
||||||
return DefaultTypeResolver.fromType(defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
setComponentTypeResolver(fieldType: string, resolver: ComponentTypeResolver, override: boolean = false) {
|
|
||||||
if (!fieldType) {
|
|
||||||
throw new Error(`fieldType is null or not defined`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!resolver) {
|
|
||||||
throw new Error(`resolver is null or not defined`);
|
|
||||||
}
|
|
||||||
|
|
||||||
let existing = this.types[fieldType];
|
|
||||||
if (existing && !override) {
|
|
||||||
throw new Error(`already mapped, use override option if you intend replacing existing mapping.`);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.types[fieldType] = resolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolveComponentType(field: FormFieldModel, defaultValue: Type<{}> = UnknownWidgetComponent): Type<{}> {
|
|
||||||
if (field) {
|
|
||||||
let resolver = this.getComponentTypeResolver(field.type, defaultValue);
|
|
||||||
return resolver(field);
|
|
||||||
}
|
|
||||||
return defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ComponentTypeResolver = (field: FormFieldModel) => Type<{}>;
|
|
||||||
|
|
||||||
export class DefaultTypeResolver {
|
|
||||||
static fromType(type: Type<{}>): ComponentTypeResolver {
|
|
||||||
return (field: FormFieldModel) => {
|
|
||||||
return type;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -39,6 +39,7 @@ import { AuthGuardBpm } from './src/services/auth-guard-bpm.service';
|
|||||||
import { AuthGuardEcm } from './src/services/auth-guard-ecm.service';
|
import { AuthGuardEcm } from './src/services/auth-guard-ecm.service';
|
||||||
import { AuthGuard } from './src/services/auth-guard.service';
|
import { AuthGuard } from './src/services/auth-guard.service';
|
||||||
import { AuthenticationService } from './src/services/authentication.service';
|
import { AuthenticationService } from './src/services/authentication.service';
|
||||||
|
import { CardItemTypeService } from './src/services/card-item-types.service';
|
||||||
import { CommentProcessService } from './src/services/comment-process.service';
|
import { CommentProcessService } from './src/services/comment-process.service';
|
||||||
import { ContentService } from './src/services/content.service';
|
import { ContentService } from './src/services/content.service';
|
||||||
import { CookieService } from './src/services/cookie.service';
|
import { CookieService } from './src/services/cookie.service';
|
||||||
@@ -98,6 +99,8 @@ export { AlfrescoTranslateLoader } from './src/services/translate-loader.service
|
|||||||
export { AppConfigService } from './src/services/app-config.service';
|
export { AppConfigService } from './src/services/app-config.service';
|
||||||
export { ThumbnailService } from './src/services/thumbnail.service';
|
export { ThumbnailService } from './src/services/thumbnail.service';
|
||||||
export { UploadService } from './src/services/upload.service';
|
export { UploadService } from './src/services/upload.service';
|
||||||
|
export { DynamicComponentMapper, DynamicComponentResolveFunction, DynamicComponentResolver } from './src/services/dynamic-component-mapper.service';
|
||||||
|
export { CardItemTypeService } from './src/services/card-item-types.service';
|
||||||
export { CardViewUpdateService } from './src/services/card-view-update.service';
|
export { CardViewUpdateService } from './src/services/card-view-update.service';
|
||||||
export { UpdateNotification } from './src/services/card-view-update.service';
|
export { UpdateNotification } from './src/services/card-view-update.service';
|
||||||
export { ClickNotification } from './src/services/card-view-update.service';
|
export { ClickNotification } from './src/services/card-view-update.service';
|
||||||
@@ -167,6 +170,7 @@ export * from './src/events/base-ui.event';
|
|||||||
export * from './src/events/folder-created.event';
|
export * from './src/events/folder-created.event';
|
||||||
export * from './src/events/file.event';
|
export * from './src/events/file.event';
|
||||||
|
|
||||||
|
export * from './src/models/card-view-baseitem.model';
|
||||||
export * from './src/models/card-view-textitem.model';
|
export * from './src/models/card-view-textitem.model';
|
||||||
export * from './src/models/card-view-mapitem.model';
|
export * from './src/models/card-view-mapitem.model';
|
||||||
export * from './src/models/card-view-dateitem.model';
|
export * from './src/models/card-view-dateitem.model';
|
||||||
@@ -219,6 +223,7 @@ export function providers() {
|
|||||||
PeopleProcessService,
|
PeopleProcessService,
|
||||||
AppsProcessService,
|
AppsProcessService,
|
||||||
CommentProcessService,
|
CommentProcessService,
|
||||||
|
CardItemTypeService,
|
||||||
AppConfigService
|
AppConfigService
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
|||||||
import { By } from '@angular/platform-browser';
|
import { By } from '@angular/platform-browser';
|
||||||
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
|
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
|
||||||
import { CardViewItem } from '../../interface/card-view-item.interface';
|
import { CardViewItem } from '../../interface/card-view-item.interface';
|
||||||
|
import { CardItemTypeService } from '../../services/card-item-types.service';
|
||||||
import { CardViewContentProxyDirective } from './card-view-content-proxy.directive';
|
import { CardViewContentProxyDirective } from './card-view-content-proxy.directive';
|
||||||
import { CardViewItemDispatcherComponent } from './card-view-item-dispatcher.component';
|
import { CardViewItemDispatcherComponent } from './card-view-item-dispatcher.component';
|
||||||
|
|
||||||
@@ -37,9 +38,13 @@ export class CardViewShinyCustomElementItemComponent {
|
|||||||
describe('CardViewItemDispatcherComponent', () => {
|
describe('CardViewItemDispatcherComponent', () => {
|
||||||
|
|
||||||
let fixture: ComponentFixture<CardViewItemDispatcherComponent>;
|
let fixture: ComponentFixture<CardViewItemDispatcherComponent>;
|
||||||
|
let cardItemTypeService: CardItemTypeService;
|
||||||
let component: CardViewItemDispatcherComponent;
|
let component: CardViewItemDispatcherComponent;
|
||||||
|
|
||||||
beforeEach(async(() => {
|
beforeEach(async(() => {
|
||||||
|
cardItemTypeService = new CardItemTypeService();
|
||||||
|
cardItemTypeService.setComponentTypeResolver('shiny-custom-element', () => CardViewShinyCustomElementItemComponent);
|
||||||
|
|
||||||
TestBed.configureTestingModule({
|
TestBed.configureTestingModule({
|
||||||
imports: [],
|
imports: [],
|
||||||
declarations: [
|
declarations: [
|
||||||
@@ -47,7 +52,7 @@ describe('CardViewItemDispatcherComponent', () => {
|
|||||||
CardViewShinyCustomElementItemComponent,
|
CardViewShinyCustomElementItemComponent,
|
||||||
CardViewContentProxyDirective
|
CardViewContentProxyDirective
|
||||||
],
|
],
|
||||||
providers: []
|
providers: [ { provide: CardItemTypeService, useValue: cardItemTypeService } ]
|
||||||
});
|
});
|
||||||
|
|
||||||
// entryComponents are not supported yet on TestBed, that is why this ugly workaround:
|
// entryComponents are not supported yet on TestBed, that is why this ugly workaround:
|
||||||
|
@@ -20,10 +20,10 @@ import {
|
|||||||
ComponentFactoryResolver,
|
ComponentFactoryResolver,
|
||||||
Input,
|
Input,
|
||||||
OnChanges,
|
OnChanges,
|
||||||
Type,
|
|
||||||
ViewChild
|
ViewChild
|
||||||
} from '@angular/core';
|
} from '@angular/core';
|
||||||
import { CardViewItem } from '../../interface/card-view-item.interface';
|
import { CardViewItem } from '../../interface/card-view-item.interface';
|
||||||
|
import { CardItemTypeService } from '../../services/card-item-types.service';
|
||||||
import { CardViewContentProxyDirective } from './card-view-content-proxy.directive';
|
import { CardViewContentProxyDirective } from './card-view-content-proxy.directive';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -46,7 +46,8 @@ export class CardViewItemDispatcherComponent implements OnChanges {
|
|||||||
public ngOnInit;
|
public ngOnInit;
|
||||||
public ngDoCheck;
|
public ngDoCheck;
|
||||||
|
|
||||||
constructor(private resolver: ComponentFactoryResolver) {
|
constructor(private cardItemTypeService: CardItemTypeService,
|
||||||
|
private resolver: ComponentFactoryResolver) {
|
||||||
const dynamicLifecycleMethods = [
|
const dynamicLifecycleMethods = [
|
||||||
'ngOnInit',
|
'ngOnInit',
|
||||||
'ngDoCheck',
|
'ngDoCheck',
|
||||||
@@ -72,11 +73,8 @@ export class CardViewItemDispatcherComponent implements OnChanges {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private loadComponent() {
|
private loadComponent() {
|
||||||
const upperCamelCasedType = this.getUpperCamelCase(this.property.type),
|
const factoryClass = this.cardItemTypeService.resolveComponentType(this.property);
|
||||||
className = `CardView${upperCamelCasedType}ItemComponent`;
|
|
||||||
|
|
||||||
const factories = Array.from(this.resolver['_factories'].keys());
|
|
||||||
const factoryClass = <Type<any>> factories.find((x: any) => x.name === className);
|
|
||||||
const factory = this.resolver.resolveComponentFactory(factoryClass);
|
const factory = this.resolver.resolveComponentFactory(factoryClass);
|
||||||
this.componentReference = this.content.viewContainerRef.createComponent(factory);
|
this.componentReference = this.content.viewContainerRef.createComponent(factory);
|
||||||
|
|
||||||
@@ -84,11 +82,6 @@ export class CardViewItemDispatcherComponent implements OnChanges {
|
|||||||
this.componentReference.instance.property = this.property;
|
this.componentReference.instance.property = this.property;
|
||||||
}
|
}
|
||||||
|
|
||||||
private getUpperCamelCase(type: string): string {
|
|
||||||
const camelCasedType = type.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); });
|
|
||||||
return camelCasedType[0].toUpperCase() + camelCasedType.substr(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private proxy(methodName, ...args) {
|
private proxy(methodName, ...args) {
|
||||||
if (this.componentReference.instance[methodName]) {
|
if (this.componentReference.instance[methodName]) {
|
||||||
this.componentReference.instance[methodName].apply(this.componentReference.instance, args);
|
this.componentReference.instance[methodName].apply(this.componentReference.instance, args);
|
||||||
|
@@ -25,13 +25,14 @@
|
|||||||
|
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
import { CardViewItem } from '../interface/card-view-item.interface';
|
import { CardViewItem } from '../interface/card-view-item.interface';
|
||||||
|
import { DynamicComponentModel } from '../services/dynamic-component-mapper.service';
|
||||||
import { CardViewBaseItemModel, CardViewItemProperties } from './card-view-baseitem.model';
|
import { CardViewBaseItemModel, CardViewItemProperties } from './card-view-baseitem.model';
|
||||||
|
|
||||||
export interface CardViewDateItemProperties extends CardViewItemProperties {
|
export interface CardViewDateItemProperties extends CardViewItemProperties {
|
||||||
format?: string;
|
format?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CardViewDateItemModel extends CardViewBaseItemModel implements CardViewItem {
|
export class CardViewDateItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
|
||||||
type: string = 'date';
|
type: string = 'date';
|
||||||
format: string;
|
format: string;
|
||||||
|
|
||||||
|
@@ -24,9 +24,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { CardViewItem } from '../interface/card-view-item.interface';
|
import { CardViewItem } from '../interface/card-view-item.interface';
|
||||||
|
import { DynamicComponentModel } from '../services/dynamic-component-mapper.service';
|
||||||
import { CardViewBaseItemModel, CardViewItemProperties } from './card-view-baseitem.model';
|
import { CardViewBaseItemModel, CardViewItemProperties } from './card-view-baseitem.model';
|
||||||
|
|
||||||
export class CardViewMapItemModel extends CardViewBaseItemModel implements CardViewItem {
|
export class CardViewMapItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
|
||||||
type: string = 'map';
|
type: string = 'map';
|
||||||
value: Map<string, string>;
|
value: Map<string, string>;
|
||||||
|
|
||||||
|
@@ -24,12 +24,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { CardViewItem } from '../interface/card-view-item.interface';
|
import { CardViewItem } from '../interface/card-view-item.interface';
|
||||||
|
import { DynamicComponentModel } from '../services/dynamic-component-mapper.service';
|
||||||
import { CardViewBaseItemModel, CardViewItemProperties } from './card-view-baseitem.model';
|
import { CardViewBaseItemModel, CardViewItemProperties } from './card-view-baseitem.model';
|
||||||
|
|
||||||
export interface CardViewTextItemProperties extends CardViewItemProperties {
|
export interface CardViewTextItemProperties extends CardViewItemProperties {
|
||||||
multiline?: boolean;
|
multiline?: boolean;
|
||||||
}
|
}
|
||||||
export class CardViewTextItemModel extends CardViewBaseItemModel implements CardViewItem {
|
export class CardViewTextItemModel extends CardViewBaseItemModel implements CardViewItem, DynamicComponentModel {
|
||||||
type: string = 'text';
|
type: string = 'text';
|
||||||
multiline: boolean;
|
multiline: boolean;
|
||||||
|
|
||||||
|
@@ -0,0 +1,34 @@
|
|||||||
|
/*!
|
||||||
|
* @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 { Injectable, Type } from '@angular/core';
|
||||||
|
import { CardViewDateItemComponent } from '../components/view/card-view-dateitem.component';
|
||||||
|
import { CardViewMapItemComponent } from '../components/view/card-view-mapitem.component';
|
||||||
|
import { CardViewTextItemComponent } from '../components/view/card-view-textitem.component';
|
||||||
|
import { DynamicComponentMapper, DynamicComponentResolveFunction, DynamicComponentResolver } from '../services/dynamic-component-mapper.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class CardItemTypeService extends DynamicComponentMapper {
|
||||||
|
|
||||||
|
protected defaultValue: Type<{}> = CardViewTextItemComponent;
|
||||||
|
|
||||||
|
protected types: { [key: string]: DynamicComponentResolveFunction } = {
|
||||||
|
'text': DynamicComponentResolver.fromType(CardViewTextItemComponent),
|
||||||
|
'date': DynamicComponentResolver.fromType(CardViewDateItemComponent),
|
||||||
|
'map': DynamicComponentResolver.fromType(CardViewMapItemComponent)
|
||||||
|
};
|
||||||
|
}
|
@@ -0,0 +1,66 @@
|
|||||||
|
/*!
|
||||||
|
* @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 { Type } from '@angular/core';
|
||||||
|
|
||||||
|
export interface DynamicComponentModel { type: string; }
|
||||||
|
export type DynamicComponentResolveFunction = (model: DynamicComponentModel) => Type<{}>;
|
||||||
|
export class DynamicComponentResolver {
|
||||||
|
static fromType(type: Type<{}>): DynamicComponentResolveFunction {
|
||||||
|
return (model: DynamicComponentModel) => {
|
||||||
|
return type;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export abstract class DynamicComponentMapper {
|
||||||
|
|
||||||
|
protected defaultValue: Type<{}> = undefined;
|
||||||
|
protected types: { [key: string]: DynamicComponentResolveFunction } = {};
|
||||||
|
|
||||||
|
getComponentTypeResolver(type: string, defaultValue: Type<{}> = this.defaultValue): DynamicComponentResolveFunction {
|
||||||
|
if (type) {
|
||||||
|
return this.types[type] || DynamicComponentResolver.fromType(defaultValue);
|
||||||
|
}
|
||||||
|
return DynamicComponentResolver.fromType(defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
setComponentTypeResolver(type: string, resolver: DynamicComponentResolveFunction, override: boolean = false) {
|
||||||
|
if (!type) {
|
||||||
|
throw new Error(`type is null or not defined`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resolver) {
|
||||||
|
throw new Error(`resolver is null or not defined`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let existing = this.types[type];
|
||||||
|
if (existing && !override) {
|
||||||
|
throw new Error(`already mapped, use override option if you intend replacing existing mapping.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.types[type] = resolver;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveComponentType(model: DynamicComponentModel, defaultValue: Type<{}> = this.defaultValue): Type<{}> {
|
||||||
|
if (model) {
|
||||||
|
let resolver = this.getComponentTypeResolver(model.type, defaultValue);
|
||||||
|
return resolver(model);
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user