mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-13 21:13:07 +00:00
Edit and create communities
This commit is contained in:
@@ -42,6 +42,7 @@
|
|||||||
"head": "Collections of this Community"
|
"head": "Collections of this Community"
|
||||||
},
|
},
|
||||||
"edit": {
|
"edit": {
|
||||||
|
"head": "Edit collction",
|
||||||
"name": "Name",
|
"name": "Name",
|
||||||
"description": "Short Description",
|
"description": "Short Description",
|
||||||
"introductory": "Introductory text (HTML)",
|
"introductory": "Introductory text (HTML)",
|
||||||
|
@@ -38,7 +38,7 @@ export class CreateCollectionPageComponent {
|
|||||||
|
|
||||||
onSubmit(data: any) {
|
onSubmit(data: any) {
|
||||||
this.parentUUID$.pipe(take(1)).subscribe((uuid: string) => {
|
this.parentUUID$.pipe(take(1)).subscribe((uuid: string) => {
|
||||||
const collection = Object.assign(new NormalizedCollection(), {
|
const collection = Object.assign(new Collection(), {
|
||||||
name: data.name,
|
name: data.name,
|
||||||
metadata: [
|
metadata: [
|
||||||
{ key: 'dc.description', value: data.introductory },
|
{ key: 'dc.description', value: data.introductory },
|
||||||
|
@@ -1,27 +1,4 @@
|
|||||||
<form #form="ngForm" (ngSubmit)="onSubmit(form.value)" class="row" action="/">
|
<ds-form *ngIf="formModel" #formRef="formComponent"
|
||||||
<div class="col-12 form-group">
|
[formId]="'community-form-id'"
|
||||||
<label for="community-name" class="font-weight-bold">{{ 'community.edit.name' | translate }}</label>
|
[formModel]="formModel" (submit)="onSubmit($event)"></ds-form>
|
||||||
<input type="text" [(ngModel)]="name" name="name" id="community-name" class="form-control" [ngClass]="{'is-invalid' : !name && nameRequiredError}" aria-label="Community Name" />
|
|
||||||
<div class="invalid-feedback">{{ 'community.edit.required.name' | translate }}</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 form-group">
|
|
||||||
<label for="community-description" class="font-weight-bold">{{ 'community.edit.description' | translate }}</label>
|
|
||||||
<input type="text" [(ngModel)]="description" name="description" id="community-description" class="form-control" aria-label="Community Short Description" />
|
|
||||||
</div>
|
|
||||||
<div class="col-12 form-group">
|
|
||||||
<label for="community-introductory" class="font-weight-bold">{{ 'community.edit.introductory' | translate }}</label>
|
|
||||||
<textarea [(ngModel)]="introductory" name="introductory" id="community-introductory" class="form-control" aria-label="Community Introductory Text" rows="6" ></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 form-group">
|
|
||||||
<label for="community-copyright" class="font-weight-bold">{{ 'community.edit.copyright' | translate }}</label>
|
|
||||||
<textarea [(ngModel)]="copyright" name="copyright" id="community-copyright" class="form-control" aria-label="Community Copyright Text" rows="6" ></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 form-group">
|
|
||||||
<label for="community-news" class="font-weight-bold">{{ 'community.edit.news' | translate }}</label>
|
|
||||||
<textarea [(ngModel)]="news" name="news" id="community-news" class="form-control" aria-label="Community News" rows="6" ></textarea>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 form-group">
|
|
||||||
<button type="button" class="btn btn-secondary" id="community-cancel" (click)="cancel()">{{ 'community.edit.cancel' | translate }}</button>
|
|
||||||
<button type="submit" class="btn btn-secondary" id="community-submit">{{ 'community.edit.submit' | translate }}</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
|
@@ -1,39 +1,93 @@
|
|||||||
import { Component, EventEmitter, Output } from '@angular/core';
|
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||||
import { isNotEmpty } from '../../shared/empty.util';
|
|
||||||
import { Location } from '@angular/common';
|
import { Location } from '@angular/common';
|
||||||
|
import {
|
||||||
|
DynamicFormService,
|
||||||
|
DynamicInputModel,
|
||||||
|
DynamicTextAreaModel
|
||||||
|
} from '@ng-dynamic-forms/core';
|
||||||
|
import { FormGroup } from '@angular/forms';
|
||||||
|
import { DynamicFormControlModel } from '@ng-dynamic-forms/core/src/model/dynamic-form-control.model';
|
||||||
|
import { Community } from '../../core/shared/community.model';
|
||||||
|
import { ResourceType } from '../../core/shared/resource-type';
|
||||||
|
import { hasValue, isNotEmpty } from '../../shared/empty.util';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-community-form',
|
selector: 'ds-community-form',
|
||||||
styleUrls: ['./community-form.component.scss'],
|
styleUrls: ['./community-form.component.scss'],
|
||||||
templateUrl: './community-form.component.html'
|
templateUrl: './community-form.component.html'
|
||||||
})
|
})
|
||||||
export class CommunityFormComponent {
|
export class CommunityFormComponent implements OnInit {
|
||||||
|
|
||||||
name: string;
|
@Input() community: Community = new Community();
|
||||||
description: string;
|
formModel: DynamicFormControlModel[] = [
|
||||||
introductory: string;
|
new DynamicInputModel({
|
||||||
copyright: string;
|
id: 'title',
|
||||||
news: string;
|
name: 'dc.title',
|
||||||
|
label: 'Name',
|
||||||
|
required: true,
|
||||||
|
validators: {
|
||||||
|
required: null
|
||||||
|
},
|
||||||
|
errorMessages: {
|
||||||
|
required: 'Please enter a name for this title'
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new DynamicTextAreaModel({
|
||||||
|
id: 'description',
|
||||||
|
name: 'dc.description',
|
||||||
|
label: 'Introductory text (HTML)',
|
||||||
|
}),
|
||||||
|
new DynamicTextAreaModel({
|
||||||
|
id: 'abstract',
|
||||||
|
name: 'dc.description.abstract',
|
||||||
|
label: 'Short Description',
|
||||||
|
}),
|
||||||
|
new DynamicTextAreaModel({
|
||||||
|
id: 'rights',
|
||||||
|
name: 'dc.rights',
|
||||||
|
label: 'Copyright text (HTML)',
|
||||||
|
}),
|
||||||
|
new DynamicTextAreaModel({
|
||||||
|
id: 'tableofcontents',
|
||||||
|
name: 'dc.description.tableofcontents',
|
||||||
|
label: 'News (HTML)',
|
||||||
|
}),
|
||||||
|
];
|
||||||
|
|
||||||
nameRequiredError = false;
|
formGroup: FormGroup;
|
||||||
|
|
||||||
@Output() submitted: EventEmitter<any> = new EventEmitter();
|
@Output() submitForm: EventEmitter<any> = new EventEmitter();
|
||||||
|
|
||||||
public constructor(private location: Location) {
|
|
||||||
|
|
||||||
|
public constructor(private location: Location, private formService: DynamicFormService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmit(data: any) {
|
ngOnInit(): void {
|
||||||
if (isNotEmpty(data.name)) {
|
this.formModel.forEach(
|
||||||
this.submitted.emit(data);
|
(fieldModel: DynamicInputModel) => {
|
||||||
this.nameRequiredError = false;
|
fieldModel.value = this.community.findMetadata(fieldModel.name);
|
||||||
} else {
|
}
|
||||||
this.nameRequiredError = true;
|
);
|
||||||
}
|
this.formGroup = this.formService.createFormGroup(this.formModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(event: Event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
const metadata = this.formModel.map(
|
||||||
|
(fieldModel: DynamicInputModel) => {
|
||||||
|
return { key: fieldModel.name, value: fieldModel.value }
|
||||||
|
}
|
||||||
|
);
|
||||||
|
const filteredOldMetadata = this.community.metadata.filter((filter) => !metadata.map((md) => md.key).includes(filter.key));
|
||||||
|
const filteredNewMetadata = metadata.filter((md) => isNotEmpty(md.value));
|
||||||
|
const newMetadata = [...filteredOldMetadata, ...filteredNewMetadata];
|
||||||
|
const updatedCommunity = Object.assign({}, this.community, {
|
||||||
|
metadata: newMetadata,
|
||||||
|
type: ResourceType.Community
|
||||||
|
});
|
||||||
|
this.submitForm.emit(updatedCommunity);
|
||||||
}
|
}
|
||||||
|
|
||||||
cancel() {
|
cancel() {
|
||||||
this.location.back();
|
this.location.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -5,13 +5,23 @@ import { CommunityPageComponent } from './community-page.component';
|
|||||||
import { CommunityPageResolver } from './community-page.resolver';
|
import { CommunityPageResolver } from './community-page.resolver';
|
||||||
import { CreateCommunityPageComponent } from './create-community-page/create-community-page.component';
|
import { CreateCommunityPageComponent } from './create-community-page/create-community-page.component';
|
||||||
import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
|
import { AuthenticatedGuard } from '../core/auth/authenticated.guard';
|
||||||
|
import { EditCommunityPageComponent } from './edit-community-page/edit-community-page.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
RouterModule.forChild([
|
RouterModule.forChild([
|
||||||
{ path: 'create',
|
{ path: 'create',
|
||||||
component: CreateCommunityPageComponent,
|
component: CreateCommunityPageComponent,
|
||||||
canActivate: [AuthenticatedGuard] },
|
canActivate: [AuthenticatedGuard]
|
||||||
|
},
|
||||||
|
{ path: ':id/edit',
|
||||||
|
pathMatch: 'full',
|
||||||
|
component: EditCommunityPageComponent,
|
||||||
|
canActivate: [AuthenticatedGuard],
|
||||||
|
resolve: {
|
||||||
|
community: CommunityPageResolver
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: ':id',
|
path: ':id',
|
||||||
component: CommunityPageComponent,
|
component: CommunityPageComponent,
|
||||||
|
@@ -28,6 +28,8 @@
|
|||||||
[community]="communityPayload"></ds-community-page-sub-collection-list>
|
[community]="communityPayload"></ds-community-page-sub-collection-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<a [routerLink]="'edit'">Edit</a>
|
||||||
|
|
||||||
<ds-error *ngIf="communityRD?.hasFailed" message="{{'error.community' | translate}}"></ds-error>
|
<ds-error *ngIf="communityRD?.hasFailed" message="{{'error.community' | translate}}"></ds-error>
|
||||||
<ds-loading *ngIf="communityRD?.isLoading"
|
<ds-loading *ngIf="communityRD?.isLoading"
|
||||||
message="{{'loading.community' | translate}}"></ds-loading>
|
message="{{'loading.community' | translate}}"></ds-loading>
|
||||||
|
@@ -24,8 +24,6 @@ import { hasValue } from '../shared/empty.util';
|
|||||||
export class CommunityPageComponent implements OnInit, OnDestroy {
|
export class CommunityPageComponent implements OnInit, OnDestroy {
|
||||||
communityRD$: Observable<RemoteData<Community>>;
|
communityRD$: Observable<RemoteData<Community>>;
|
||||||
logoRD$: Observable<RemoteData<Bitstream>>;
|
logoRD$: Observable<RemoteData<Bitstream>>;
|
||||||
|
|
||||||
|
|
||||||
private subs: Subscription[] = [];
|
private subs: Subscription[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@@ -42,14 +40,9 @@ export class CommunityPageComponent implements OnInit, OnDestroy {
|
|||||||
map((rd: RemoteData<Community>) => rd.payload),
|
map((rd: RemoteData<Community>) => rd.payload),
|
||||||
filter((community: Community) => hasValue(community)),
|
filter((community: Community) => hasValue(community)),
|
||||||
mergeMap((community: Community) => community.logo));
|
mergeMap((community: Community) => community.logo));
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
|
this.subs.filter((sub) => hasValue(sub)).forEach((sub) => sub.unsubscribe());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -8,6 +8,7 @@ import { CommunityPageSubCollectionListComponent } from './sub-collection-list/c
|
|||||||
import { CommunityPageRoutingModule } from './community-page-routing.module';
|
import { CommunityPageRoutingModule } from './community-page-routing.module';
|
||||||
import { CreateCommunityPageComponent } from './create-community-page/create-community-page.component';
|
import { CreateCommunityPageComponent } from './create-community-page/create-community-page.component';
|
||||||
import { CommunityFormComponent } from './community-form/community-form.component';
|
import { CommunityFormComponent } from './community-form/community-form.component';
|
||||||
|
import { EditCommunityPageComponent } from './edit-community-page/edit-community-page.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -19,6 +20,7 @@ import { CommunityFormComponent } from './community-form/community-form.componen
|
|||||||
CommunityPageComponent,
|
CommunityPageComponent,
|
||||||
CommunityPageSubCollectionListComponent,
|
CommunityPageSubCollectionListComponent,
|
||||||
CreateCommunityPageComponent,
|
CreateCommunityPageComponent,
|
||||||
|
EditCommunityPageComponent,
|
||||||
CommunityFormComponent
|
CommunityFormComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@@ -7,5 +7,5 @@
|
|||||||
</ng-container>
|
</ng-container>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ds-community-form (submitted)="onSubmit($event)"></ds-community-form>
|
<ds-community-form (submitForm)="onSubmit($event)"></ds-community-form>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -8,12 +8,10 @@ import { Observable } from 'rxjs/Observable';
|
|||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
import { Community } from '../../core/shared/community.model';
|
import { Community } from '../../core/shared/community.model';
|
||||||
import { DSOSuccessResponse, ErrorResponse } from '../../core/cache/response-cache.models';
|
import { DSOSuccessResponse, ErrorResponse } from '../../core/cache/response-cache.models';
|
||||||
import { BrowserModule } from '@angular/platform-browser';
|
|
||||||
import { SharedModule } from '../../shared/shared.module';
|
import { SharedModule } from '../../shared/shared.module';
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { CommunityFormComponent } from '../community-form/community-form.component';
|
import { CommunityFormComponent } from '../community-form/community-form.component';
|
||||||
import { RouterTestingModule } from '@angular/router/testing';
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
import { RequestError } from '../../core/data/request.models';
|
|
||||||
|
|
||||||
describe('CreateCommunityPageComponent', () => {
|
describe('CreateCommunityPageComponent', () => {
|
||||||
let comp: CreateCommunityPageComponent;
|
let comp: CreateCommunityPageComponent;
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, OnInit } from '@angular/core';
|
||||||
import { Community } from '../../core/shared/community.model';
|
import { Community } from '../../core/shared/community.model';
|
||||||
import { CommunityDataService } from '../../core/data/community-data.service';
|
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
@@ -7,55 +7,46 @@ import { Router } from '@angular/router';
|
|||||||
import { RemoteData } from '../../core/data/remote-data';
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
import { isNotEmpty } from '../../shared/empty.util';
|
import { isNotEmpty } from '../../shared/empty.util';
|
||||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||||
import { take } from 'rxjs/operators';
|
import { map, take } from 'rxjs/operators';
|
||||||
import { ResourceType } from '../../core/shared/resource-type';
|
import { getSucceededRemoteData } from '../../core/shared/operators';
|
||||||
import { NormalizedCommunity } from '../../core/cache/models/normalized-community.model';
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'ds-create-community',
|
selector: 'ds-create-community',
|
||||||
styleUrls: ['./create-community-page.component.scss'],
|
styleUrls: ['./create-community-page.component.scss'],
|
||||||
templateUrl: './create-community-page.component.html'
|
templateUrl: './create-community-page.component.html'
|
||||||
})
|
})
|
||||||
export class CreateCommunityPageComponent {
|
export class CreateCommunityPageComponent implements OnInit {
|
||||||
|
|
||||||
public parentUUID$: Observable<string>;
|
public parentUUID$: Observable<string>;
|
||||||
public communityRDObs: Observable<RemoteData<Community>>;
|
public parentRD$: Observable<RemoteData<Community>>;
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
private communityDataService: CommunityDataService,
|
private communityDataService: CommunityDataService,
|
||||||
private routeService: RouteService,
|
private routeService: RouteService,
|
||||||
private router: Router
|
private router: Router
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
this.parentUUID$ = this.routeService.getQueryParameterValue('parent');
|
this.parentUUID$ = this.routeService.getQueryParameterValue('parent');
|
||||||
this.parentUUID$.subscribe((uuid: string) => {
|
this.parentUUID$.subscribe((parentID: string) => {
|
||||||
if (isNotEmpty(uuid)) {
|
if (isNotEmpty(parentID)) {
|
||||||
this.communityRDObs = this.communityDataService.findById(uuid);
|
this.parentRD$ = this.communityDataService.findById(parentID);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onSubmit(data: any) {
|
onSubmit(community: Community) {
|
||||||
this.parentUUID$.pipe(take(1)).subscribe((uuid: string) => {
|
this.parentUUID$.pipe(take(1)).subscribe((uuid: string) => {
|
||||||
const community = Object.assign(new NormalizedCommunity(), {
|
this.communityDataService.create(community, uuid)
|
||||||
name: data.name,
|
.pipe(getSucceededRemoteData())
|
||||||
metadata: [
|
.subscribe((communityRD: RemoteData<Community>) => {
|
||||||
{ key: 'dc.description', value: data.introductory },
|
const newUUID = communityRD.payload.uuid;
|
||||||
{ key: 'dc.description.abstract', value: data.description },
|
this.router.navigate(['/communities/' + newUUID]);
|
||||||
{ key: 'dc.rights', value: data.copyright }
|
|
||||||
// TODO: metadata for news
|
|
||||||
],
|
|
||||||
type: ResourceType.Community
|
|
||||||
});
|
|
||||||
this.communityDataService.create(community, uuid).pipe(take(1)).subscribe((rd: RemoteData<DSpaceObject>) => {
|
|
||||||
if (rd.hasSucceeded) {
|
|
||||||
if (uuid) {
|
|
||||||
this.router.navigate(['communities', uuid]);
|
|
||||||
} else {
|
|
||||||
this.router.navigate([]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,11 @@
|
|||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 pb-4">
|
||||||
|
<ng-container *ngVar="(parentUUID$ | async)?.payload as parent">
|
||||||
|
<h2 *ngIf="!parent" id="header" class="border-bottom pb-2">{{ 'community.edit.head' | translate }}</h2>
|
||||||
|
<h2 *ngIf="parent" id="sub-header" class="border-bottom pb-2">{{ 'community.edit.sub-head' | translate:{ parent: parent.name } }}</h2>
|
||||||
|
</ng-container>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<ds-community-form (submitForm)="onSubmit($event)" [community]="(communityRD$ | async)?.payload"></ds-community-form>
|
||||||
|
</div>
|
@@ -0,0 +1 @@
|
|||||||
|
|
@@ -0,0 +1,90 @@
|
|||||||
|
import { CreateCommunityPageComponent } from './create-community-page.component';
|
||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||||
|
import { RouteService } from '../../shared/services/route.service';
|
||||||
|
import { Router } from '@angular/router';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { Observable } from 'rxjs/Observable';
|
||||||
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
|
import { Community } from '../../core/shared/community.model';
|
||||||
|
import { DSOSuccessResponse, ErrorResponse } from '../../core/cache/response-cache.models';
|
||||||
|
import { BrowserModule } from '@angular/platform-browser';
|
||||||
|
import { SharedModule } from '../../shared/shared.module';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { CommunityFormComponent } from '../community-form/community-form.component';
|
||||||
|
import { RouterTestingModule } from '@angular/router/testing';
|
||||||
|
import { RequestError } from '../../core/data/request.models';
|
||||||
|
|
||||||
|
describe('CreateCommunityPageComponent', () => {
|
||||||
|
let comp: CreateCommunityPageComponent;
|
||||||
|
let fixture: ComponentFixture<CreateCommunityPageComponent>;
|
||||||
|
let communityDataService: CommunityDataService;
|
||||||
|
let routeService: RouteService;
|
||||||
|
let router: Router;
|
||||||
|
|
||||||
|
const community = Object.assign(new Community(), {
|
||||||
|
uuid: 'a20da287-e174-466a-9926-f66b9300d347',
|
||||||
|
name: 'test community'
|
||||||
|
});
|
||||||
|
|
||||||
|
const newCommunity = Object.assign(new Community(), {
|
||||||
|
uuid: '1ff59938-a69a-4e62-b9a4-718569c55d48',
|
||||||
|
name: 'new community'
|
||||||
|
});
|
||||||
|
|
||||||
|
const communityDataServiceStub = {
|
||||||
|
findById: (uuid) => Observable.of(new RemoteData(false, false, true, null, Object.assign(new Community(), {
|
||||||
|
uuid: uuid,
|
||||||
|
name: community.name
|
||||||
|
}))),
|
||||||
|
create: (com, uuid?) => Observable.of(new RemoteData(false, false, true, undefined, newCommunity))
|
||||||
|
};
|
||||||
|
const routeServiceStub = {
|
||||||
|
getQueryParameterValue: (param) => Observable.of(community.uuid)
|
||||||
|
};
|
||||||
|
const routerStub = {
|
||||||
|
navigate: (commands) => commands
|
||||||
|
};
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [TranslateModule.forRoot(), SharedModule, CommonModule, RouterTestingModule],
|
||||||
|
declarations: [CreateCommunityPageComponent, CommunityFormComponent],
|
||||||
|
providers: [
|
||||||
|
{ provide: CommunityDataService, useValue: communityDataServiceStub },
|
||||||
|
{ provide: RouteService, useValue: routeServiceStub },
|
||||||
|
{ provide: Router, useValue: routerStub }
|
||||||
|
]
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(CreateCommunityPageComponent);
|
||||||
|
comp = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
communityDataService = (comp as any).communityDataService;
|
||||||
|
routeService = (comp as any).routeService;
|
||||||
|
router = (comp as any).router;
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('onSubmit', () => {
|
||||||
|
const data = {
|
||||||
|
name: 'test'
|
||||||
|
};
|
||||||
|
|
||||||
|
it('should navigate when successful', () => {
|
||||||
|
spyOn(router, 'navigate');
|
||||||
|
comp.onSubmit(data);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(router.navigate).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not navigate on failure', () => {
|
||||||
|
spyOn(router, 'navigate');
|
||||||
|
spyOn(communityDataService, 'create').and.returnValue(Observable.of(new RemoteData(true, true, false, undefined, newCommunity)));
|
||||||
|
comp.onSubmit(data);
|
||||||
|
fixture.detectChanges();
|
||||||
|
expect(router.navigate).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,46 @@
|
|||||||
|
import { Component } from '@angular/core';
|
||||||
|
import { Community } from '../../core/shared/community.model';
|
||||||
|
import { CommunityDataService } from '../../core/data/community-data.service';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { RouteService } from '../../shared/services/route.service';
|
||||||
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
|
import { RemoteData } from '../../core/data/remote-data';
|
||||||
|
import { isNotEmpty } from '../../shared/empty.util';
|
||||||
|
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||||
|
import { first, map, take, tap } from 'rxjs/operators';
|
||||||
|
import { ResourceType } from '../../core/shared/resource-type';
|
||||||
|
import { NormalizedCommunity } from '../../core/cache/models/normalized-community.model';
|
||||||
|
import { getSucceededRemoteData } from '../../core/shared/operators';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-edit-community',
|
||||||
|
styleUrls: ['./edit-community-page.component.scss'],
|
||||||
|
templateUrl: './edit-community-page.component.html'
|
||||||
|
})
|
||||||
|
export class EditCommunityPageComponent {
|
||||||
|
|
||||||
|
public parentUUID$: Observable<string>;
|
||||||
|
public parentRD$: Observable<RemoteData<Community>>;
|
||||||
|
public communityRD$: Observable<RemoteData<Community>>;
|
||||||
|
|
||||||
|
public constructor(
|
||||||
|
private communityDataService: CommunityDataService,
|
||||||
|
private routeService: RouteService,
|
||||||
|
private router: Router,
|
||||||
|
private route: ActivatedRoute
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.communityRD$ = this.route.data.pipe(first(), map((data) => data.community));
|
||||||
|
}
|
||||||
|
|
||||||
|
onSubmit(community: Community) {
|
||||||
|
this.communityDataService.update(community)
|
||||||
|
.pipe(getSucceededRemoteData())
|
||||||
|
.subscribe((communityRD: RemoteData<Community>) => {
|
||||||
|
const newUUID = communityRD.payload.uuid;
|
||||||
|
this.router.navigate(['/communities/' + newUUID]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
36
src/app/core/cache/builders/data-build.service.ts
vendored
Normal file
36
src/app/core/cache/builders/data-build.service.ts
vendored
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { NormalizedObject } from '../models/normalized-object.model';
|
||||||
|
import { CacheableObject } from '../object-cache.reducer';
|
||||||
|
import { getRelationships } from './build-decorators';
|
||||||
|
import { NormalizedObjectFactory } from '../models/normalized-object-factory';
|
||||||
|
import { map, take } from 'rxjs/operators';
|
||||||
|
import { hasValue, isNotEmpty } from '../../../shared/empty.util';
|
||||||
|
import { PaginatedList } from '../../data/paginated-list';
|
||||||
|
|
||||||
|
export function isRestDataObject(halObj: any) {
|
||||||
|
return isNotEmpty(halObj._links) && hasValue(halObj._links.self);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isRestPaginatedList(halObj: any) {
|
||||||
|
return hasValue(halObj.page) && hasValue(halObj._embedded);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isPaginatedList(halObj: any) {
|
||||||
|
return hasValue(halObj.page) && hasValue(halObj.pageInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DataBuildService {
|
||||||
|
normalize<TDomain extends CacheableObject, TNormalized extends NormalizedObject>(domainModel: TDomain): TNormalized {
|
||||||
|
const normalizedConstructor = NormalizedObjectFactory.getConstructor(domainModel.type);
|
||||||
|
const relationships = getRelationships(normalizedConstructor) || [];
|
||||||
|
|
||||||
|
const normalizedModel = Object.assign({}, domainModel) as any;
|
||||||
|
relationships.forEach((key: string) => {
|
||||||
|
if (hasValue(domainModel[key])) {
|
||||||
|
domainModel[key] = undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return normalizedModel;
|
||||||
|
}
|
||||||
|
}
|
@@ -51,10 +51,7 @@ export class RemoteDataBuildService {
|
|||||||
const requestEntry$ = observableRace(
|
const requestEntry$ = observableRace(
|
||||||
href$.pipe(getRequestFromRequestHref(this.requestService)),
|
href$.pipe(getRequestFromRequestHref(this.requestService)),
|
||||||
requestUUID$.pipe(getRequestFromRequestUUID(this.requestService)),
|
requestUUID$.pipe(getRequestFromRequestUUID(this.requestService)),
|
||||||
).pipe(
|
|
||||||
take(1)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// always use self link if that is cached, only if it isn't, get it via the response.
|
// always use self link if that is cached, only if it isn't, get it via the response.
|
||||||
const payload$ =
|
const payload$ =
|
||||||
observableCombineLatest(
|
observableCombineLatest(
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { autoserialize, inheritSerialization } from 'cerialize';
|
import { autoserialize, deserialize, inheritSerialization, serialize } from 'cerialize';
|
||||||
|
|
||||||
import { NormalizedDSpaceObject } from './normalized-dspace-object.model';
|
import { NormalizedDSpaceObject } from './normalized-dspace-object.model';
|
||||||
import { Community } from '../../shared/community.model';
|
import { Community } from '../../shared/community.model';
|
||||||
@@ -21,32 +21,32 @@ export class NormalizedCommunity extends NormalizedDSpaceObject {
|
|||||||
/**
|
/**
|
||||||
* The Bitstream that represents the logo of this Community
|
* The Bitstream that represents the logo of this Community
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@deserialize
|
||||||
@relationship(ResourceType.Bitstream, false)
|
@relationship(ResourceType.Bitstream, false)
|
||||||
logo: string;
|
logo: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of Communities that are direct parents of this Community
|
* An array of Communities that are direct parents of this Community
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@deserialize
|
||||||
@relationship(ResourceType.Community, true)
|
@relationship(ResourceType.Community, true)
|
||||||
parents: string[];
|
parents: string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Community that owns this Community
|
* The Community that owns this Community
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@deserialize
|
||||||
@relationship(ResourceType.Community, false)
|
@relationship(ResourceType.Community, false)
|
||||||
owner: string;
|
owner: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* List of Collections that are owned by this Community
|
* List of Collections that are owned by this Community
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@deserialize
|
||||||
@relationship(ResourceType.Collection, true)
|
@relationship(ResourceType.Collection, true)
|
||||||
collections: string[];
|
collections: string[];
|
||||||
|
|
||||||
@autoserialize
|
@deserialize
|
||||||
@relationship(ResourceType.Community, true)
|
@relationship(ResourceType.Community, true)
|
||||||
subcommunities: string[];
|
subcommunities: string[];
|
||||||
|
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { autoserialize, autoserializeAs } from 'cerialize';
|
import { autoserialize, autoserializeAs, deserialize, serialize } from 'cerialize';
|
||||||
import { DSpaceObject } from '../../shared/dspace-object.model';
|
import { DSpaceObject } from '../../shared/dspace-object.model';
|
||||||
|
|
||||||
import { Metadatum } from '../../shared/metadatum.model';
|
import { Metadatum } from '../../shared/metadatum.model';
|
||||||
@@ -45,12 +45,6 @@ export class NormalizedDSpaceObject extends NormalizedObject {
|
|||||||
@autoserialize
|
@autoserialize
|
||||||
type: ResourceType;
|
type: ResourceType;
|
||||||
|
|
||||||
/**
|
|
||||||
* The name for this DSpaceObject
|
|
||||||
*/
|
|
||||||
@autoserialize
|
|
||||||
name: string;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array containing all metadata of this DSpaceObject
|
* An array containing all metadata of this DSpaceObject
|
||||||
*/
|
*/
|
||||||
@@ -60,13 +54,13 @@ export class NormalizedDSpaceObject extends NormalizedObject {
|
|||||||
/**
|
/**
|
||||||
* An array of DSpaceObjects that are direct parents of this DSpaceObject
|
* An array of DSpaceObjects that are direct parents of this DSpaceObject
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@deserialize
|
||||||
parents: string[];
|
parents: string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The DSpaceObject that owns this DSpaceObject
|
* The DSpaceObject that owns this DSpaceObject
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@deserialize
|
||||||
owner: string;
|
owner: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -75,7 +69,7 @@ export class NormalizedDSpaceObject extends NormalizedObject {
|
|||||||
* Repeated here to make the serialization work,
|
* Repeated here to make the serialization work,
|
||||||
* inheritSerialization doesn't seem to work for more than one level
|
* inheritSerialization doesn't seem to work for more than one level
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@deserialize
|
||||||
_links: {
|
_links: {
|
||||||
[name: string]: string
|
[name: string]: string
|
||||||
}
|
}
|
||||||
|
@@ -63,6 +63,8 @@ import { NotificationsService } from '../shared/notifications/notifications.serv
|
|||||||
import { UploaderService } from '../shared/uploader/uploader.service';
|
import { UploaderService } from '../shared/uploader/uploader.service';
|
||||||
import { BrowseItemsResponseParsingService } from './data/browse-items-response-parsing-service';
|
import { BrowseItemsResponseParsingService } from './data/browse-items-response-parsing-service';
|
||||||
import { DSpaceObjectDataService } from './data/dspace-object-data.service';
|
import { DSpaceObjectDataService } from './data/dspace-object-data.service';
|
||||||
|
import { DataBuildService } from './cache/builders/data-build.service';
|
||||||
|
import { DSOUpdateComparator } from './data/dso-update-comparator';
|
||||||
|
|
||||||
const IMPORTS = [
|
const IMPORTS = [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
@@ -99,6 +101,7 @@ const PROVIDERS = [
|
|||||||
ObjectCacheService,
|
ObjectCacheService,
|
||||||
PaginationComponentOptions,
|
PaginationComponentOptions,
|
||||||
RegistryService,
|
RegistryService,
|
||||||
|
DataBuildService,
|
||||||
RemoteDataBuildService,
|
RemoteDataBuildService,
|
||||||
RequestService,
|
RequestService,
|
||||||
EndpointMapResponseParsingService,
|
EndpointMapResponseParsingService,
|
||||||
@@ -126,6 +129,7 @@ const PROVIDERS = [
|
|||||||
UploaderService,
|
UploaderService,
|
||||||
UUIDService,
|
UUIDService,
|
||||||
DSpaceObjectDataService,
|
DSpaceObjectDataService,
|
||||||
|
DSOUpdateComparator,
|
||||||
// register AuthInterceptor as HttpInterceptor
|
// register AuthInterceptor as HttpInterceptor
|
||||||
{
|
{
|
||||||
provide: HTTP_INTERCEPTORS,
|
provide: HTTP_INTERCEPTORS,
|
||||||
|
@@ -8,15 +8,7 @@ import { GenericConstructor } from '../shared/generic-constructor';
|
|||||||
import { PaginatedList } from './paginated-list';
|
import { PaginatedList } from './paginated-list';
|
||||||
import { ResourceType } from '../shared/resource-type';
|
import { ResourceType } from '../shared/resource-type';
|
||||||
import { RESTURLCombiner } from '../url-combiner/rest-url-combiner';
|
import { RESTURLCombiner } from '../url-combiner/rest-url-combiner';
|
||||||
|
import { isRestDataObject, isRestPaginatedList } from '../cache/builders/data-build.service';
|
||||||
function isObjectLevel(halObj: any) {
|
|
||||||
return isNotEmpty(halObj._links) && hasValue(halObj._links.self);
|
|
||||||
}
|
|
||||||
|
|
||||||
function isPaginatedResponse(halObj: any) {
|
|
||||||
return hasValue(halObj.page) && hasValue(halObj._embedded);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* tslint:disable:max-classes-per-file */
|
/* tslint:disable:max-classes-per-file */
|
||||||
|
|
||||||
export abstract class BaseResponseParsingService {
|
export abstract class BaseResponseParsingService {
|
||||||
@@ -29,11 +21,11 @@ export abstract class BaseResponseParsingService {
|
|||||||
if (isNotEmpty(data)) {
|
if (isNotEmpty(data)) {
|
||||||
if (hasNoValue(data) || (typeof data !== 'object')) {
|
if (hasNoValue(data) || (typeof data !== 'object')) {
|
||||||
return data;
|
return data;
|
||||||
} else if (isPaginatedResponse(data)) {
|
} else if (isRestPaginatedList(data)) {
|
||||||
return this.processPaginatedList(data, requestUUID);
|
return this.processPaginatedList(data, requestUUID);
|
||||||
} else if (Array.isArray(data)) {
|
} else if (Array.isArray(data)) {
|
||||||
return this.processArray(data, requestUUID);
|
return this.processArray(data, requestUUID);
|
||||||
} else if (isObjectLevel(data)) {
|
} else if (isRestDataObject(data)) {
|
||||||
data = this.fixBadEPersonRestResponse(data);
|
data = this.fixBadEPersonRestResponse(data);
|
||||||
const object = this.deserialize(data);
|
const object = this.deserialize(data);
|
||||||
if (isNotEmpty(data._embedded)) {
|
if (isNotEmpty(data._embedded)) {
|
||||||
@@ -43,10 +35,10 @@ export abstract class BaseResponseParsingService {
|
|||||||
.forEach((property) => {
|
.forEach((property) => {
|
||||||
const parsedObj = this.process<ObjectDomain, ObjectType>(data._embedded[property], requestUUID);
|
const parsedObj = this.process<ObjectDomain, ObjectType>(data._embedded[property], requestUUID);
|
||||||
if (isNotEmpty(parsedObj)) {
|
if (isNotEmpty(parsedObj)) {
|
||||||
if (isPaginatedResponse(data._embedded[property])) {
|
if (isRestPaginatedList(data._embedded[property])) {
|
||||||
object[property] = parsedObj;
|
object[property] = parsedObj;
|
||||||
object[property].page = parsedObj.page.map((obj) => obj.self);
|
object[property].page = parsedObj.page.map((obj) => obj.self);
|
||||||
} else if (isObjectLevel(data._embedded[property])) {
|
} else if (isRestDataObject(data._embedded[property])) {
|
||||||
object[property] = parsedObj.self;
|
object[property] = parsedObj.self;
|
||||||
} else if (Array.isArray(parsedObj)) {
|
} else if (Array.isArray(parsedObj)) {
|
||||||
object[property] = parsedObj.map((obj) => obj.self)
|
object[property] = parsedObj.map((obj) => obj.self)
|
||||||
@@ -80,7 +72,7 @@ export abstract class BaseResponseParsingService {
|
|||||||
list = this.flattenSingleKeyObject(list);
|
list = this.flattenSingleKeyObject(list);
|
||||||
}
|
}
|
||||||
const page: ObjectDomain[] = this.processArray(list, requestUUID);
|
const page: ObjectDomain[] = this.processArray(list, requestUUID);
|
||||||
return new PaginatedList<ObjectDomain>(pageInfo, page);
|
return new PaginatedList<ObjectDomain>(pageInfo, page, );
|
||||||
}
|
}
|
||||||
|
|
||||||
protected processArray<ObjectDomain, ObjectType>(data: any, requestUUID: string): ObjectDomain[] {
|
protected processArray<ObjectDomain, ObjectType>(data: any, requestUUID: string): ObjectDomain[] {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { Inject, Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||||
import { NormalizedCollection } from '../cache/models/normalized-collection.model';
|
import { NormalizedCollection } from '../cache/models/normalized-collection.model';
|
||||||
@@ -10,9 +10,10 @@ import { CommunityDataService } from './community-data.service';
|
|||||||
import { RequestService } from './request.service';
|
import { RequestService } from './request.service';
|
||||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
import { AuthService } from '../auth/auth.service';
|
import { AuthService } from '../auth/auth.service';
|
||||||
import { Community } from '../shared/community.model';
|
|
||||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { DataBuildService } from '../cache/builders/data-build.service';
|
||||||
|
import { DSOUpdateComparator } from './dso-update-comparator';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CollectionDataService extends ComColDataService<NormalizedCollection, Collection> {
|
export class CollectionDataService extends ComColDataService<NormalizedCollection, Collection> {
|
||||||
@@ -21,13 +22,15 @@ export class CollectionDataService extends ComColDataService<NormalizedCollectio
|
|||||||
constructor(
|
constructor(
|
||||||
protected requestService: RequestService,
|
protected requestService: RequestService,
|
||||||
protected rdbService: RemoteDataBuildService,
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected dataBuildService: DataBuildService,
|
||||||
protected store: Store<CoreState>,
|
protected store: Store<CoreState>,
|
||||||
protected cds: CommunityDataService,
|
protected cds: CommunityDataService,
|
||||||
protected objectCache: ObjectCacheService,
|
protected objectCache: ObjectCacheService,
|
||||||
protected halService: HALEndpointService,
|
protected halService: HALEndpointService,
|
||||||
protected authService: AuthService,
|
protected authService: AuthService,
|
||||||
protected notificationsService: NotificationsService,
|
protected notificationsService: NotificationsService,
|
||||||
protected http: HttpClient
|
protected http: HttpClient,
|
||||||
|
protected comparator: DSOUpdateComparator
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
@@ -14,10 +14,12 @@ import { NormalizedObject } from '../cache/models/normalized-object.model';
|
|||||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
import { RequestEntry } from './request.reducer';
|
import { RequestEntry } from './request.reducer';
|
||||||
import { of as observableOf } from 'rxjs';
|
import { of as observableOf } from 'rxjs';
|
||||||
import { Community } from '../shared/community.model';
|
|
||||||
import { AuthService } from '../auth/auth.service';
|
import { AuthService } from '../auth/auth.service';
|
||||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { DataBuildService } from '../cache/builders/data-build.service';
|
||||||
|
import { DSOUpdateComparator } from './dso-update-comparator';
|
||||||
|
import { UpdateComparator } from './update-comparator';
|
||||||
|
|
||||||
const LINK_NAME = 'test';
|
const LINK_NAME = 'test';
|
||||||
|
|
||||||
@@ -30,6 +32,7 @@ class TestService extends ComColDataService<NormalizedTestObject, any> {
|
|||||||
constructor(
|
constructor(
|
||||||
protected requestService: RequestService,
|
protected requestService: RequestService,
|
||||||
protected rdbService: RemoteDataBuildService,
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected dataBuildService: DataBuildService,
|
||||||
protected store: Store<CoreState>,
|
protected store: Store<CoreState>,
|
||||||
protected EnvConfig: GlobalConfig,
|
protected EnvConfig: GlobalConfig,
|
||||||
protected cds: CommunityDataService,
|
protected cds: CommunityDataService,
|
||||||
@@ -38,6 +41,7 @@ class TestService extends ComColDataService<NormalizedTestObject, any> {
|
|||||||
protected authService: AuthService,
|
protected authService: AuthService,
|
||||||
protected notificationsService: NotificationsService,
|
protected notificationsService: NotificationsService,
|
||||||
protected http: HttpClient,
|
protected http: HttpClient,
|
||||||
|
protected comparator: DSOUpdateComparator,
|
||||||
protected linkPath: string
|
protected linkPath: string
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
@@ -60,6 +64,8 @@ describe('ComColDataService', () => {
|
|||||||
const EnvConfig = {} as GlobalConfig;
|
const EnvConfig = {} as GlobalConfig;
|
||||||
const notificationsService = {} as NotificationsService;
|
const notificationsService = {} as NotificationsService;
|
||||||
const http = {} as HttpClient;
|
const http = {} as HttpClient;
|
||||||
|
const comparator = {} as any;
|
||||||
|
const dataBuildService = {} as DataBuildService;
|
||||||
|
|
||||||
const scopeID = 'd9d30c0c-69b7-4369-8397-ca67c888974d';
|
const scopeID = 'd9d30c0c-69b7-4369-8397-ca67c888974d';
|
||||||
const options = Object.assign(new FindAllOptions(), {
|
const options = Object.assign(new FindAllOptions(), {
|
||||||
@@ -78,7 +84,7 @@ describe('ComColDataService', () => {
|
|||||||
const authHeader = 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJlaWQiOiJhNjA4NmIzNC0zOTE4LTQ1YjctOGRkZC05MzI5YTcwMmEyNmEiLCJzZyI6W10sImV4cCI6MTUzNDk0MDcyNX0.RV5GAtiX6cpwBN77P_v16iG9ipeyiO7faNYSNMzq_sQ';
|
const authHeader = 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJlaWQiOiJhNjA4NmIzNC0zOTE4LTQ1YjctOGRkZC05MzI5YTcwMmEyNmEiLCJzZyI6W10sImV4cCI6MTUzNDk0MDcyNX0.RV5GAtiX6cpwBN77P_v16iG9ipeyiO7faNYSNMzq_sQ';
|
||||||
|
|
||||||
const mockHalService = {
|
const mockHalService = {
|
||||||
getEndpoint: (linkPath) => Observable.of(communitiesEndpoint)
|
getEndpoint: (linkPath) => observableOf(communitiesEndpoint)
|
||||||
};
|
};
|
||||||
|
|
||||||
function initMockCommunityDataService(): CommunityDataService {
|
function initMockCommunityDataService(): CommunityDataService {
|
||||||
@@ -112,6 +118,7 @@ describe('ComColDataService', () => {
|
|||||||
return new TestService(
|
return new TestService(
|
||||||
requestService,
|
requestService,
|
||||||
rdbService,
|
rdbService,
|
||||||
|
dataBuildService,
|
||||||
store,
|
store,
|
||||||
EnvConfig,
|
EnvConfig,
|
||||||
cds,
|
cds,
|
||||||
@@ -120,6 +127,7 @@ describe('ComColDataService', () => {
|
|||||||
authService,
|
authService,
|
||||||
notificationsService,
|
notificationsService,
|
||||||
http,
|
http,
|
||||||
|
comparator,
|
||||||
LINK_NAME
|
LINK_NAME
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -20,8 +20,9 @@ import { NormalizedObject } from '../cache/models/normalized-object.model';
|
|||||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
import { RequestEntry } from './request.reducer';
|
import { RequestEntry } from './request.reducer';
|
||||||
import { getResponseFromEntry } from '../shared/operators';
|
import { getResponseFromEntry } from '../shared/operators';
|
||||||
|
import { CacheableObject } from '../cache/object-cache.reducer';
|
||||||
|
|
||||||
export abstract class ComColDataService<TNormalized extends NormalizedObject, TDomain> extends DataService<TNormalized, TDomain> {
|
export abstract class ComColDataService<TNormalized extends NormalizedObject, TDomain extends CacheableObject> extends DataService<TNormalized, TDomain> {
|
||||||
protected abstract cds: CommunityDataService;
|
protected abstract cds: CommunityDataService;
|
||||||
protected abstract objectCache: ObjectCacheService;
|
protected abstract objectCache: ObjectCacheService;
|
||||||
protected abstract halService: HALEndpointService;
|
protected abstract halService: HALEndpointService;
|
||||||
|
@@ -18,6 +18,8 @@ import { Observable } from 'rxjs';
|
|||||||
import { PaginatedList } from './paginated-list';
|
import { PaginatedList } from './paginated-list';
|
||||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { DataBuildService } from '../cache/builders/data-build.service';
|
||||||
|
import { DSOUpdateComparator } from './dso-update-comparator';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CommunityDataService extends ComColDataService<NormalizedCommunity, Community> {
|
export class CommunityDataService extends ComColDataService<NormalizedCommunity, Community> {
|
||||||
@@ -28,12 +30,14 @@ export class CommunityDataService extends ComColDataService<NormalizedCommunity,
|
|||||||
constructor(
|
constructor(
|
||||||
protected requestService: RequestService,
|
protected requestService: RequestService,
|
||||||
protected rdbService: RemoteDataBuildService,
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected dataBuildService: DataBuildService,
|
||||||
protected store: Store<CoreState>,
|
protected store: Store<CoreState>,
|
||||||
protected objectCache: ObjectCacheService,
|
protected objectCache: ObjectCacheService,
|
||||||
protected halService: HALEndpointService,
|
protected halService: HALEndpointService,
|
||||||
protected authService: AuthService,
|
protected authService: AuthService,
|
||||||
protected notificationsService: NotificationsService,
|
protected notificationsService: NotificationsService,
|
||||||
protected http: HttpClient
|
protected http: HttpClient,
|
||||||
|
protected comparator: DSOUpdateComparator
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
@@ -177,7 +177,7 @@ describe('ConfigResponseParsingService', () => {
|
|||||||
'https://rest.api/config/submissionsections/traditionalpagetwo',
|
'https://rest.api/config/submissionsections/traditionalpagetwo',
|
||||||
'https://rest.api/config/submissionsections/upload',
|
'https://rest.api/config/submissionsections/upload',
|
||||||
'https://rest.api/config/submissionsections/license'
|
'https://rest.api/config/submissionsections/license'
|
||||||
])
|
], 'https://rest.api/config/submissiondefinitions/traditional/sections')
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should return a ConfigSuccessResponse if data contains a valid config endpoint response', () => {
|
it('should return a ConfigSuccessResponse if data contains a valid config endpoint response', () => {
|
||||||
|
@@ -1,4 +1,13 @@
|
|||||||
import { delay, distinctUntilChanged, filter, find, switchMap, map, take, tap } from 'rxjs/operators';
|
import {
|
||||||
|
delay,
|
||||||
|
distinctUntilChanged,
|
||||||
|
filter,
|
||||||
|
find,
|
||||||
|
switchMap,
|
||||||
|
map,
|
||||||
|
take,
|
||||||
|
tap, first, mergeMap
|
||||||
|
} from 'rxjs/operators';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { Store } from '@ngrx/store';
|
import { Store } from '@ngrx/store';
|
||||||
import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
|
import { hasValue, isNotEmpty, isNotEmptyOperator } from '../../shared/empty.util';
|
||||||
@@ -32,10 +41,14 @@ import { DSOSuccessResponse, ErrorResponse, RestResponse } from '../cache/respon
|
|||||||
import { NotificationOptions } from '../../shared/notifications/models/notification-options.model';
|
import { NotificationOptions } from '../../shared/notifications/models/notification-options.model';
|
||||||
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
import { DSpaceRESTv2Serializer } from '../dspace-rest-v2/dspace-rest-v2.serializer';
|
||||||
import { NormalizedObjectFactory } from '../cache/models/normalized-object-factory';
|
import { NormalizedObjectFactory } from '../cache/models/normalized-object-factory';
|
||||||
|
import { CacheableObject } from '../cache/object-cache.reducer';
|
||||||
|
import { DataBuildService } from '../cache/builders/data-build.service';
|
||||||
|
import { UpdateComparator } from './update-comparator';
|
||||||
|
|
||||||
export abstract class DataService<TNormalized extends NormalizedObject, TDomain> {
|
export abstract class DataService<TNormalized extends NormalizedObject, TDomain extends CacheableObject> {
|
||||||
protected abstract requestService: RequestService;
|
protected abstract requestService: RequestService;
|
||||||
protected abstract rdbService: RemoteDataBuildService;
|
protected abstract rdbService: RemoteDataBuildService;
|
||||||
|
protected abstract dataBuildService: DataBuildService;
|
||||||
protected abstract store: Store<CoreState>;
|
protected abstract store: Store<CoreState>;
|
||||||
protected abstract linkPath: string;
|
protected abstract linkPath: string;
|
||||||
protected abstract halService: HALEndpointService;
|
protected abstract halService: HALEndpointService;
|
||||||
@@ -43,6 +56,7 @@ export abstract class DataService<TNormalized extends NormalizedObject, TDomain>
|
|||||||
protected abstract authService: AuthService;
|
protected abstract authService: AuthService;
|
||||||
protected abstract notificationsService: NotificationsService;
|
protected abstract notificationsService: NotificationsService;
|
||||||
protected abstract http: HttpClient;
|
protected abstract http: HttpClient;
|
||||||
|
protected abstract comparator: UpdateComparator<TNormalized>;
|
||||||
|
|
||||||
public abstract getBrowseEndpoint(options: FindAllOptions, linkPath?: string): Observable<string>
|
public abstract getBrowseEndpoint(options: FindAllOptions, linkPath?: string): Observable<string>
|
||||||
|
|
||||||
@@ -122,15 +136,21 @@ export abstract class DataService<TNormalized extends NormalizedObject, TDomain>
|
|||||||
* The patch is derived from the differences between the given object and its version in the object cache
|
* The patch is derived from the differences between the given object and its version in the object cache
|
||||||
* @param {DSpaceObject} object The given object
|
* @param {DSpaceObject} object The given object
|
||||||
*/
|
*/
|
||||||
update(object: DSpaceObject) {
|
update(object: TDomain): Observable<RemoteData<TDomain>> {
|
||||||
const oldVersion = this.objectCache.getBySelfLink(object.self);
|
const oldVersion$ = this.objectCache.getBySelfLink(object.self);
|
||||||
const operations = compare(oldVersion, object);
|
return oldVersion$.pipe(first(), mergeMap((oldVersion: TNormalized) => {
|
||||||
if (isNotEmpty(operations)) {
|
const newVersion = this.dataBuildService.normalize<TDomain, TNormalized>(object);
|
||||||
this.objectCache.addPatch(object.self, operations);
|
const operations = this.comparator.compare(oldVersion, newVersion);
|
||||||
}
|
if (isNotEmpty(operations)) {
|
||||||
|
this.objectCache.addPatch(object.self, operations);
|
||||||
|
}
|
||||||
|
return this.findById(object.uuid);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
create(dso: TNormalized, parentUUID: string): Observable<RemoteData<TDomain>> {
|
create(dso: TDomain, parentUUID: string): Observable<RemoteData<TDomain>> {
|
||||||
const requestId = this.requestService.generateRequestId();
|
const requestId = this.requestService.generateRequestId();
|
||||||
const endpoint$ = this.halService.getEndpoint(this.linkPath).pipe(
|
const endpoint$ = this.halService.getEndpoint(this.linkPath).pipe(
|
||||||
isNotEmptyOperator(),
|
isNotEmptyOperator(),
|
||||||
@@ -138,7 +158,8 @@ export abstract class DataService<TNormalized extends NormalizedObject, TDomain>
|
|||||||
map((endpoint: string) => parentUUID ? `${endpoint}?parent=${parentUUID}` : endpoint)
|
map((endpoint: string) => parentUUID ? `${endpoint}?parent=${parentUUID}` : endpoint)
|
||||||
);
|
);
|
||||||
|
|
||||||
const serializedDso = new DSpaceRESTv2Serializer(NormalizedObjectFactory.getConstructor(dso.type)).serialize(dso);
|
const normalizedObject: TNormalized = this.dataBuildService.normalize<TDomain, TNormalized>(dso);
|
||||||
|
const serializedDso = new DSpaceRESTv2Serializer(NormalizedObjectFactory.getConstructor(dso.type)).serialize(normalizedObject);
|
||||||
|
|
||||||
const request$ = endpoint$.pipe(
|
const request$ = endpoint$.pipe(
|
||||||
take(1),
|
take(1),
|
||||||
@@ -150,6 +171,7 @@ export abstract class DataService<TNormalized extends NormalizedObject, TDomain>
|
|||||||
configureRequest(this.requestService)
|
configureRequest(this.requestService)
|
||||||
).subscribe();
|
).subscribe();
|
||||||
|
|
||||||
|
// Resolve self link for new object
|
||||||
const selfLink$ = this.requestService.getByUUID(requestId).pipe(
|
const selfLink$ = this.requestService.getByUUID(requestId).pipe(
|
||||||
getResponseFromEntry(),
|
getResponseFromEntry(),
|
||||||
map((response: RestResponse) => {
|
map((response: RestResponse) => {
|
||||||
|
12
src/app/core/data/dso-update-comparator.ts
Normal file
12
src/app/core/data/dso-update-comparator.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { Operation } from 'fast-json-patch/lib/core';
|
||||||
|
import { compare } from 'fast-json-patch';
|
||||||
|
import { UpdateComparator } from './update-comparator';
|
||||||
|
import { NormalizedDSpaceObject } from '../cache/models/normalized-dspace-object.model';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class DSOUpdateComparator implements UpdateComparator<NormalizedDSpaceObject> {
|
||||||
|
compare(object1: NormalizedDSpaceObject, object2: NormalizedDSpaceObject): Operation[] {
|
||||||
|
return compare(object1.metadata, object2.metadata).map((operation: Operation) => Object.assign({}, operation, { path: '/metadata' + operation.path }));
|
||||||
|
}
|
||||||
|
}
|
@@ -14,6 +14,8 @@ import { ObjectCacheService } from '../cache/object-cache.service';
|
|||||||
import { AuthService } from '../auth/auth.service';
|
import { AuthService } from '../auth/auth.service';
|
||||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { DataBuildService } from '../cache/builders/data-build.service';
|
||||||
|
import { DSOUpdateComparator } from './dso-update-comparator';
|
||||||
|
|
||||||
/* tslint:disable:max-classes-per-file */
|
/* tslint:disable:max-classes-per-file */
|
||||||
class DataServiceImpl extends DataService<NormalizedDSpaceObject, DSpaceObject> {
|
class DataServiceImpl extends DataService<NormalizedDSpaceObject, DSpaceObject> {
|
||||||
@@ -22,12 +24,14 @@ class DataServiceImpl extends DataService<NormalizedDSpaceObject, DSpaceObject>
|
|||||||
constructor(
|
constructor(
|
||||||
protected requestService: RequestService,
|
protected requestService: RequestService,
|
||||||
protected rdbService: RemoteDataBuildService,
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected dataBuildService: DataBuildService,
|
||||||
protected store: Store<CoreState>,
|
protected store: Store<CoreState>,
|
||||||
protected objectCache: ObjectCacheService,
|
protected objectCache: ObjectCacheService,
|
||||||
protected halService: HALEndpointService,
|
protected halService: HALEndpointService,
|
||||||
protected authService: AuthService,
|
protected authService: AuthService,
|
||||||
protected notificationsService: NotificationsService,
|
protected notificationsService: NotificationsService,
|
||||||
protected http: HttpClient) {
|
protected http: HttpClient,
|
||||||
|
protected comparator: DSOUpdateComparator) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,12 +52,14 @@ export class DSpaceObjectDataService {
|
|||||||
constructor(
|
constructor(
|
||||||
protected requestService: RequestService,
|
protected requestService: RequestService,
|
||||||
protected rdbService: RemoteDataBuildService,
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected dataBuildService: DataBuildService,
|
||||||
protected objectCache: ObjectCacheService,
|
protected objectCache: ObjectCacheService,
|
||||||
protected halService: HALEndpointService,
|
protected halService: HALEndpointService,
|
||||||
protected authService: AuthService,
|
protected authService: AuthService,
|
||||||
protected notificationsService: NotificationsService,
|
protected notificationsService: NotificationsService,
|
||||||
protected http: HttpClient) {
|
protected http: HttpClient,
|
||||||
this.dataService = new DataServiceImpl(requestService, rdbService, null, objectCache, halService, authService, notificationsService, http);
|
protected comparator: DSOUpdateComparator) {
|
||||||
|
this.dataService = new DataServiceImpl(requestService, rdbService, dataBuildService, null, objectCache, halService, authService, notificationsService, http, comparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
findById(uuid: string): Observable<RemoteData<DSpaceObject>> {
|
findById(uuid: string): Observable<RemoteData<DSpaceObject>> {
|
||||||
|
@@ -19,6 +19,8 @@ import { ObjectCacheService } from '../cache/object-cache.service';
|
|||||||
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
import { AuthService } from '../auth/auth.service';
|
import { AuthService } from '../auth/auth.service';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { DataBuildService } from '../cache/builders/data-build.service';
|
||||||
|
import { DSOUpdateComparator } from './dso-update-comparator';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ItemDataService extends DataService<NormalizedItem, Item> {
|
export class ItemDataService extends DataService<NormalizedItem, Item> {
|
||||||
@@ -27,13 +29,15 @@ export class ItemDataService extends DataService<NormalizedItem, Item> {
|
|||||||
constructor(
|
constructor(
|
||||||
protected requestService: RequestService,
|
protected requestService: RequestService,
|
||||||
protected rdbService: RemoteDataBuildService,
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected dataBuildService: DataBuildService,
|
||||||
protected store: Store<CoreState>,
|
protected store: Store<CoreState>,
|
||||||
private bs: BrowseService,
|
private bs: BrowseService,
|
||||||
protected objectCache: ObjectCacheService,
|
protected objectCache: ObjectCacheService,
|
||||||
protected halService: HALEndpointService,
|
protected halService: HALEndpointService,
|
||||||
protected authService: AuthService,
|
protected authService: AuthService,
|
||||||
protected notificationsService: NotificationsService,
|
protected notificationsService: NotificationsService,
|
||||||
protected http: HttpClient) {
|
protected http: HttpClient,
|
||||||
|
protected comparator: DSOUpdateComparator) {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -81,4 +81,12 @@ export class PaginatedList<T> {
|
|||||||
set last(last: string) {
|
set last(last: string) {
|
||||||
this.pageInfo.last = last;
|
this.pageInfo.last = last;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get self(): string {
|
||||||
|
return this.pageInfo.self;
|
||||||
|
}
|
||||||
|
|
||||||
|
set self(self: string) {
|
||||||
|
this.pageInfo.self = self;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -80,7 +80,7 @@ export class RequestService {
|
|||||||
this.store.pipe(select(this.entryFromUUIDSelector(uuid))),
|
this.store.pipe(select(this.entryFromUUIDSelector(uuid))),
|
||||||
this.store.pipe(
|
this.store.pipe(
|
||||||
select(this.originalUUIDFromUUIDSelector(uuid)),
|
select(this.originalUUIDFromUUIDSelector(uuid)),
|
||||||
switchMap((originalUUID) => {
|
mergeMap((originalUUID) => {
|
||||||
return this.store.pipe(select(this.entryFromUUIDSelector(originalUUID)))
|
return this.store.pipe(select(this.entryFromUUIDSelector(originalUUID)))
|
||||||
},
|
},
|
||||||
))
|
))
|
||||||
|
6
src/app/core/data/update-comparator.ts
Normal file
6
src/app/core/data/update-comparator.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
import { NormalizedObject } from '../cache/models/normalized-object.model';
|
||||||
|
import { Operation } from 'fast-json-patch/lib/core';
|
||||||
|
|
||||||
|
export interface UpdateComparator<TNormalized extends NormalizedObject> {
|
||||||
|
compare(object1: TNormalized, object2: TNormalized): Operation[];
|
||||||
|
}
|
@@ -34,14 +34,15 @@ export class DSpaceObject implements CacheableObject, ListableObject {
|
|||||||
/**
|
/**
|
||||||
* The name for this DSpaceObject
|
* The name for this DSpaceObject
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
get name(): string {
|
||||||
name: string;
|
return this.findMetadata('dc.title');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array containing all metadata of this DSpaceObject
|
* An array containing all metadata of this DSpaceObject
|
||||||
*/
|
*/
|
||||||
@autoserialize
|
@autoserialize
|
||||||
metadata: Metadatum[];
|
metadata: Metadatum[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of DSpaceObjects that are direct parents of this DSpaceObject
|
* An array of DSpaceObjects that are direct parents of this DSpaceObject
|
||||||
|
@@ -39,4 +39,7 @@ export class PageInfo {
|
|||||||
|
|
||||||
@autoserialize
|
@autoserialize
|
||||||
first: string;
|
first: string;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
self: string;
|
||||||
}
|
}
|
||||||
|
@@ -96,7 +96,6 @@ export class DsDynamicFormControlComponent extends DynamicFormControlContainerCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
static getFormControlType(model: DynamicFormControlModel): Type<DynamicFormControl> | null {
|
static getFormControlType(model: DynamicFormControlModel): Type<DynamicFormControl> | null {
|
||||||
|
|
||||||
switch (model.type) {
|
switch (model.type) {
|
||||||
|
|
||||||
case DYNAMIC_FORM_CONTROL_TYPE_ARRAY:
|
case DYNAMIC_FORM_CONTROL_TYPE_ARRAY:
|
||||||
|
@@ -51,7 +51,7 @@
|
|||||||
|
|
||||||
<div class="col text-right">
|
<div class="col text-right">
|
||||||
<button type="reset" class="btn btn-default" (click)="reset()">{{'form.cancel' | translate}}</button>
|
<button type="reset" class="btn btn-default" (click)="reset()">{{'form.cancel' | translate}}</button>
|
||||||
<button type="submit" class="btn btn-primary" (click)="onSubmit($event)"
|
<button type="submit" class="btn btn-primary" (click)="onSubmit()"
|
||||||
[disabled]="!(isValid() | async)">{{'form.submit' | translate}}
|
[disabled]="!(isValid() | async)">{{'form.submit' | translate}}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -73,7 +73,7 @@ export class FormComponent implements OnDestroy, OnInit {
|
|||||||
* An event fired when form is valid and submitted .
|
* An event fired when form is valid and submitted .
|
||||||
* Event's payload equals to the form content.
|
* Event's payload equals to the form content.
|
||||||
*/
|
*/
|
||||||
@Output() submit: EventEmitter<Observable<any>> = new EventEmitter<Observable<any>>();
|
@Output() submitForm: EventEmitter<Observable<any>> = new EventEmitter<Observable<any>>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object of FormGroup type
|
* An object of FormGroup type
|
||||||
@@ -264,7 +264,7 @@ export class FormComponent implements OnDestroy, OnInit {
|
|||||||
*/
|
*/
|
||||||
onSubmit(): void {
|
onSubmit(): void {
|
||||||
if (this.getFormGroupValidStatus()) {
|
if (this.getFormGroupValidStatus()) {
|
||||||
this.submit.emit(this.formService.getFormData(this.formId));
|
this.submitForm.emit(this.formService.getFormData(this.formId));
|
||||||
} else {
|
} else {
|
||||||
this.formService.validateAllFormFields(this.formGroup);
|
this.formService.validateAllFormFields(this.formGroup);
|
||||||
}
|
}
|
||||||
|
@@ -98,7 +98,7 @@ export class FormService {
|
|||||||
const errorKey = this.getValidatorNameFromMap(message);
|
const errorKey = this.getValidatorNameFromMap(message);
|
||||||
let errorMsg = message;
|
let errorMsg = message;
|
||||||
|
|
||||||
// if form control model has not errorMessages object, create it
|
// if form control model has no errorMessages object, create it
|
||||||
if (!model.errorMessages) {
|
if (!model.errorMessages) {
|
||||||
model.errorMessages = {};
|
model.errorMessages = {};
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user