mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-07-24 17:32:15 +00:00
basic form events hooks and readme updates (#1528)
* basic form events hooks FormService now exposes the following events: - formLoaded (formRendered alternative) - formFieldValueChanged - taskCompleted - taskCompletedError - taskSaved - taskSavedError * readme updates
This commit is contained in:
committed by
Mario Romano
parent
dd753ba890
commit
bd485c730f
@@ -40,7 +40,7 @@ import {
|
||||
DataSorting
|
||||
} from 'ng2-alfresco-datatable';
|
||||
import { AlfrescoApiService } from 'ng2-alfresco-core';
|
||||
import { FormRenderingService } from 'ng2-activiti-form';
|
||||
import { FormService, FormRenderingService, FormEvent, FormFieldEvent } from 'ng2-activiti-form';
|
||||
import { /*CustomEditorComponent*/ CustomStencil01 } from './custom-editor/custom-editor.component';
|
||||
|
||||
declare var componentHandler;
|
||||
@@ -99,7 +99,8 @@ export class ActivitiDemoComponent implements AfterViewInit {
|
||||
constructor(private elementRef: ElementRef,
|
||||
private route: ActivatedRoute,
|
||||
private apiService: AlfrescoApiService,
|
||||
private formRenderingService: FormRenderingService) {
|
||||
private formRenderingService: FormRenderingService,
|
||||
private formService: FormService) {
|
||||
this.dataTasks = new ObjectDataTableAdapter(
|
||||
[],
|
||||
[
|
||||
@@ -123,6 +124,14 @@ export class ActivitiDemoComponent implements AfterViewInit {
|
||||
|
||||
// Uncomment this line to map 'custom_stencil_01' to local editor component
|
||||
formRenderingService.setComponentTypeResolver('custom_stencil_01', () => CustomStencil01, true);
|
||||
|
||||
formService.formLoaded.subscribe((e: FormEvent) => {
|
||||
console.log(`Form loaded: ${e.form.id}`);
|
||||
});
|
||||
|
||||
formService.formFieldValueChanged.subscribe((e: FormFieldEvent) => {
|
||||
console.log(`Field value changed. Form: ${e.form.id}, Field: ${e.field.id}, Value: ${e.field.value}`);
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
@@ -31,6 +31,22 @@
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Library Contents
|
||||
|
||||
### Components
|
||||
|
||||
- [ActivitiForm](#activitiform-component)
|
||||
- ActivitiStartForm
|
||||
|
||||
### Services
|
||||
|
||||
- [FormService](#formservice)
|
||||
- ActivitiAlfrescoContentService
|
||||
- EcmModelService
|
||||
- FormRenderingService
|
||||
- NodeService
|
||||
- WidgetVisibilityService
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you start using this development framework, make sure you have installed all required software and done all the
|
||||
@@ -101,7 +117,9 @@ Follow the 3 steps below:
|
||||
Please refer to the following example file: [systemjs.config.js](demo/systemjs
|
||||
.config.js) .
|
||||
|
||||
## Basic usage examples
|
||||
## ActivitiForm Component
|
||||
|
||||
### Basic usage
|
||||
|
||||
The component shows a Form from Activiti
|
||||
|
||||
@@ -112,6 +130,7 @@ The component shows a Form from Activiti
|
||||
Usage example of this component :
|
||||
|
||||
**main.ts**
|
||||
|
||||
```ts
|
||||
import { NgModule, Component } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
@@ -223,9 +242,9 @@ and store the form field as metadata. The param nameNode is optional.
|
||||
</activiti-form>
|
||||
```
|
||||
|
||||
## Configuration
|
||||
### Configuration
|
||||
|
||||
### Properties
|
||||
#### Properties
|
||||
|
||||
The recommended set of properties can be found in the following table:
|
||||
|
||||
@@ -246,7 +265,7 @@ The recommended set of properties can be found in the following table:
|
||||
| `path` | string | | Path of the folder where to store the metadata. |
|
||||
| `nameNode` (optional) | string | true | Name to assign to the new node where the metadata are stored. |
|
||||
|
||||
#### Advanced properties
|
||||
##### Advanced properties
|
||||
|
||||
The following properties are for complex customisation purposes:
|
||||
|
||||
@@ -255,7 +274,7 @@ The recommended set of properties can be found in the following table:
|
||||
| `form` | FormModel | | Underlying form model instance. |
|
||||
| `debugMode` | boolean | false | Toggle debug mode, allows displaying additional data for development and debugging purposes. |
|
||||
|
||||
### Events
|
||||
#### Events
|
||||
|
||||
| Name | Description |
|
||||
| --- | --- |
|
||||
@@ -332,6 +351,70 @@ There are two additional functions that can be of a great value when controlling
|
||||
**Please note that if `event.preventDefault()` is not called then default outcome behaviour
|
||||
will also be executed after your custom code.**
|
||||
|
||||
## FormService
|
||||
|
||||
```ts
|
||||
import { Component } from '@angular/core';
|
||||
import { FormService, FormEvent, FormFieldEvent } from 'ng2-activiti-form';
|
||||
|
||||
@Component(...)
|
||||
class MyComponent {
|
||||
|
||||
constructor(private formService: FormService) {
|
||||
|
||||
formService.formLoaded.subscribe((e: FormEvent) => {
|
||||
console.log(`Form loaded: ${e.form.id}`);
|
||||
});
|
||||
|
||||
formService.formFieldValueChanged.subscribe((e: FormFieldEvent) => {
|
||||
console.log(`Field value changed. Form: ${e.form.id}, Field: ${e.field.id}, Value: ${e.field.value}`);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
| Name | Args Type | Description |
|
||||
| --- | --- | --- |
|
||||
| formLoaded | FormEvent | Raised when form has been loaded or reloaded |
|
||||
| formFieldValueChanged | FormFieldEvent | Raised when input values change |
|
||||
| taskCompleted | FormEvent | Raised when a task is completed successfully |
|
||||
| taskCompletedError | FormErrorEvent | Raised when a task is completed unsuccessfully |
|
||||
| taskSaved | FormEvent | Raised when a task is saved successfully |
|
||||
| taskSavedError | FormErrorEvent | Raised when a task is saved unsuccessfully |
|
||||
|
||||
### Methods
|
||||
|
||||
| Name | Params | Returns | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| createFormFromANode | (formName: string) | Observable<any\> | Create a Form with a fields for each metadata properties |
|
||||
| createForm | (formName: string) | Observable<any\> | Create a Form |
|
||||
| addFieldsToAForm | (formId: string, formModel: FormDefinitionModel) | Observable<any\> | Add Fileds to A form |
|
||||
| searchFrom | (name: string) | Observable<any\> | Search For A Form by name |
|
||||
| getForms | n/a | Observable<any\> | Get All the forms |
|
||||
| getProcessDefinitions | n/a | Observable<any\> | Get Process Definitions |
|
||||
| getTasks | n/a | Observable<any\> | Get All the Tasks |
|
||||
| getTask | (taskId: string) | Observable<any\> | Get Task |
|
||||
| saveTaskForm | (taskId: string, formValues: FormValues) | Observable<any\> | Save Task Form |
|
||||
| completeTaskForm | (taskId: string, formValues: FormValues, outcome?: string) | Observable<any\> | Complete Task Form |
|
||||
| getTaskForm | (taskId: string) | Observable<any\> | Get Form related to a taskId |
|
||||
| getFormDefinitionById | (formId: string) | Observable<any\> | Get Form Definition |
|
||||
| getFormDefinitionByName | (name: string) | Observable<any\> | Returns form definition by a given name. |
|
||||
| getStartFormInstance | (processId: string) | Observable<any\> | Get start form instance for a given processId |
|
||||
| getStartFormDefinition | (processId: string) | Observable<any\> | Get start form definition for a given process |
|
||||
| createTemporaryRawRelatedContent | (file: any) | Observable<any\> | Save File |
|
||||
| getRestFieldValues | (taskId: string, field: string) | Observable<any\> | |
|
||||
| getRestFieldValuesByProcessId | (processDefinitionId: string, field: string) | Observable<any\> | |
|
||||
| getRestFieldValuesColumnByProcessId | (processDefinitionId: string, field: string, column?: string) | Observable<any\> | |
|
||||
| getRestFieldValuesColumn | (taskId: string, field: string, column?: string) | Observable<any\> | |
|
||||
| getWorkflowGroups\* | (filter: string, groupId?: string) | Observable<GroupModel[]\> | |
|
||||
| getWorkflowUsers\* | (filter: string, groupId?: string) | Observable<GroupUserModel[]\> | |
|
||||
|
||||
\* _Uses private Activiti WebApp api_
|
||||
|
||||
## See also
|
||||
|
||||
- [Form Stencils with Angular 2](docs/stencils.md)
|
||||
|
@@ -37,6 +37,7 @@ export * from './src/components/widgets/index';
|
||||
export * from './src/services/ecm-model.service';
|
||||
export * from './src/services/node.service';
|
||||
export * from './src/services/form-rendering.service';
|
||||
export * from './src/events/index';
|
||||
|
||||
export const ACTIVITI_FORM_DIRECTIVES: any[] = [
|
||||
ActivitiForm,
|
||||
|
@@ -15,21 +15,13 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
AfterViewChecked,
|
||||
OnChanges,
|
||||
SimpleChanges,
|
||||
Input,
|
||||
Output,
|
||||
EventEmitter
|
||||
} from '@angular/core';
|
||||
import { Component, OnInit, AfterViewChecked, OnChanges, SimpleChanges, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { LogService } from 'ng2-alfresco-core';
|
||||
import { EcmModelService } from './../services/ecm-model.service';
|
||||
import { FormService } from './../services/form.service';
|
||||
import { NodeService } from './../services/node.service';
|
||||
import { FormModel, FormOutcomeModel, FormValues, FormFieldModel, FormOutcomeEvent } from './widgets/core/index';
|
||||
import { FormEvent, FormErrorEvent } from './../events/index';
|
||||
|
||||
import { WidgetVisibilityService } from './../services/widget-visibility.service';
|
||||
|
||||
@@ -272,14 +264,14 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
}
|
||||
|
||||
if (outcome.id === ActivitiForm.CUSTOM_OUTCOME_ID) {
|
||||
this.formSaved.emit(this.form);
|
||||
this.onTaskSaved(this.form);
|
||||
this.storeFormAsMetadata();
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
// Note: Activiti is using NAME field rather than ID for outcomes
|
||||
if (outcome.name) {
|
||||
this.formSaved.emit(this.form);
|
||||
this.onTaskSaved(this.form);
|
||||
this.completeTaskForm(outcome.name);
|
||||
return true;
|
||||
}
|
||||
@@ -345,8 +337,8 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
.getTaskForm(taskId)
|
||||
.subscribe(
|
||||
form => {
|
||||
this.form = new FormModel(form, data, this.readOnly);
|
||||
this.formLoaded.emit(this.form);
|
||||
this.form = new FormModel(form, data, this.readOnly, this.formService);
|
||||
this.onFormLoaded(this.form);
|
||||
},
|
||||
(error) => {
|
||||
this.handleError(error);
|
||||
@@ -361,7 +353,7 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
form => {
|
||||
this.formName = form.name;
|
||||
this.form = this.parseForm(form);
|
||||
this.formLoaded.emit(this.form);
|
||||
this.onFormLoaded(this.form);
|
||||
},
|
||||
(error) => {
|
||||
this.handleError(error);
|
||||
@@ -377,7 +369,7 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
this.formService.getFormDefinitionById(id).subscribe(
|
||||
form => {
|
||||
this.form = this.parseForm(form);
|
||||
this.formLoaded.emit(this.form);
|
||||
this.onFormLoaded(this.form);
|
||||
},
|
||||
(error) => {
|
||||
this.handleError(error);
|
||||
@@ -396,12 +388,10 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
.saveTaskForm(this.form.taskId, this.form.values)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.formSaved.emit(this.form);
|
||||
this.onTaskSaved(this.form);
|
||||
this.storeFormAsMetadata();
|
||||
},
|
||||
(error) => {
|
||||
this.handleError(error);
|
||||
}
|
||||
error => this.onTaskSavedError(this.form, error)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -412,12 +402,10 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
.completeTaskForm(this.form.taskId, this.form.values, outcome)
|
||||
.subscribe(
|
||||
() => {
|
||||
this.formCompleted.emit(this.form);
|
||||
this.onTaskCompleted(this.form);
|
||||
this.storeFormAsMetadata();
|
||||
},
|
||||
(error) => {
|
||||
this.handleError(error);
|
||||
}
|
||||
error => this.onTaskCompletedError(this.form, error)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -429,7 +417,7 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
|
||||
parseForm(json: any): FormModel {
|
||||
if (json) {
|
||||
let form = new FormModel(json, this.data, this.readOnly);
|
||||
let form = new FormModel(json, this.data, this.readOnly, this.formService);
|
||||
if (!json.fields) {
|
||||
form.outcomes = this.getFormDefinitionOutcomes(form);
|
||||
}
|
||||
@@ -496,4 +484,29 @@ export class ActivitiForm implements OnInit, AfterViewChecked, OnChanges {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected onFormLoaded(form: FormModel) {
|
||||
this.formLoaded.emit(form);
|
||||
this.formService.formLoaded.next(new FormEvent(form));
|
||||
}
|
||||
|
||||
protected onTaskSaved(form: FormModel) {
|
||||
this.formSaved.emit(form);
|
||||
this.formService.taskSaved.next(new FormEvent(form));
|
||||
}
|
||||
|
||||
protected onTaskSavedError(form: FormModel, error: any) {
|
||||
this.handleError(error);
|
||||
this.formService.taskSavedError.next(new FormErrorEvent(form, error));
|
||||
}
|
||||
|
||||
protected onTaskCompleted(form: FormModel) {
|
||||
this.formCompleted.emit(form);
|
||||
this.formService.taskCompleted.next(new FormEvent(form));
|
||||
}
|
||||
|
||||
protected onTaskCompletedError(form: FormModel, error: any) {
|
||||
this.handleError(error);
|
||||
this.formService.taskCompletedError.next(new FormErrorEvent(form, error));
|
||||
}
|
||||
}
|
||||
|
@@ -23,6 +23,8 @@ import { FormOutcomeModel } from './form-outcome.model';
|
||||
import { FormFieldModel } from './form-field.model';
|
||||
import { FormFieldTypes } from './form-field-types';
|
||||
import { FormFieldTemplates } from './form-field-templates';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
import { FormFieldEvent } from './../../../events/index';
|
||||
|
||||
export class FormModel {
|
||||
|
||||
@@ -66,7 +68,7 @@ export class FormModel {
|
||||
return this.outcomes && this.outcomes.length > 0;
|
||||
}
|
||||
|
||||
constructor(json?: any, data?: FormValues, readOnly: boolean = false) {
|
||||
constructor(json?: any, data?: FormValues, readOnly: boolean = false, protected formService?: FormService) {
|
||||
this.readOnly = readOnly;
|
||||
|
||||
if (json) {
|
||||
@@ -120,6 +122,9 @@ export class FormModel {
|
||||
|
||||
onFormFieldChanged(field: FormFieldModel) {
|
||||
this.validateField(field);
|
||||
if (this.formService) {
|
||||
this.formService.formFieldValueChanged.next(new FormFieldEvent(this, field));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: consider evaluating and caching once the form is loaded
|
||||
|
@@ -0,0 +1,30 @@
|
||||
/*!
|
||||
* @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 { FormEvent } from './form.event';
|
||||
import { FormModel } from './../components/widgets/core/index';
|
||||
|
||||
export class FormErrorEvent extends FormEvent {
|
||||
|
||||
readonly error: any;
|
||||
|
||||
constructor(form: FormModel, error: any) {
|
||||
super(form);
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,30 @@
|
||||
/*!
|
||||
* @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 { FormEvent } from './form.event';
|
||||
import { FormModel, FormFieldModel } from './../components/widgets/core/index';
|
||||
|
||||
export class FormFieldEvent extends FormEvent {
|
||||
|
||||
readonly field: FormFieldModel;
|
||||
|
||||
constructor(form: FormModel, field: FormFieldModel) {
|
||||
super(form);
|
||||
this.field = field;
|
||||
}
|
||||
|
||||
}
|
27
ng2-components/ng2-activiti-form/src/events/form.event.ts
Normal file
27
ng2-components/ng2-activiti-form/src/events/form.event.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
/*!
|
||||
* @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 { FormModel } from './../components/widgets/core/index';
|
||||
|
||||
export class FormEvent {
|
||||
|
||||
readonly form: FormModel;
|
||||
|
||||
constructor(form: FormModel) {
|
||||
this.form = form;
|
||||
}
|
||||
}
|
20
ng2-components/ng2-activiti-form/src/events/index.ts
Normal file
20
ng2-components/ng2-activiti-form/src/events/index.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
/*!
|
||||
* @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.
|
||||
*/
|
||||
|
||||
export * from './form.event';
|
||||
export * from './form-error.event';
|
||||
export * from './form-field.event';
|
@@ -16,13 +16,14 @@
|
||||
*/
|
||||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs/Rx';
|
||||
import { Observable, Subject } from 'rxjs/Rx';
|
||||
import { AlfrescoApiService, LogService } from 'ng2-alfresco-core';
|
||||
import { FormValues } from './../components/widgets/core/index';
|
||||
import { FormDefinitionModel } from '../models/form-definition.model';
|
||||
import { EcmModelService } from './ecm-model.service';
|
||||
import { GroupModel } from './../components/widgets/core/group.model';
|
||||
import { GroupUserModel } from './../components/widgets/core/group-user.model';
|
||||
import { FormEvent, FormErrorEvent, FormFieldEvent } from './../events/index';
|
||||
|
||||
@Injectable()
|
||||
export class FormService {
|
||||
@@ -30,6 +31,13 @@ export class FormService {
|
||||
static UNKNOWN_ERROR_MESSAGE: string = 'Unknown error';
|
||||
static GENERIC_ERROR_MESSAGE: string = 'Server error';
|
||||
|
||||
formLoaded: Subject<FormEvent> = new Subject<FormEvent>();
|
||||
formFieldValueChanged: Subject<FormFieldEvent> = new Subject<FormFieldEvent>();
|
||||
taskCompleted: Subject<FormEvent> = new Subject<FormEvent>();
|
||||
taskCompletedError: Subject<FormErrorEvent> = new Subject<FormErrorEvent>();
|
||||
taskSaved: Subject<FormEvent> = new Subject<FormEvent>();
|
||||
taskSavedError: Subject<FormErrorEvent> = new Subject<FormErrorEvent>();
|
||||
|
||||
constructor(private ecmModelService: EcmModelService,
|
||||
private apiService: AlfrescoApiService,
|
||||
private logService: LogService) {
|
||||
@@ -111,7 +119,7 @@ export class FormService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Process Definition
|
||||
* Get Process Definitions
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
getProcessDefinitions(): Observable<any> {
|
||||
@@ -122,7 +130,6 @@ export class FormService {
|
||||
|
||||
/**
|
||||
* Get All the Tasks
|
||||
* @param taskId Task Id
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
getTasks(): Observable<any> {
|
||||
@@ -196,7 +203,7 @@ export class FormService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns form definition ID by a given name.
|
||||
* Returns form definition by a given name.
|
||||
* @param name
|
||||
* @returns {Promise<T>|Promise<ErrorObservable>}
|
||||
*/
|
||||
@@ -328,7 +335,7 @@ export class FormService {
|
||||
});
|
||||
}
|
||||
|
||||
getFormId(res: any) {
|
||||
getFormId(res: any): string {
|
||||
let result = null;
|
||||
|
||||
if (res && res.data && res.data.length > 0) {
|
||||
|
Reference in New Issue
Block a user