mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
another intermediate commit
This commit is contained in:
13
angular.json
Normal file
13
angular.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"version": 1,
|
||||
"cli": {
|
||||
"defaultCollection": "@ngrx/schematics"
|
||||
},
|
||||
"projects": {
|
||||
"core": {
|
||||
"root": "",
|
||||
"projectType": "application"
|
||||
}
|
||||
}
|
||||
}
|
35
package.json
35
package.json
@@ -41,14 +41,14 @@
|
||||
"server:watch": "nodemon dist/server.js",
|
||||
"server:watch:debug": "nodemon --debug dist/server.js",
|
||||
"webpack:watch": "webpack -w --mode development",
|
||||
"watch": "yarn run build && npm-run-all -p webpack:watch server:watch",
|
||||
"watch:debug": "yarn run build && npm-run-all -p webpack:watch server:watch:debug",
|
||||
"watch": "yarn run build && npm-run-all -p webpack:watch server:watch --mode development",
|
||||
"watch:debug": "yarn run build && npm-run-all -p webpack:watch server:watch:debug --mode development",
|
||||
"predebug": "yarn run build",
|
||||
"predebug:server": "yarn run build",
|
||||
"debug": "node --debug-brk dist/server.js",
|
||||
"debug:server": "node-nightly --inspect --debug-brk dist/server.js",
|
||||
"debug:build": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js",
|
||||
"debug:build:prod": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js --env.aot --env.client --env.server -p",
|
||||
"debug:build": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js --mode development",
|
||||
"debug:build:prod": "node-nightly --inspect --debug-brk node_modules/webpack/bin/webpack.js --env.aot --env.client --env.server --mode production",
|
||||
"ci": "yarn run lint && yarn run build:aot && yarn run test:headless && npm-run-all -p -r server e2e",
|
||||
"protractor": "node node_modules/protractor/bin/protractor",
|
||||
"pree2e": "yarn run webdriver:update",
|
||||
@@ -64,6 +64,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/animations": "^6.1.4",
|
||||
"@angular/cli": "^6.1.5",
|
||||
"@angular/common": "^6.1.4",
|
||||
"@angular/core": "^6.1.4",
|
||||
"@angular/forms": "^6.1.4",
|
||||
@@ -105,6 +106,7 @@
|
||||
"methods": "1.1.2",
|
||||
"moment": "^2.22.1",
|
||||
"morgan": "1.9.0",
|
||||
"ng-mocks": "^6.2.1",
|
||||
"ng2-file-upload": "1.2.1",
|
||||
"ng2-nouislider": "^1.7.11",
|
||||
"ngx-bootstrap": "^3.0.1",
|
||||
@@ -114,7 +116,7 @@
|
||||
"nouislider": "^11.0.0",
|
||||
"pem": "1.12.3",
|
||||
"reflect-metadata": "0.1.12",
|
||||
"rxjs": "^6.2.2",
|
||||
"rxjs": "6.2.2",
|
||||
"sortablejs": "1.7.0",
|
||||
"text-mask-core": "5.0.1",
|
||||
"ts-md5": "^1.2.4",
|
||||
@@ -126,8 +128,11 @@
|
||||
"devDependencies": {
|
||||
"@angular/compiler": "^6.1.4",
|
||||
"@angular/compiler-cli": "^6.1.4",
|
||||
"@ngrx/entity": "^6.1.0",
|
||||
"@ngrx/schematics": "^6.1.0",
|
||||
"@ngrx/store-devtools": "^6.1.0",
|
||||
"@ngtools/webpack": "^6.1.5",
|
||||
"@schematics/angular": "^0.7.5",
|
||||
"@types/acorn": "^4.0.3",
|
||||
"@types/cookie-parser": "1.4.1",
|
||||
"@types/deep-freeze": "0.1.1",
|
||||
@@ -160,14 +165,14 @@
|
||||
"imports-loader": "0.8.0",
|
||||
"istanbul-instrumenter-loader": "3.0.1",
|
||||
"jasmine-core": "^3.2.1",
|
||||
"jasmine-marbles": "0.3.0",
|
||||
"jasmine-marbles": "0.3.1",
|
||||
"jasmine-spec-reporter": "4.2.1",
|
||||
"karma": "2.0.0",
|
||||
"karma": "3.0.0",
|
||||
"karma-chrome-launcher": "2.2.0",
|
||||
"karma-cli": "1.0.1",
|
||||
"karma-coverage": "1.1.1",
|
||||
"karma-coverage": "1.1.2",
|
||||
"karma-istanbul-preprocessor": "0.0.2",
|
||||
"karma-jasmine": "1.1.1",
|
||||
"karma-jasmine": "1.1.2",
|
||||
"karma-mocha-reporter": "2.2.5",
|
||||
"karma-phantomjs-launcher": "1.0.4",
|
||||
"karma-remap-coverage": "^0.1.5",
|
||||
@@ -178,12 +183,12 @@
|
||||
"ngrx-store-freeze": "^0.2.4",
|
||||
"node-sass": "^4.7.2",
|
||||
"nodemon": "^1.15.0",
|
||||
"npm-run-all": "4.1.2",
|
||||
"postcss": "^6.0.18",
|
||||
"postcss-apply": "0.8.0",
|
||||
"postcss-cli": "^5.0.0",
|
||||
"npm-run-all": "4.1.3",
|
||||
"postcss": "^7.0.2",
|
||||
"postcss-apply": "0.11.0",
|
||||
"postcss-cli": "^6.0.0",
|
||||
"postcss-cssnext": "3.1.0",
|
||||
"postcss-loader": "^2.1.0",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"postcss-responsive-type": "1.0.0",
|
||||
"postcss-smart-import": "0.7.6",
|
||||
"protractor": "^5.3.0",
|
||||
@@ -196,7 +201,7 @@
|
||||
"rollup-plugin-node-globals": "1.2.1",
|
||||
"rollup-plugin-node-resolve": "^3.0.3",
|
||||
"rollup-plugin-terser": "^2.0.2",
|
||||
"sass-loader": "6.0.6",
|
||||
"sass-loader": "7.1.0",
|
||||
"script-ext-html-webpack-plugin": "2.0.1",
|
||||
"source-map": "0.7.3",
|
||||
"source-map-loader": "0.2.4",
|
||||
|
@@ -4,7 +4,6 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import 'rxjs/add/observable/of';
|
||||
|
||||
import { LoginPageComponent } from './login-page.component';
|
||||
|
||||
|
@@ -1,4 +1,3 @@
|
||||
import 'rxjs/add/observable/of';
|
||||
import { PaginatedSearchOptions } from './paginated-search-options.model';
|
||||
import { SearchOptions } from './search-options.model';
|
||||
import { SearchFilter } from './search-filter.model';
|
||||
|
@@ -3,7 +3,6 @@ import { SearchSidebarService } from './search-sidebar.service';
|
||||
import { AppState } from '../../app.reducer';
|
||||
import { async, TestBed } from '@angular/core/testing';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import 'rxjs/add/observable/of';
|
||||
import { SearchSidebarCollapseAction, SearchSidebarExpandAction } from './search-sidebar.actions';
|
||||
import { HostWindowService } from '../../shared/host-window.service';
|
||||
|
||||
@@ -13,7 +12,7 @@ describe('SearchSidebarService', () => {
|
||||
/* tslint:disable:no-empty */
|
||||
dispatch: {},
|
||||
/* tslint:enable:no-empty */
|
||||
select: observableOf(true)
|
||||
pipe: observableOf(true)
|
||||
});
|
||||
const windowService = jasmine.createSpyObj('hostWindowService',
|
||||
{
|
||||
|
@@ -4,7 +4,6 @@ import { ActivatedRoute, Router } from '@angular/router';
|
||||
|
||||
import { Store, StoreModule } from '@ngrx/store';
|
||||
import { REQUEST } from '@nguniversal/express-engine/tokens';
|
||||
import 'rxjs/add/observable/of';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
|
||||
import { authReducer, AuthState } from './auth.reducer';
|
||||
@@ -27,7 +26,7 @@ describe('AuthService test', () => {
|
||||
|
||||
const mockStore: Store<AuthState> = jasmine.createSpyObj('store', {
|
||||
dispatch: {},
|
||||
select: observableOf(true)
|
||||
pipe: observableOf(true)
|
||||
});
|
||||
let authService: AuthService;
|
||||
const authRequest = new AuthRequestServiceStub();
|
||||
|
31
src/app/core/cache/object-cache.service.spec.ts
vendored
31
src/app/core/cache/object-cache.service.spec.ts
vendored
@@ -7,6 +7,7 @@ import { CoreState } from '../core.reducers';
|
||||
import { ResourceType } from '../shared/resource-type';
|
||||
import { NormalizedItem } from './models/normalized-item.model';
|
||||
import { first } from 'rxjs/operators';
|
||||
import * as ngrx from '@ngrx/store';
|
||||
|
||||
describe('ObjectCacheService', () => {
|
||||
let service: ObjectCacheService;
|
||||
@@ -52,7 +53,11 @@ describe('ObjectCacheService', () => {
|
||||
|
||||
describe('getBySelfLink', () => {
|
||||
it('should return an observable of the cached object with the specified self link and type', () => {
|
||||
spyOn(store, 'select').and.returnValue(observableOf(cacheEntry));
|
||||
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||
return () => {
|
||||
return () => observableOf(cacheEntry);
|
||||
};
|
||||
});
|
||||
|
||||
// due to the implementation of spyOn above, this subscribe will be synchronous
|
||||
service.getBySelfLink(selfLink).pipe(first()).subscribe((o) => {
|
||||
@@ -64,7 +69,11 @@ describe('ObjectCacheService', () => {
|
||||
});
|
||||
|
||||
it('should not return a cached object that has exceeded its time to live', () => {
|
||||
spyOn(store, 'select').and.returnValue(observableOf(invalidCacheEntry));
|
||||
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||
return () => {
|
||||
return () => observableOf(invalidCacheEntry);
|
||||
};
|
||||
});
|
||||
|
||||
let getObsHasFired = false;
|
||||
const subscription = service.getBySelfLink(selfLink).subscribe((o) => getObsHasFired = true);
|
||||
@@ -88,19 +97,31 @@ describe('ObjectCacheService', () => {
|
||||
|
||||
describe('has', () => {
|
||||
it('should return true if the object with the supplied self link is cached and still valid', () => {
|
||||
spyOn(store, 'select').and.returnValue(observableOf(cacheEntry));
|
||||
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||
return () => {
|
||||
return () => observableOf(cacheEntry);
|
||||
};
|
||||
});
|
||||
|
||||
expect(service.hasBySelfLink(selfLink)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false if the object with the supplied self link isn't cached", () => {
|
||||
spyOn(store, 'select').and.returnValue(observableOf(undefined));
|
||||
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||
return () => {
|
||||
return () => observableOf(undefined);
|
||||
};
|
||||
});
|
||||
|
||||
expect(service.hasBySelfLink(selfLink)).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if the object with the supplied self link is cached but has exceeded its time to live', () => {
|
||||
spyOn(store, 'select').and.returnValue(observableOf(invalidCacheEntry));
|
||||
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||
return () => {
|
||||
return () => observableOf(invalidCacheEntry);
|
||||
};
|
||||
});
|
||||
|
||||
expect(service.hasBySelfLink(selfLink)).toBe(false);
|
||||
});
|
||||
|
@@ -6,6 +6,8 @@ import { CoreState } from '../core.reducers';
|
||||
import { RestResponse } from './response-cache.models';
|
||||
import { ResponseCacheEntry } from './response-cache.reducer';
|
||||
import { first } from 'rxjs/operators';
|
||||
import * as ngrx from '@ngrx/store'
|
||||
import { cold } from 'jasmine-marbles';
|
||||
|
||||
describe('ResponseCacheService', () => {
|
||||
let service: ResponseCacheService;
|
||||
@@ -41,10 +43,11 @@ describe('ResponseCacheService', () => {
|
||||
|
||||
describe('get', () => {
|
||||
it('should return an observable of the cached request with the specified key', () => {
|
||||
spyOn(store, 'select').and.callFake((...args: any[]) => {
|
||||
return observableOf(validCacheEntry(keys[1]));
|
||||
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||
return () => {
|
||||
return () => observableOf(validCacheEntry(keys[1]));
|
||||
};
|
||||
});
|
||||
|
||||
let testObj: ResponseCacheEntry;
|
||||
service.get(keys[1]).pipe(first()).subscribe((entry) => {
|
||||
testObj = entry;
|
||||
@@ -53,8 +56,10 @@ describe('ResponseCacheService', () => {
|
||||
});
|
||||
|
||||
it('should not return a cached request that has exceeded its time to live', () => {
|
||||
spyOn(store, 'select').and.callFake((...args: any[]) => {
|
||||
return observableOf(invalidCacheEntry(keys[1]));
|
||||
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||
return () => {
|
||||
return () => observableOf(invalidCacheEntry(keys[1]));
|
||||
};
|
||||
});
|
||||
|
||||
let getObsHasFired = false;
|
||||
@@ -66,17 +71,29 @@ describe('ResponseCacheService', () => {
|
||||
|
||||
describe('has', () => {
|
||||
it('should return true if the request with the supplied key is cached and still valid', () => {
|
||||
spyOn(store, 'select').and.returnValue(observableOf(validCacheEntry(keys[1])));
|
||||
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||
return () => {
|
||||
return () => observableOf(validCacheEntry(keys[1]));
|
||||
};
|
||||
});
|
||||
expect(service.has(keys[1])).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false if the request with the supplied key isn\'t cached', () => {
|
||||
spyOn(store, 'select').and.returnValue(observableOf(undefined));
|
||||
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||
return () => {
|
||||
return () => observableOf(undefined);
|
||||
};
|
||||
});
|
||||
expect(service.has(keys[1])).toBe(false);
|
||||
});
|
||||
|
||||
it('should return false if the request with the supplied key is cached but has exceeded its time to live', () => {
|
||||
spyOn(store, 'select').and.returnValue(observableOf(invalidCacheEntry(keys[1])));
|
||||
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||
return () => {
|
||||
return () => observableOf(invalidCacheEntry(keys[1]));
|
||||
};
|
||||
});
|
||||
expect(service.has(keys[1])).toBe(false);
|
||||
});
|
||||
});
|
||||
|
@@ -56,11 +56,11 @@ describe('ConfigService', () => {
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
scheduler = getTestScheduler();
|
||||
responseCache = initMockResponseCacheService(true);
|
||||
requestService = getMockRequestService();
|
||||
service = initTestService();
|
||||
scheduler = getTestScheduler();
|
||||
halService = new HALEndpointServiceStub(configEndpoint);
|
||||
service = initTestService();
|
||||
});
|
||||
|
||||
describe('getConfigByHref', () => {
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Observable, of as observableOf, throwError as observableThrowError } from 'rxjs';
|
||||
import { Observable, of as observableOf, throwError as observableThrowError, merge as observableMerge } from 'rxjs';
|
||||
import { distinctUntilChanged, filter, map, mergeMap, tap } from 'rxjs/operators';
|
||||
import { RequestService } from '../data/request.service';
|
||||
import { ResponseCacheService } from '../cache/response-cache.service';
|
||||
@@ -18,18 +18,17 @@ export abstract class ConfigService {
|
||||
protected abstract halService: HALEndpointService;
|
||||
|
||||
protected getConfig(request: RestRequest): Observable<ConfigData> {
|
||||
return this.responseCache.get(request.href).pipe(
|
||||
map((entry: ResponseCacheEntry) => entry.response),
|
||||
mergeMap((response) => {
|
||||
if (response.isSuccessful && isNotEmpty(response) && isNotEmpty((response as ConfigSuccessResponse).configDefinition)) {
|
||||
const configResponse = response as ConfigSuccessResponse;
|
||||
return observableOf(new ConfigData(configResponse.pageInfo, configResponse.configDefinition));
|
||||
} else if (!response.isSuccessful) {
|
||||
return observableThrowError(new Error(`Couldn't retrieve the config`));
|
||||
}
|
||||
}),
|
||||
distinctUntilChanged()
|
||||
const responses = this.responseCache.get(request.href).pipe(map((entry: ResponseCacheEntry) => entry.response));
|
||||
const errorResponses = responses.pipe(
|
||||
filter((response) => !response.isSuccessful),
|
||||
mergeMap(() => observableThrowError(new Error(`Couldn't retrieve the config`)))
|
||||
);
|
||||
const successResponses = responses.pipe(
|
||||
filter((response) => response.isSuccessful && isNotEmpty(response) && isNotEmpty((response as ConfigSuccessResponse).configDefinition)),
|
||||
map((response: ConfigSuccessResponse) => new ConfigData(response.pageInfo, response.configDefinition))
|
||||
);
|
||||
return observableMerge(errorResponses, successResponses);
|
||||
|
||||
}
|
||||
|
||||
protected getConfigByNameHref(endpoint, resourceName): string {
|
||||
@@ -73,7 +72,7 @@ export abstract class ConfigService {
|
||||
map((endpointURL: string) => new ConfigRequest(this.requestService.generateRequestId(), endpointURL)),
|
||||
tap((request: RestRequest) => this.requestService.configure(request)),
|
||||
mergeMap((request: RestRequest) => this.getConfig(request)),
|
||||
distinctUntilChanged(),);
|
||||
distinctUntilChanged());
|
||||
}
|
||||
|
||||
public getConfigByHref(href: string): Observable<ConfigData> {
|
||||
@@ -91,10 +90,11 @@ export abstract class ConfigService {
|
||||
map((endpointURL: string) => new ConfigRequest(this.requestService.generateRequestId(), endpointURL)),
|
||||
tap((request: RestRequest) => this.requestService.configure(request)),
|
||||
mergeMap((request: RestRequest) => this.getConfig(request)),
|
||||
distinctUntilChanged(),);
|
||||
distinctUntilChanged());
|
||||
}
|
||||
|
||||
public getConfigBySearch(options: FindAllOptions = {}): Observable<ConfigData> {
|
||||
console.log(this.halService.getEndpoint(this.linkPath));
|
||||
return this.halService.getEndpoint(this.linkPath).pipe(
|
||||
map((endpoint: string) => this.getConfigSearchHref(endpoint, options)),
|
||||
filter((href: string) => isNotEmpty(href)),
|
||||
@@ -102,7 +102,7 @@ export abstract class ConfigService {
|
||||
map((endpointURL: string) => new ConfigRequest(this.requestService.generateRequestId(), endpointURL)),
|
||||
tap((request: RestRequest) => this.requestService.configure(request)),
|
||||
mergeMap((request: RestRequest) => this.getConfig(request)),
|
||||
distinctUntilChanged(),);
|
||||
distinctUntilChanged());
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { Observable, throwError as observableThrowError } from 'rxjs';
|
||||
import { Observable, throwError as observableThrowError, merge as observableMerge } from 'rxjs';
|
||||
import { distinctUntilChanged, filter, first, map, mergeMap, tap } from 'rxjs/operators';
|
||||
import { isEmpty, isNotEmpty } from '../../shared/empty.util';
|
||||
import { NormalizedCommunity } from '../cache/models/normalized-community.model';
|
||||
@@ -10,6 +10,7 @@ import { DataService } from './data.service';
|
||||
import { FindByIDRequest } from './request.models';
|
||||
import { NormalizedObject } from '../cache/models/normalized-object.model';
|
||||
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||
import { DSOSuccessResponse } from '../cache/response-cache.models';
|
||||
|
||||
export abstract class ComColDataService<TNormalized extends NormalizedObject, TDomain> extends DataService<TNormalized, TDomain> {
|
||||
protected abstract cds: CommunityDataService;
|
||||
@@ -38,23 +39,39 @@ export abstract class ComColDataService<TNormalized extends NormalizedObject, TD
|
||||
this.requestService.configure(request);
|
||||
}),);
|
||||
|
||||
return scopeCommunityHrefObs.pipe(
|
||||
// return scopeCommunityHrefObs.pipe(
|
||||
// mergeMap((href: string) => this.responseCache.get(href)),
|
||||
// map((entry: ResponseCacheEntry) => entry.response),
|
||||
// mergeMap((response) => {
|
||||
// if (response.isSuccessful) {
|
||||
// const community$: Observable<NormalizedCommunity> = this.objectCache.getByUUID(scopeID);
|
||||
// return community$.pipe(
|
||||
// map((community) => community._links[this.linkPath]),
|
||||
// filter((href) => isNotEmpty(href)),
|
||||
// distinctUntilChanged()
|
||||
// );
|
||||
// } else if (!response.isSuccessful) {
|
||||
// return observableThrowError(new Error(`The Community with scope ${scopeID} couldn't be retrieved`))
|
||||
// }
|
||||
// }),
|
||||
// distinctUntilChanged()
|
||||
// );
|
||||
const responses = scopeCommunityHrefObs.pipe(
|
||||
mergeMap((href: string) => this.responseCache.get(href)),
|
||||
map((entry: ResponseCacheEntry) => entry.response),
|
||||
mergeMap((response) => {
|
||||
if (response.isSuccessful) {
|
||||
const community$: Observable<NormalizedCommunity> = this.objectCache.getByUUID(scopeID);
|
||||
return community$.pipe(
|
||||
map((community) => community._links[this.linkPath]),
|
||||
filter((href) => isNotEmpty(href)),
|
||||
distinctUntilChanged()
|
||||
);
|
||||
} else if (!response.isSuccessful) {
|
||||
return observableThrowError(new Error(`The Community with scope ${scopeID} couldn't be retrieved`))
|
||||
}
|
||||
}),
|
||||
distinctUntilChanged()
|
||||
map((entry: ResponseCacheEntry) => entry.response));
|
||||
const errorResponses = responses.pipe(
|
||||
filter((response) => !response.isSuccessful),
|
||||
mergeMap(() => observableThrowError(new Error(`The Community with scope ${scopeID} couldn't be retrieved`)))
|
||||
);
|
||||
const successResponses = responses.pipe(
|
||||
filter((response) => response.isSuccessful),
|
||||
mergeMap(() => this.objectCache.getByUUID(scopeID)),
|
||||
map((nc: NormalizedCommunity) => nc._links[this.linkPath]),
|
||||
filter((href) => isNotEmpty(href))
|
||||
);
|
||||
|
||||
|
||||
return observableMerge(errorResponses, successResponses).pipe(distinctUntilChanged());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -1,15 +1,14 @@
|
||||
import { Store } from '@ngrx/store';
|
||||
import { cold, hot } from 'jasmine-marbles';
|
||||
import { cold, getTestScheduler, hot } from 'jasmine-marbles';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { getMockObjectCacheService } from '../../shared/mocks/mock-object-cache.service';
|
||||
import { getMockResponseCacheService } from '../../shared/mocks/mock-response-cache.service';
|
||||
import { getMockStore } from '../../shared/mocks/mock-store';
|
||||
import { defaultUUID, getMockUUIDService } from '../../shared/mocks/mock-uuid.service';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { ResponseCacheService } from '../cache/response-cache.service';
|
||||
import { CoreState } from '../core.reducers';
|
||||
import { UUIDService } from '../shared/uuid.service';
|
||||
import { RequestConfigureAction, RequestExecuteAction } from './request.actions';
|
||||
import * as ngrx from '@ngrx/store';
|
||||
import {
|
||||
DeleteRequest,
|
||||
GetRequest,
|
||||
@@ -21,8 +20,12 @@ import {
|
||||
RestRequest
|
||||
} from './request.models';
|
||||
import { RequestService } from './request.service';
|
||||
import { ActionsSubject, Store } from '@ngrx/store';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
|
||||
|
||||
describe('RequestService', () => {
|
||||
let scheduler: TestScheduler;
|
||||
let service: RequestService;
|
||||
let serviceAsAny: any;
|
||||
let objectCache: ObjectCacheService;
|
||||
@@ -39,8 +42,10 @@ describe('RequestService', () => {
|
||||
const testOptionsRequest = new OptionsRequest(testUUID, testHref);
|
||||
const testHeadRequest = new HeadRequest(testUUID, testHref);
|
||||
const testPatchRequest = new PatchRequest(testUUID, testHref);
|
||||
|
||||
let selectSpy;
|
||||
beforeEach(() => {
|
||||
scheduler = getTestScheduler();
|
||||
|
||||
objectCache = getMockObjectCacheService();
|
||||
(objectCache.hasBySelfLink as any).and.returnValue(false);
|
||||
|
||||
@@ -50,8 +55,13 @@ describe('RequestService', () => {
|
||||
|
||||
uuidService = getMockUUIDService();
|
||||
|
||||
store = getMockStore<CoreState>();
|
||||
(store.pipe as any).and.returnValue(observableOf(undefined));
|
||||
store = new Store<CoreState>(new BehaviorSubject({}), new ActionsSubject(), null);
|
||||
selectSpy = spyOnProperty(ngrx, 'select')
|
||||
selectSpy.and.callFake(() => {
|
||||
return () => {
|
||||
return () => cold('a', { a: undefined });
|
||||
};
|
||||
});
|
||||
|
||||
service = new RequestService(
|
||||
objectCache,
|
||||
@@ -134,11 +144,15 @@ describe('RequestService', () => {
|
||||
describe('getByUUID', () => {
|
||||
describe('if the request with the specified UUID exists in the store', () => {
|
||||
beforeEach(() => {
|
||||
(store.pipe as any).and.returnValues(hot('a', {
|
||||
a: {
|
||||
completed: true
|
||||
}
|
||||
}));
|
||||
selectSpy.and.callFake(() => {
|
||||
return () => {
|
||||
return () => hot('a', {
|
||||
a: {
|
||||
completed: true
|
||||
}
|
||||
});
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an Observable of the RequestEntry', () => {
|
||||
@@ -155,9 +169,11 @@ describe('RequestService', () => {
|
||||
|
||||
describe('if the request with the specified UUID doesn\'t exist in the store', () => {
|
||||
beforeEach(() => {
|
||||
(store.pipe as any).and.returnValues(hot('a', {
|
||||
a: undefined
|
||||
}));
|
||||
selectSpy.and.callFake(() => {
|
||||
return () => {
|
||||
return () => hot('a', { a: undefined });
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an Observable of undefined', () => {
|
||||
@@ -175,9 +191,11 @@ describe('RequestService', () => {
|
||||
describe('getByHref', () => {
|
||||
describe('when the request with the specified href exists in the store', () => {
|
||||
beforeEach(() => {
|
||||
(store.pipe as any).and.returnValues(hot('a', {
|
||||
a: testUUID
|
||||
}));
|
||||
selectSpy.and.callFake(() => {
|
||||
return () => {
|
||||
return () => hot('a', { a: testUUID });
|
||||
};
|
||||
});
|
||||
spyOn(service, 'getByUUID').and.returnValue(cold('b', {
|
||||
b: {
|
||||
completed: true
|
||||
@@ -199,9 +217,11 @@ describe('RequestService', () => {
|
||||
|
||||
describe('when the request with the specified href doesn\'t exist in the store', () => {
|
||||
beforeEach(() => {
|
||||
(store.pipe as any).and.returnValues(hot('a', {
|
||||
a: undefined
|
||||
}));
|
||||
selectSpy.and.callFake(() => {
|
||||
return () => {
|
||||
return () => hot('a', { a: undefined });
|
||||
};
|
||||
});
|
||||
spyOn(service, 'getByUUID').and.returnValue(cold('b', {
|
||||
b: undefined
|
||||
}));
|
||||
@@ -241,7 +261,8 @@ describe('RequestService', () => {
|
||||
});
|
||||
|
||||
it('should dispatch the request', () => {
|
||||
service.configure(request);
|
||||
scheduler.schedule(() => service.configure(request));
|
||||
scheduler.flush();
|
||||
expect(serviceAsAny.dispatchRequest).toHaveBeenCalledWith(request);
|
||||
});
|
||||
});
|
||||
@@ -398,6 +419,10 @@ describe('RequestService', () => {
|
||||
});
|
||||
|
||||
describe('dispatchRequest', () => {
|
||||
beforeEach(() => {
|
||||
spyOn(store, 'dispatch');
|
||||
});
|
||||
|
||||
it('should dispatch a RequestConfigureAction', () => {
|
||||
const request = testGetRequest;
|
||||
serviceAsAny.dispatchRequest(request);
|
||||
@@ -428,7 +453,11 @@ describe('RequestService', () => {
|
||||
|
||||
describe('when the request is added to the store', () => {
|
||||
it('should stop tracking the request', () => {
|
||||
(store.pipe as any).and.returnValues(observableOf({ request }));
|
||||
selectSpy.and.callFake(() => {
|
||||
return () => {
|
||||
return () => observableOf({ request });
|
||||
};
|
||||
});
|
||||
serviceAsAny.trackRequestsOnTheirWayToTheStore(request);
|
||||
expect(serviceAsAny.requestsOnTheirWayToTheStore.includes(request.href)).toBeFalsy();
|
||||
});
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import { Observable } from 'rxjs';
|
||||
import { filter, first, map, mergeMap, take } from 'rxjs/operators';
|
||||
import { Observable, merge as observableMerge } from 'rxjs';
|
||||
import { filter, first, map, mergeMap, partition, take } from 'rxjs/operators';
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { MemoizedSelector, select, Store } from '@ngrx/store';
|
||||
import { hasValue } from '../../shared/empty.util';
|
||||
import { CacheableObject } from '../cache/object-cache.reducer';
|
||||
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||
import { DSOSuccessResponse } from '../cache/response-cache.models';
|
||||
import { DSOSuccessResponse, RestResponse } from '../cache/response-cache.models';
|
||||
import { ResponseCacheEntry } from '../cache/response-cache.reducer';
|
||||
import { ResponseCacheService } from '../cache/response-cache.service';
|
||||
import { coreSelector, CoreState } from '../core.reducers';
|
||||
@@ -82,17 +82,21 @@ export class RequestService {
|
||||
private isCachedOrPending(request: GetRequest) {
|
||||
let isCached = this.objectCache.hasBySelfLink(request.href);
|
||||
if (!isCached && this.responseCache.has(request.href)) {
|
||||
this.responseCache.get(request.href).pipe(
|
||||
first(),
|
||||
map((entry: ResponseCacheEntry) => {
|
||||
const response = entry.response;
|
||||
if (response.isSuccessful && hasValue((response as DSOSuccessResponse).resourceSelfLinks)) {
|
||||
return (response as DSOSuccessResponse).resourceSelfLinks.every((selfLink) => this.objectCache.hasBySelfLink(selfLink))
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
})
|
||||
).subscribe((c) => isCached = c);
|
||||
const responses = this.responseCache.get(request.href).pipe(
|
||||
take(1),
|
||||
map((entry: ResponseCacheEntry) => entry.response)
|
||||
);
|
||||
|
||||
const errorResponses = responses.pipe(filter((response) => !response.isSuccessful), map(() => true)); // TODO add a configurable number of retries in case of an error.
|
||||
const dsoSuccessResponses = responses.pipe(
|
||||
filter((response) => response.isSuccessful && hasValue((response as DSOSuccessResponse).resourceSelfLinks)),
|
||||
map((response: DSOSuccessResponse) => response.resourceSelfLinks),
|
||||
map((resourceSelfLinks: string[]) => resourceSelfLinks
|
||||
.every((selfLink) => this.objectCache.hasBySelfLink(selfLink))
|
||||
));
|
||||
const otherSuccessResponses = responses.pipe(filter((response) => response.isSuccessful && !hasValue((response as DSOSuccessResponse).resourceSelfLinks)), map(() => true));
|
||||
|
||||
observableMerge(errorResponses, otherSuccessResponses, dsoSuccessResponses).subscribe((c) => isCached = c);
|
||||
}
|
||||
const isPending = this.isPending(request);
|
||||
return isCached || isPending;
|
||||
|
37
src/app/core/data/test.spec.ts
Normal file
37
src/app/core/data/test.spec.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { select } from '@ngrx/store';
|
||||
import * as ngrx from '@ngrx/store';
|
||||
import { cold, hot } from 'jasmine-marbles';
|
||||
import { Observable } from 'rxjs';
|
||||
import { count, take } from 'rxjs/operators';
|
||||
|
||||
class TestClass {
|
||||
selectSomething(input$: Observable<any>) {
|
||||
return input$.pipe(
|
||||
select('something'),
|
||||
take(1)
|
||||
)
|
||||
}
|
||||
}
|
||||
describe('mockSelect', () => {
|
||||
let testClass;
|
||||
beforeEach(() => {
|
||||
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||
return () => {
|
||||
return () => cold('a', { a: 'bingo!' });
|
||||
};
|
||||
});
|
||||
|
||||
testClass = new TestClass();
|
||||
});
|
||||
|
||||
it('should mock select', () => {
|
||||
const input$ = hot('a', { a: '' });
|
||||
const expected$ = hot('(b|)', { b: 'bingo!' });
|
||||
const result$ = testClass.selectSomething(input$);
|
||||
result$.pipe(count()).subscribe((t) => console.log('resykts', t));
|
||||
expected$.pipe(count()).subscribe((t) => console.log('expected', t));
|
||||
result$.subscribe((v) => console.log('result$', v));
|
||||
expected$.subscribe((v) => console.log('expected$', v));
|
||||
expect(result$).toBeObservable(expected$)
|
||||
});
|
||||
})
|
@@ -19,7 +19,7 @@ import { HostWindowServiceStub } from '../shared/testing/host-window-service-stu
|
||||
import { RouterStub } from '../shared/testing/router-stub';
|
||||
import { Router } from '@angular/router';
|
||||
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
|
||||
|
||||
import * as ngrx from '@ngrx/store';
|
||||
let comp: HeaderComponent;
|
||||
let fixture: ComponentFixture<HeaderComponent>;
|
||||
let store: Store<HeaderState>;
|
||||
@@ -72,7 +72,11 @@ describe('HeaderComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
menu = fixture.debugElement.query(By.css('#collapsingNav')).nativeElement;
|
||||
spyOn(store, 'select').and.returnValue(observableOf({ navCollapsed: true }));
|
||||
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||
return () => {
|
||||
return () => observableOf({ navCollapsed: true })
|
||||
};
|
||||
});
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
@@ -87,7 +91,11 @@ describe('HeaderComponent', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
menu = fixture.debugElement.query(By.css('#collapsingNav')).nativeElement;
|
||||
spyOn(store, 'select').and.returnValue(observableOf(false));
|
||||
spyOnProperty(ngrx, 'select').and.callFake(() => {
|
||||
return () => {
|
||||
return () => observableOf(false)
|
||||
};
|
||||
});
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
|
@@ -1,7 +1,6 @@
|
||||
// Load the implementations that should be tested
|
||||
import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { async, ComponentFixture, fakeAsync, inject, TestBed, tick, } from '@angular/core/testing';
|
||||
import 'rxjs/add/observable/of';
|
||||
|
||||
import { Chips } from './models/chips.model';
|
||||
import { UploaderService } from '../uploader/uploader.service';
|
||||
|
@@ -12,429 +12,7 @@
|
||||
<div [ngClass]="{'form-row': model.hasLanguages }">
|
||||
<div [ngClass]="getClass('grid', 'control')">
|
||||
|
||||
<ng-container [ngSwitch]="type">
|
||||
|
||||
<!-- FORM ARRAY ------------------------------------------------------------------------------------------->
|
||||
<div *ngSwitchCase="1"
|
||||
[dynamicId]="bindId && model.id"
|
||||
[formArrayName]="model.id"
|
||||
[ngClass]="getClass('element', 'control')">
|
||||
|
||||
<div *ngFor="let groupModel of model.groups; let idx = index" role="group"
|
||||
[formGroupName]="idx" [ngClass]="[getClass('element', 'group'), getClass('grid', 'group')]">
|
||||
|
||||
<ds-dynamic-form-control *ngFor="let _model of groupModel.group"
|
||||
[bindId]="false"
|
||||
[formId]="formId"
|
||||
[context]="groupModel"
|
||||
[group]="control.at(idx)"
|
||||
[hasErrorMessaging]="_model.hasErrorMessages"
|
||||
[hidden]="_model.hidden"
|
||||
[layout]="layout"
|
||||
[model]="_model"
|
||||
[templates]="templateList"
|
||||
[ngClass]="[getClass('element', 'host', _model), getClass('grid', 'host', _model)]"
|
||||
(dfBlur)="onBlur($event)"
|
||||
(dfChange)="onValueChange($event)"
|
||||
(dfFocus)="onFocus($event)"></ds-dynamic-form-control>
|
||||
|
||||
<ng-container *ngTemplateOutlet="templates[2]?.templateRef; context: groupModel"></ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- CALENDAR --------------------------------------------------------------------------------------------->
|
||||
<ngb-datepicker *ngSwitchCase="2"
|
||||
[displayMonths]="getAdditional('displayMonths', 1)"
|
||||
[dynamicId]="bindId && model.id"
|
||||
[firstDayOfWeek]="getAdditional('firstDayOfWeek', 1)"
|
||||
[formControlName]="model.id"
|
||||
[maxDate]="model.max"
|
||||
[minDate]="model.min"
|
||||
[navigation]="getAdditional('navigation', 'select')"
|
||||
[ngClass]="getClass('element', 'control')"
|
||||
[outsideDays]="getAdditional('outsideDays', 'visible')"
|
||||
[showWeekdays]="getAdditional('showWeekdays', true)"
|
||||
[showWeekNumbers]="getAdditional('showWeekNumbers', false)"
|
||||
[startDate]="model.focusedDate"
|
||||
(select)="onValueChange($event)"></ngb-datepicker>
|
||||
|
||||
<!-- CHECKBOX --------------------------------------------------------------------------------------------->
|
||||
<div *ngSwitchCase="3" class="custom-control custom-checkbox" [class.disabled]="model.disabled">
|
||||
<input type="checkbox" class="custom-control-input"
|
||||
[checked]="model.checked"
|
||||
[class.is-invalid]="showErrorMessages"
|
||||
[id]="bindId && model.id"
|
||||
[dynamicId]="bindId && model.id"
|
||||
[formControlName]="model.id"
|
||||
[indeterminate]="model.indeterminate"
|
||||
[name]="model.name"
|
||||
[ngClass]="getClass('element', 'control')"
|
||||
[required]="model.required"
|
||||
[tabindex]="model.tabIndex"
|
||||
[value]="model.value"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)" >
|
||||
<label class="custom-control-label" [for]="bindId && model.id">
|
||||
<span [innerHTML]="model.label"
|
||||
[ngClass]="[getClass('element', 'label'), getClass('grid', 'label')]">
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<!-- CHECKBOX GROUP --------------------------------------------------------------------------------------->
|
||||
<div *ngSwitchCase="4" class="btn-group btn-group-toggle" data-toggle="buttons"
|
||||
[dynamicId]="bindId && model.id"
|
||||
[formGroupName]="model.id"
|
||||
[ngClass]="getClass('element', 'control')">
|
||||
<label *ngFor="let checkboxModel of model.group" ngbButtonLabel
|
||||
[hidden]="checkboxModel.hidden"
|
||||
[ngClass]="getClass('element', 'control', checkboxModel)">
|
||||
<input type="checkbox" ngbButton
|
||||
[checked]="checkboxModel.checked"
|
||||
[id]="bindId && checkboxModel.id"
|
||||
[dynamicId]="bindId && checkboxModel.id"
|
||||
[formControlName]="checkboxModel.id"
|
||||
[indeterminate]="checkboxModel.indeterminate"
|
||||
[name]="checkboxModel.name"
|
||||
[required]="checkboxModel.required"
|
||||
[tabindex]="checkboxModel.tabIndex"
|
||||
[value]="checkboxModel.value"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"/>
|
||||
<span [ngClass]="getClass('element', 'label', checkboxModel)"
|
||||
[innerHTML]="checkboxModel.label"></span></label>
|
||||
</div>
|
||||
|
||||
<!-- DATEPICKER ------------------------------------------------------------------------------------------->
|
||||
<div *ngSwitchCase="5" class="input-group">
|
||||
<input ngbDatepicker class="form-control" #datepicker="ngbDatepicker"
|
||||
[class.is-invalid]="showErrorMessages"
|
||||
[displayMonths]="getAdditional('displayMonths', 1)"
|
||||
[dynamicId]="bindId && model.id"
|
||||
[firstDayOfWeek]="getAdditional('firstDayOfWeek', 1)"
|
||||
[formControlName]="model.id"
|
||||
[maxDate]="model.max"
|
||||
[minDate]="model.min"
|
||||
[name]="model.name"
|
||||
[navigation]="getAdditional('navigation', 'select')"
|
||||
[ngClass]="getClass('element', 'control')"
|
||||
[outsideDays]="getAdditional('outsideDays', 'visible')"
|
||||
[placeholder]="(model.placeholder | translate)"
|
||||
[placement]="getAdditional('placement', 'bottom-left')"
|
||||
[showWeekdays]="getAdditional('showWeekdays', true)"
|
||||
[showWeekNumbers]="getAdditional('showWeekNumbers', false)"
|
||||
[startDate]="model.focusedDate"
|
||||
(dateSelect)="onValueChange($event)"
|
||||
(blur)="onBlur($event)"
|
||||
(focus)="onFocus($event)">
|
||||
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-outline-secondary"
|
||||
type="button"
|
||||
[class.disabled]="model.disabled"
|
||||
[disabled]="model.disabled"
|
||||
(click)="datepicker.toggle()">
|
||||
<i *ngIf="model.toggleIcon" class="{{model.toggleIcon}}" aria-hidden="true"></i>
|
||||
<span *ngIf="model.toggleLabel">{{ model.toggleLabel }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- FORM GROUP ------------------------------------------------------------------------------------------->
|
||||
<div *ngSwitchCase="6" role="group"
|
||||
[dynamicId]="bindId && model.id"
|
||||
[formGroupName]="model.id"
|
||||
[ngClass]="getClass('element','control')">
|
||||
|
||||
<ds-dynamic-form-control *ngFor="let _model of model.group"
|
||||
[asBootstrapFormGroup]="true"
|
||||
[formId]="formId"
|
||||
[group]="control"
|
||||
[hasErrorMessaging]="_model.hasErrorMessages"
|
||||
[hidden]="_model.hidden"
|
||||
[layout]="layout"
|
||||
[model]="_model"
|
||||
[templates]="templateList"
|
||||
[ngClass]="[getClass('element', 'host', _model), getClass('grid', 'host', _model)]"
|
||||
(dfBlur)="onBlur($event)"
|
||||
(dfChange)="onValueChange($event)"
|
||||
(dfFocus)="onFocus($event)"></ds-dynamic-form-control>
|
||||
</div>
|
||||
|
||||
<!-- INPUT ------------------------------------------------------------------------------------------------>
|
||||
<div *ngSwitchCase="7" [class.input-group]="model.prefix || model.suffix">
|
||||
|
||||
<div *ngIf="model.prefix" class="input-group-prepend">
|
||||
<span class="input-group-text" [innerHTML]="model.prefix"></span>
|
||||
</div>
|
||||
|
||||
<ng-container *ngTemplateOutlet="inputTemplate;
|
||||
context:{bindId: bindId, model: model, showErrorMessages: showErrorMessages}">
|
||||
|
||||
</ng-container>
|
||||
|
||||
<div *ngIf="model.suffix" class="input-group-append">
|
||||
<span class="input-group-text" [innerHTML]="model.suffix"></span>
|
||||
</div>
|
||||
|
||||
<datalist *ngIf="model.list" [id]="model.listId">
|
||||
<option *ngFor="let option of model.list" [value]="option">
|
||||
</datalist>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- RADIO GROUP ------------------------------------------------------------------------------------------>
|
||||
<div *ngSwitchCase="8" ngbRadioGroup class="btn-group btn-group-toggle" role="radiogroup"
|
||||
[dynamicId]="bindId && model.id"
|
||||
[formControlName]="model.id"
|
||||
[ngClass]="getClass('element', 'control')"
|
||||
[tabindex]="model.tabIndex"
|
||||
(change)="onValueChange($event)">
|
||||
|
||||
<legend *ngIf="model.legend" [innerHTML]="model.legend"></legend>
|
||||
|
||||
<label *ngFor="let option of model.options$ | async" ngbButtonLabel
|
||||
[ngClass]="[getClass('element', 'option'), getClass('grid', 'option')]">
|
||||
|
||||
<input type="radio" ngbButton
|
||||
[disabled]="option.disabled"
|
||||
[name]="model.name"
|
||||
[value]="option.value"
|
||||
(blur)="onBlur($event)"
|
||||
(focus)="onFocus($event)"/><span [innerHTML]="option.label"></span>
|
||||
</label>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- SELECT ----------------------------------------------------------------------------------------------->
|
||||
<ng-container *ngSwitchCase="9">
|
||||
<ng-container *ngTemplateOutlet="selectTemplate;
|
||||
context:{bindId: bindId, model: model, showErrorMessages: showErrorMessages}">
|
||||
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<!-- TEXTAREA --------------------------------------------------------------------------------------------->
|
||||
<textarea *ngSwitchCase="10" class="form-control"
|
||||
[class.is-invalid]="showErrorMessages"
|
||||
[dynamicId]="bindId && model.id"
|
||||
[cols]="model.cols"
|
||||
[formControlName]="model.id"
|
||||
[maxlength]="model.maxLength"
|
||||
[minlength]="model.minLength"
|
||||
[name]="model.name"
|
||||
[ngClass]="getClass('element', 'control')"
|
||||
[placeholder]="(model.placeholder | translate)"
|
||||
[readonly]="model.readOnly"
|
||||
[required]="model.required"
|
||||
[rows]="model.rows"
|
||||
[spellcheck]="model.spellCheck"
|
||||
[tabindex]="model.tabIndex"
|
||||
[wrap]="model.wrap"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"></textarea>
|
||||
|
||||
<!-- TIMEPICKER ------------------------------------------------------------------------------------------->
|
||||
<ngb-timepicker *ngSwitchCase="11"
|
||||
[dynamicId]="bindId && model.id"
|
||||
[formControlName]="model.id"
|
||||
[hourStep]="getAdditional('hourStep', 1)"
|
||||
[meridian]="model.meridian"
|
||||
[minuteStep]="getAdditional('minuteStep', 1)"
|
||||
[ngClass]="getClass('element', 'control')"
|
||||
[seconds]="model.showSeconds"
|
||||
[secondStep]="getAdditional('secondStep', 1)"
|
||||
[size]="getAdditional('size', 'medium')"
|
||||
[spinners]="getAdditional('spinners', true)"></ngb-timepicker>
|
||||
|
||||
|
||||
|
||||
<ng-container *ngSwitchCase="12">
|
||||
<ng-container *ngTemplateOutlet="typeaheadTemplate;
|
||||
context:{bindId: bindId, model: model, showErrorMessages: showErrorMessages}">
|
||||
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-container *ngSwitchCase="13">
|
||||
<ng-container *ngTemplateOutlet="scrollableDropdownTemplate;
|
||||
context:{bindId: bindId, model: model, showErrorMessages: showErrorMessages}">
|
||||
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="14">
|
||||
<ng-container *ngTemplateOutlet="tagTemplate;
|
||||
context:{bindId: bindId, model: model, showErrorMessages: showErrorMessages}">
|
||||
|
||||
</ng-container>
|
||||
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="15">
|
||||
<ng-container *ngTemplateOutlet="listTemplate;
|
||||
context:{bindId: bindId, model: model, showErrorMessages: showErrorMessages}">
|
||||
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="16">
|
||||
<ds-dynamic-group [model]="model"
|
||||
[formId]="formId"
|
||||
[group]="group"
|
||||
[showErrorMessages]="showErrorMessages"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"></ds-dynamic-group>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="17">
|
||||
<ds-date-picker
|
||||
[bindId]="bindId"
|
||||
[group]="group"
|
||||
[model]="model"
|
||||
[showErrorMessages]="showErrorMessages"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"></ds-date-picker>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="18">
|
||||
<ds-dynamic-lookup
|
||||
[bindId]="bindId"
|
||||
[group]="group"
|
||||
[model]="model"
|
||||
[showErrorMessages]="showErrorMessages"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"
|
||||
></ds-dynamic-lookup>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngSwitchCase="19">
|
||||
<ds-dynamic-lookup
|
||||
[bindId]="bindId"
|
||||
[group]="group"
|
||||
[model]="model"
|
||||
[showErrorMessages]="showErrorMessages"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"
|
||||
></ds-dynamic-lookup>
|
||||
</ng-container>
|
||||
|
||||
<small *ngIf="model.hint" class="text-muted" [innerHTML]="model.hint"
|
||||
[ngClass]="getClass('element', 'hint')"></small>
|
||||
|
||||
<div *ngIf="showErrorMessages" [ngClass]="[getClass('element', 'errors'), getClass('grid', 'errors')]">
|
||||
<small *ngFor="let message of errorMessages" class="invalid-feedback d-block">{{ message | translate:model.validators }}</small>
|
||||
</div>
|
||||
|
||||
</ng-container>
|
||||
|
||||
|
||||
<ng-template #inputTemplate let-bindId="bindId" let-model="model"
|
||||
let-showErrorMessages="showErrorMessages">
|
||||
<input [attr.accept]="model.accept"
|
||||
[attr.list]="model.listId"
|
||||
[attr.max]="model.max"
|
||||
[attr.min]="model.min"
|
||||
[attr.multiple]="model.multiple"
|
||||
[attr.step]="model.step"
|
||||
[autocomplete]="model.autoComplete"
|
||||
[autofocus]="model.autoFocus"
|
||||
[class.form-control]="model.inputType !== 'file'"
|
||||
[class.form-control-file]="model.inputType === 'file'"
|
||||
[class.is-invalid]="showErrorMessages"
|
||||
[dynamicId]="bindId && model.id"
|
||||
[formControlName]="model.id"
|
||||
[maxlength]="model.maxLength"
|
||||
[minlength]="model.minLength"
|
||||
[name]="model.name"
|
||||
[ngClass]="getClass('element', 'control')"
|
||||
[pattern]="model.pattern"
|
||||
[placeholder]="(model.placeholder | translate)"
|
||||
[readonly]="model.readOnly"
|
||||
[required]="model.required"
|
||||
[spellcheck]="model.spellCheck"
|
||||
[tabindex]="model.tabIndex"
|
||||
[textMask]="{mask: (model.mask || false), showMask: model.mask && !(model.placeholder)}"
|
||||
[type]="model.inputType"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"/>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #selectTemplate let-bindId="bindId" let-model="model"
|
||||
let-showErrorMessages="showErrorMessages">
|
||||
<select class="form-control"
|
||||
[class.is-invalid]="showErrorMessages"
|
||||
[dynamicId]="bindId && model.id"
|
||||
[formControlName]="model.id"
|
||||
[name]="model.name"
|
||||
[ngClass]="getClass('element', 'control')"
|
||||
[required]="model.required"
|
||||
[tabindex]="model.tabIndex"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)">
|
||||
|
||||
<option *ngFor="let option of model.options$ | async"
|
||||
[disabled]="option.disabled"
|
||||
[ngValue]="option.value">{{ option.label }}</option>
|
||||
|
||||
</select>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #typeaheadTemplate let-bindId="bindId" let-model="model"
|
||||
let-showErrorMessages="showErrorMessages">
|
||||
<ds-dynamic-typeahead [bindId]="bindId"
|
||||
[group]="group"
|
||||
[model]="model"
|
||||
[showErrorMessages]="showErrorMessages"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"></ds-dynamic-typeahead>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #scrollableDropdownTemplate let-bindId="bindId" let-model="model"
|
||||
let-showErrorMessages="showErrorMessages">
|
||||
<ds-dynamic-scrollable-dropdown [bindId]="bindId"
|
||||
[group]="group"
|
||||
[model]="model"
|
||||
[showErrorMessages]="showErrorMessages"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"></ds-dynamic-scrollable-dropdown>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #tagTemplate let-bindId="bindId" let-model="model"
|
||||
let-showErrorMessages="showErrorMessages">
|
||||
<ds-dynamic-tag [bindId]="bindId"
|
||||
[group]="group"
|
||||
[model]="model"
|
||||
[showErrorMessages]="showErrorMessages"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"></ds-dynamic-tag>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #listTemplate let-bindId="bindId" let-model="model"
|
||||
let-showErrorMessages="showErrorMessages">
|
||||
<ds-dynamic-list [bindId]="bindId"
|
||||
[group]="group"
|
||||
[model]="model"
|
||||
[showErrorMessages]="showErrorMessages"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"></ds-dynamic-list>
|
||||
</ng-template>
|
||||
<ng-container #componentViewContainer></ng-container>
|
||||
|
||||
</div>
|
||||
|
||||
|
@@ -25,7 +25,7 @@ import {
|
||||
DynamicTextAreaModel,
|
||||
DynamicTimePickerModel
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { DsDynamicFormControlComponent, NGBootstrapFormControlType } from './ds-dynamic-form-control.component';
|
||||
import { DsDynamicFormControlComponent } from './ds-dynamic-form-control.component';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { SharedModule } from '../../../shared.module';
|
||||
import { DynamicDsDatePickerModel } from './models/date-picker/date-picker.model';
|
||||
@@ -39,6 +39,27 @@ import { DynamicTagModel } from './models/tag/dynamic-tag.model';
|
||||
import { DynamicTypeaheadModel } from './models/typeahead/dynamic-typeahead.model';
|
||||
import { DynamicQualdropModel } from './models/ds-dynamic-qualdrop.model';
|
||||
import { DynamicLookupNameModel } from './models/lookup/dynamic-lookup-name.model';
|
||||
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
|
||||
import {
|
||||
DynamicNGBootstrapCalendarComponent,
|
||||
DynamicNGBootstrapCheckboxComponent,
|
||||
DynamicNGBootstrapCheckboxGroupComponent,
|
||||
DynamicNGBootstrapDatePickerComponent,
|
||||
DynamicNGBootstrapFormArrayComponent,
|
||||
DynamicNGBootstrapFormGroupComponent,
|
||||
DynamicNGBootstrapInputComponent,
|
||||
DynamicNGBootstrapRadioGroupComponent,
|
||||
DynamicNGBootstrapSelectComponent,
|
||||
DynamicNGBootstrapTextAreaComponent,
|
||||
DynamicNGBootstrapTimePickerComponent
|
||||
} from '@ng-dynamic-forms/ui-ng-bootstrap';
|
||||
import { DsDynamicTypeaheadComponent } from './models/typeahead/dynamic-typeahead.component';
|
||||
import { DsDynamicScrollableDropdownComponent } from './models/scrollable-dropdown/dynamic-scrollable-dropdown.component';
|
||||
import { DsDynamicTagComponent } from './models/tag/dynamic-tag.component';
|
||||
import { DsDynamicListComponent } from './models/list/dynamic-list.component';
|
||||
import { DsDynamicGroupComponent } from './models/dynamic-group/dynamic-group.components';
|
||||
import { DsDatePickerComponent } from './models/date-picker/date-picker.component';
|
||||
import { DsDynamicLookupComponent } from './models/lookup/dynamic-lookup.component';
|
||||
|
||||
describe('DsDynamicFormControlComponent test suite', () => {
|
||||
|
||||
@@ -49,27 +70,42 @@ describe('DsDynamicFormControlComponent test suite', () => {
|
||||
scope: 'c1c16450-d56f-41bc-bb81-27f1d1eb5c23'
|
||||
};
|
||||
const formModel = [
|
||||
new DynamicCheckboxModel({id: 'checkbox'}),
|
||||
new DynamicCheckboxGroupModel({id: 'checkboxGroup', group: []}),
|
||||
new DynamicColorPickerModel({id: 'colorpicker'}),
|
||||
new DynamicDatePickerModel({id: 'datepicker'}),
|
||||
new DynamicEditorModel({id: 'editor'}),
|
||||
new DynamicFileUploadModel({id: 'upload', url: ''}),
|
||||
new DynamicFormArrayModel({id: 'formArray', groupFactory: () => []}),
|
||||
new DynamicFormGroupModel({id: 'formGroup', group: []}),
|
||||
new DynamicInputModel({id: 'input', maxLength: 51}),
|
||||
new DynamicRadioGroupModel({id: 'radioGroup'}),
|
||||
new DynamicRatingModel({id: 'rating'}),
|
||||
new DynamicSelectModel({id: 'select', options: [{value: 'One'}, {value: 'Two'}], value: 'One'}),
|
||||
new DynamicSliderModel({id: 'slider'}),
|
||||
new DynamicSwitchModel({id: 'switch'}),
|
||||
new DynamicTextAreaModel({id: 'textarea'}),
|
||||
new DynamicTimePickerModel({id: 'timepicker'}),
|
||||
new DynamicTypeaheadModel({id: 'typeahead'}),
|
||||
new DynamicScrollableDropdownModel({id: 'scrollableDropdown', authorityOptions: authorityOptions}),
|
||||
new DynamicTagModel({id: 'tag'}),
|
||||
new DynamicListCheckboxGroupModel({id: 'checkboxList', authorityOptions: authorityOptions, repeatable: true}),
|
||||
new DynamicListRadioGroupModel({id: 'radioList', authorityOptions: authorityOptions, repeatable: false}),
|
||||
new DynamicCheckboxModel({ id: 'checkbox' }),
|
||||
new DynamicCheckboxGroupModel({ id: 'checkboxGroup', group: [] }),
|
||||
new DynamicColorPickerModel({ id: 'colorpicker' }),
|
||||
new DynamicDatePickerModel({ id: 'datepicker' }),
|
||||
new DynamicEditorModel({ id: 'editor' }),
|
||||
new DynamicFileUploadModel({ id: 'upload', url: '' }),
|
||||
new DynamicFormArrayModel({ id: 'formArray', groupFactory: () => [] }),
|
||||
new DynamicFormGroupModel({ id: 'formGroup', group: [] }),
|
||||
new DynamicInputModel({ id: 'input', maxLength: 51 }),
|
||||
new DynamicRadioGroupModel({ id: 'radioGroup' }),
|
||||
new DynamicRatingModel({ id: 'rating' }),
|
||||
new DynamicSelectModel({
|
||||
id: 'select',
|
||||
options: [{ value: 'One' }, { value: 'Two' }],
|
||||
value: 'One'
|
||||
}),
|
||||
new DynamicSliderModel({ id: 'slider' }),
|
||||
new DynamicSwitchModel({ id: 'switch' }),
|
||||
new DynamicTextAreaModel({ id: 'textarea' }),
|
||||
new DynamicTimePickerModel({ id: 'timepicker' }),
|
||||
new DynamicTypeaheadModel({ id: 'typeahead' }),
|
||||
new DynamicScrollableDropdownModel({
|
||||
id: 'scrollableDropdown',
|
||||
authorityOptions: authorityOptions
|
||||
}),
|
||||
new DynamicTagModel({ id: 'tag' }),
|
||||
new DynamicListCheckboxGroupModel({
|
||||
id: 'checkboxList',
|
||||
authorityOptions: authorityOptions,
|
||||
repeatable: true
|
||||
}),
|
||||
new DynamicListRadioGroupModel({
|
||||
id: 'radioList',
|
||||
authorityOptions: authorityOptions,
|
||||
repeatable: false
|
||||
}),
|
||||
new DynamicGroupModel({
|
||||
id: 'relationGroup',
|
||||
formConfiguration: [],
|
||||
@@ -79,10 +115,10 @@ describe('DsDynamicFormControlComponent test suite', () => {
|
||||
scopeUUID: '',
|
||||
submissionScope: ''
|
||||
}),
|
||||
new DynamicDsDatePickerModel({id: 'datepicker'}),
|
||||
new DynamicLookupModel({id: 'lookup'}),
|
||||
new DynamicLookupNameModel({id: 'lookupName'}),
|
||||
new DynamicQualdropModel({id: 'combobox', readOnly: false})
|
||||
new DynamicDsDatePickerModel({ id: 'datepicker' }),
|
||||
new DynamicLookupModel({ id: 'lookup' }),
|
||||
new DynamicLookupNameModel({ id: 'lookupName' }),
|
||||
new DynamicQualdropModel({ id: 'combobox', readOnly: false })
|
||||
];
|
||||
const testModel = formModel[8];
|
||||
let formGroup: FormGroup;
|
||||
@@ -93,6 +129,13 @@ describe('DsDynamicFormControlComponent test suite', () => {
|
||||
|
||||
beforeEach(async(() => {
|
||||
|
||||
TestBed.overrideModule(BrowserDynamicTestingModule, {
|
||||
|
||||
set: {
|
||||
entryComponents: [DynamicNGBootstrapInputComponent]
|
||||
}
|
||||
});
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
|
||||
imports: [
|
||||
@@ -102,8 +145,9 @@ describe('DsDynamicFormControlComponent test suite', () => {
|
||||
DynamicFormsCoreModule.forRoot(),
|
||||
SharedModule,
|
||||
TranslateModule.forRoot(),
|
||||
TextMaskModule,
|
||||
TextMaskModule
|
||||
],
|
||||
providers: [DsDynamicFormControlComponent, DynamicFormService],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
}).compileComponents().then(() => {
|
||||
|
||||
@@ -128,12 +172,11 @@ describe('DsDynamicFormControlComponent test suite', () => {
|
||||
});
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
console.log(fixture.componentInstance.componentViewContainerRef);
|
||||
testElement = debugElement.query(By.css(`input[id='${testModel.id}']`));
|
||||
}));
|
||||
|
||||
it('should initialize correctly', () => {
|
||||
|
||||
expect(component.context).toBeNull();
|
||||
expect(component.control instanceof FormControl).toBe(true);
|
||||
expect(component.group instanceof FormGroup).toBe(true);
|
||||
@@ -149,15 +192,7 @@ describe('DsDynamicFormControlComponent test suite', () => {
|
||||
expect(component.change).toBeDefined();
|
||||
expect(component.focus).toBeDefined();
|
||||
|
||||
expect(component.onChange).toBeDefined();
|
||||
expect(component.onBlur).toBeDefined();
|
||||
expect(component.onFocus).toBeDefined();
|
||||
|
||||
expect(component.isValid).toBe(true);
|
||||
expect(component.isInvalid).toBe(false);
|
||||
expect(component.showErrorMessages).toBe(false);
|
||||
|
||||
expect(component.type).toBe(NGBootstrapFormControlType.Input);
|
||||
expect(component.componentType).toBe(DynamicNGBootstrapInputComponent);
|
||||
});
|
||||
|
||||
it('should have an input element', () => {
|
||||
@@ -219,63 +254,36 @@ describe('DsDynamicFormControlComponent test suite', () => {
|
||||
expect(component.onModelDisabledUpdates).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should determine correct form control type', () => {
|
||||
|
||||
it('should map a form control model to a form control component', () => {
|
||||
const testFn = DsDynamicFormControlComponent.getFormControlType;
|
||||
|
||||
expect(testFn(formModel[0])).toEqual(NGBootstrapFormControlType.Checkbox);
|
||||
|
||||
expect(testFn(formModel[1])).toEqual(NGBootstrapFormControlType.CheckboxGroup);
|
||||
|
||||
expect(testFn(formModel[0])).toBe(DynamicNGBootstrapCheckboxComponent);
|
||||
expect(testFn(formModel[1])).toBe(DynamicNGBootstrapCheckboxGroupComponent);
|
||||
expect(testFn(formModel[2])).toBeNull();
|
||||
|
||||
expect(testFn(formModel[3])).toEqual(NGBootstrapFormControlType.DatePicker);
|
||||
|
||||
expect(testFn(formModel[3])).toBe(DynamicNGBootstrapDatePickerComponent);
|
||||
(formModel[3] as DynamicDatePickerModel).inline = true;
|
||||
expect(testFn(formModel[3])).toEqual(NGBootstrapFormControlType.Calendar);
|
||||
|
||||
expect(testFn(formModel[3])).toBe(DynamicNGBootstrapCalendarComponent);
|
||||
expect(testFn(formModel[4])).toBeNull();
|
||||
|
||||
expect(testFn(formModel[5])).toBeNull();
|
||||
|
||||
expect(testFn(formModel[6])).toEqual(NGBootstrapFormControlType.Array);
|
||||
|
||||
expect(testFn(formModel[7])).toEqual(NGBootstrapFormControlType.Group);
|
||||
|
||||
expect(testFn(formModel[8])).toEqual(NGBootstrapFormControlType.Input);
|
||||
|
||||
expect(testFn(formModel[9])).toEqual(NGBootstrapFormControlType.RadioGroup);
|
||||
|
||||
expect(testFn(formModel[6])).toBe(DynamicNGBootstrapFormArrayComponent);
|
||||
expect(testFn(formModel[7])).toBe(DynamicNGBootstrapFormGroupComponent);
|
||||
expect(testFn(formModel[8])).toBe(DynamicNGBootstrapInputComponent);
|
||||
expect(testFn(formModel[9])).toBe(DynamicNGBootstrapRadioGroupComponent);
|
||||
expect(testFn(formModel[10])).toBeNull();
|
||||
|
||||
expect(testFn(formModel[11])).toEqual(NGBootstrapFormControlType.Select);
|
||||
|
||||
expect(testFn(formModel[11])).toBe(DynamicNGBootstrapSelectComponent);
|
||||
expect(testFn(formModel[12])).toBeNull();
|
||||
|
||||
expect(testFn(formModel[13])).toBeNull();
|
||||
|
||||
expect(testFn(formModel[14])).toEqual(NGBootstrapFormControlType.TextArea);
|
||||
|
||||
expect(testFn(formModel[15])).toEqual(NGBootstrapFormControlType.TimePicker);
|
||||
|
||||
expect(testFn(formModel[16])).toEqual(NGBootstrapFormControlType.TypeAhead);
|
||||
|
||||
expect(testFn(formModel[17])).toEqual(NGBootstrapFormControlType.ScrollableDropdown);
|
||||
|
||||
expect(testFn(formModel[18])).toEqual(NGBootstrapFormControlType.Tag);
|
||||
|
||||
expect(testFn(formModel[19])).toEqual(NGBootstrapFormControlType.List);
|
||||
|
||||
expect(testFn(formModel[20])).toEqual(NGBootstrapFormControlType.List);
|
||||
|
||||
expect(testFn(formModel[21])).toEqual(NGBootstrapFormControlType.Relation);
|
||||
|
||||
expect(testFn(formModel[22])).toEqual(NGBootstrapFormControlType.Date);
|
||||
|
||||
expect(testFn(formModel[23])).toEqual(NGBootstrapFormControlType.Lookup);
|
||||
|
||||
expect(testFn(formModel[24])).toEqual(NGBootstrapFormControlType.LookupName);
|
||||
|
||||
expect(testFn(formModel[25])).toEqual(NGBootstrapFormControlType.Group);
|
||||
expect(testFn(formModel[14])).toBe(DynamicNGBootstrapTextAreaComponent);
|
||||
expect(testFn(formModel[15])).toBe(DynamicNGBootstrapTimePickerComponent);
|
||||
expect(testFn(formModel[16])).toBe(DsDynamicTypeaheadComponent);
|
||||
expect(testFn(formModel[17])).toBe(DsDynamicScrollableDropdownComponent);
|
||||
expect(testFn(formModel[18])).toBe(DsDynamicTagComponent);
|
||||
expect(testFn(formModel[19])).toBe(DsDynamicListComponent);
|
||||
expect(testFn(formModel[20])).toBe(DsDynamicListComponent);
|
||||
expect(testFn(formModel[21])).toBe(DsDynamicGroupComponent);
|
||||
expect(testFn(formModel[22])).toBe(DsDatePickerComponent);
|
||||
expect(testFn(formModel[23])).toBe(DsDynamicLookupComponent);
|
||||
expect(testFn(formModel[24])).toBe(DsDynamicLookupComponent);
|
||||
expect(testFn(formModel[25])).toBe(DynamicNGBootstrapFormGroupComponent);
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -6,7 +6,7 @@ import {
|
||||
OnChanges,
|
||||
Output,
|
||||
QueryList,
|
||||
SimpleChanges, Type
|
||||
SimpleChanges, Type, ViewChild, ViewContainerRef
|
||||
} from '@angular/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import {
|
||||
@@ -39,29 +39,26 @@ import { DynamicListCheckboxGroupModel } from './models/list/dynamic-list-checkb
|
||||
import { DynamicListRadioGroupModel } from './models/list/dynamic-list-radio-group.model';
|
||||
import { isNotEmpty } from '../../../empty.util';
|
||||
import { DYNAMIC_FORM_CONTROL_TYPE_LOOKUP_NAME } from './models/lookup/dynamic-lookup-name.model';
|
||||
|
||||
export const enum NGBootstrapFormControlType {
|
||||
|
||||
Array = 1, // 'ARRAY',
|
||||
Calendar = 2, // 'CALENDAR',
|
||||
Checkbox = 3, // 'CHECKBOX',
|
||||
CheckboxGroup = 4, // 'CHECKBOX_GROUP',
|
||||
DatePicker = 5, // 'DATEPICKER',
|
||||
Group = 6, // 'GROUP',
|
||||
Input = 7, // 'INPUT',
|
||||
RadioGroup = 8, // 'RADIO_GROUP',
|
||||
Select = 9, // 'SELECT',
|
||||
TextArea = 10, // 'TEXTAREA',
|
||||
TimePicker = 11, // 'TIMEPICKER'
|
||||
TypeAhead = 12, // 'TYPEAHEAD'
|
||||
ScrollableDropdown = 13, // 'SCROLLABLE_DROPDOWN'
|
||||
Tag = 14, // 'TAG'
|
||||
List = 15, // 'TYPELIST'
|
||||
Relation = 16, // 'RELATION'
|
||||
Date = 17, // 'DATE'
|
||||
Lookup = 18, // LOOKUP
|
||||
LookupName = 19, // LOOKUP_NAME
|
||||
}
|
||||
import { DsDynamicTagComponent } from './models/tag/dynamic-tag.component';
|
||||
import {
|
||||
DynamicNGBootstrapCalendarComponent,
|
||||
DynamicNGBootstrapCheckboxComponent,
|
||||
DynamicNGBootstrapCheckboxGroupComponent,
|
||||
DynamicNGBootstrapDatePickerComponent,
|
||||
DynamicNGBootstrapFormArrayComponent,
|
||||
DynamicNGBootstrapFormGroupComponent,
|
||||
DynamicNGBootstrapInputComponent,
|
||||
DynamicNGBootstrapRadioGroupComponent,
|
||||
DynamicNGBootstrapSelectComponent,
|
||||
DynamicNGBootstrapTextAreaComponent,
|
||||
DynamicNGBootstrapTimePickerComponent
|
||||
} from '@ng-dynamic-forms/ui-ng-bootstrap';
|
||||
import { DsDatePickerComponent } from './models/date-picker/date-picker.component';
|
||||
import { DsDynamicListComponent } from './models/list/dynamic-list.component';
|
||||
import { DsDynamicTypeaheadComponent } from './models/typeahead/dynamic-typeahead.component';
|
||||
import { DsDynamicScrollableDropdownComponent } from './models/scrollable-dropdown/dynamic-scrollable-dropdown.component';
|
||||
import { DsDynamicGroupComponent } from './models/dynamic-group/dynamic-group.components';
|
||||
import { DsDynamicLookupComponent } from './models/lookup/dynamic-lookup.component';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-dynamic-form-control',
|
||||
@@ -88,67 +85,68 @@ export class DsDynamicFormControlComponent extends DynamicFormControlContainerCo
|
||||
@Output('dfChange') change: EventEmitter<DynamicFormControlEvent> = new EventEmitter<DynamicFormControlEvent>();
|
||||
@Output('dfFocus') focus: EventEmitter<DynamicFormControlEvent> = new EventEmitter<DynamicFormControlEvent>();
|
||||
/* tslint:enable:no-output-rename */
|
||||
@ViewChild('componentViewContainer', {read: ViewContainerRef}) componentViewContainerRef: ViewContainerRef;
|
||||
|
||||
type: NGBootstrapFormControlType | null;
|
||||
get componentType(): Type<DynamicFormControl> | null {
|
||||
return this.layoutService.getCustomComponentType(this.model) || DsDynamicFormControlComponent.getFormControlType(this.model);
|
||||
}
|
||||
|
||||
readonly componentType: Type<DynamicFormControl> | null;
|
||||
|
||||
static getFormControlType(model: DynamicFormControlModel): NGBootstrapFormControlType | null {
|
||||
static getFormControlType(model: DynamicFormControlModel): Type<DynamicFormControl> | null {
|
||||
|
||||
switch (model.type) {
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_ARRAY:
|
||||
return NGBootstrapFormControlType.Array;
|
||||
return DynamicNGBootstrapFormArrayComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX:
|
||||
return NGBootstrapFormControlType.Checkbox;
|
||||
return DynamicNGBootstrapCheckboxComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX_GROUP:
|
||||
return (model instanceof DynamicListCheckboxGroupModel) ? NGBootstrapFormControlType.List : NGBootstrapFormControlType.CheckboxGroup;
|
||||
return (model instanceof DynamicListCheckboxGroupModel) ? DsDynamicListComponent : DynamicNGBootstrapCheckboxGroupComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_DATEPICKER:
|
||||
const datepickerModel = model as DynamicDatePickerModel;
|
||||
|
||||
return datepickerModel.inline ? NGBootstrapFormControlType.Calendar : NGBootstrapFormControlType.DatePicker;
|
||||
return datepickerModel.inline ? DynamicNGBootstrapCalendarComponent : DynamicNGBootstrapDatePickerComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_GROUP:
|
||||
return NGBootstrapFormControlType.Group;
|
||||
return DynamicNGBootstrapFormGroupComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_INPUT:
|
||||
return NGBootstrapFormControlType.Input;
|
||||
return DynamicNGBootstrapInputComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_RADIO_GROUP:
|
||||
return (model instanceof DynamicListRadioGroupModel) ? NGBootstrapFormControlType.List : NGBootstrapFormControlType.RadioGroup;
|
||||
return (model instanceof DynamicListRadioGroupModel) ? DsDynamicListComponent : DynamicNGBootstrapRadioGroupComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_SELECT:
|
||||
return NGBootstrapFormControlType.Select;
|
||||
return DynamicNGBootstrapSelectComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_TEXTAREA:
|
||||
return NGBootstrapFormControlType.TextArea;
|
||||
return DynamicNGBootstrapTextAreaComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_TIMEPICKER:
|
||||
return NGBootstrapFormControlType.TimePicker;
|
||||
return DynamicNGBootstrapTimePickerComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_TYPEAHEAD:
|
||||
return NGBootstrapFormControlType.TypeAhead;
|
||||
return DsDynamicTypeaheadComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_SCROLLABLE_DROPDOWN:
|
||||
return NGBootstrapFormControlType.ScrollableDropdown;
|
||||
return DsDynamicScrollableDropdownComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_TAG:
|
||||
return NGBootstrapFormControlType.Tag;
|
||||
return DsDynamicTagComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP:
|
||||
return NGBootstrapFormControlType.Relation;
|
||||
return DsDynamicGroupComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_DSDATEPICKER:
|
||||
return NGBootstrapFormControlType.Date;
|
||||
return DsDatePickerComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_LOOKUP:
|
||||
return NGBootstrapFormControlType.Lookup;
|
||||
return DsDynamicLookupComponent;
|
||||
|
||||
case DYNAMIC_FORM_CONTROL_TYPE_LOOKUP_NAME:
|
||||
return NGBootstrapFormControlType.LookupName;
|
||||
return DsDynamicLookupComponent;
|
||||
|
||||
default:
|
||||
return null;
|
||||
@@ -163,11 +161,7 @@ export class DsDynamicFormControlComponent extends DynamicFormControlContainerCo
|
||||
|
||||
ngOnChanges(changes: SimpleChanges) {
|
||||
if (changes) {
|
||||
// super.ngOnChanges(changes);
|
||||
}
|
||||
|
||||
if (changes.model) {
|
||||
this.type = DsDynamicFormControlComponent.getFormControlType(this.model);
|
||||
super.ngOnChanges(changes);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -4,7 +4,7 @@ import { async, ComponentFixture, inject, TestBed, } from '@angular/core/testing
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { DynamicFormValidationService } from '@ng-dynamic-forms/core';
|
||||
import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core';
|
||||
|
||||
import { DsDatePickerComponent } from './date-picker.component';
|
||||
import { DynamicDsDatePickerModel } from './date-picker.model';
|
||||
@@ -52,10 +52,8 @@ describe('DsDatePickerComponent test suite', () => {
|
||||
providers: [
|
||||
ChangeDetectorRef,
|
||||
DsDatePickerComponent,
|
||||
DynamicFormValidationService,
|
||||
FormBuilderService,
|
||||
FormComponent,
|
||||
FormService
|
||||
{provide: DynamicFormLayoutService, useValue: {}},
|
||||
{provide: DynamicFormValidationService, useValue: {}}
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
});
|
||||
@@ -70,7 +68,6 @@ describe('DsDatePickerComponent test suite', () => {
|
||||
[bindId]='bindId'
|
||||
[group]='group'
|
||||
[model]='model'
|
||||
[showErrorMessages]='showErrorMessages'
|
||||
(blur)='onBlur($event)'
|
||||
(change)='onValueChange($event)'
|
||||
(focus)='onFocus($event)'></ds-date-picker>`;
|
||||
|
@@ -1,7 +1,12 @@
|
||||
import { Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { DynamicDsDatePickerModel } from './date-picker.model';
|
||||
import { hasNoValue, hasValue, isNotEmpty } from '../../../../../empty.util';
|
||||
import { hasValue } from '../../../../../empty.util';
|
||||
import {
|
||||
DynamicFormControlComponent,
|
||||
DynamicFormLayoutService,
|
||||
DynamicFormValidationService
|
||||
} from '@ng-dynamic-forms/core';
|
||||
|
||||
export const DS_DATE_PICKER_SEPARATOR = '-';
|
||||
|
||||
@@ -11,11 +16,11 @@ export const DS_DATE_PICKER_SEPARATOR = '-';
|
||||
templateUrl: './date-picker.component.html',
|
||||
})
|
||||
|
||||
export class DsDatePickerComponent implements OnInit {
|
||||
export class DsDatePickerComponent extends DynamicFormControlComponent implements OnInit {
|
||||
@Input() bindId = true;
|
||||
@Input() group: FormGroup;
|
||||
@Input() model: DynamicDsDatePickerModel;
|
||||
@Input() showErrorMessages = false;
|
||||
// @Input() showErrorMessages = false;
|
||||
// @Input()
|
||||
// minDate;
|
||||
// @Input()
|
||||
@@ -49,6 +54,12 @@ export class DsDatePickerComponent implements OnInit {
|
||||
disabledMonth = true;
|
||||
disabledDay = true;
|
||||
|
||||
constructor(protected layoutService: DynamicFormLayoutService,
|
||||
protected validationService: DynamicFormValidationService
|
||||
) {
|
||||
super(layoutService, validationService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
const now = new Date();
|
||||
this.initialYear = now.getFullYear();
|
||||
|
@@ -3,8 +3,6 @@ import { ChangeDetectorRef, Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/c
|
||||
import { async, ComponentFixture, inject, TestBed, } from '@angular/core/testing';
|
||||
import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
import { DynamicFormValidationService } from '@ng-dynamic-forms/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
@@ -20,12 +18,15 @@ import { FormBuilderService } from '../../../form-builder.service';
|
||||
import { FormService } from '../../../../form.service';
|
||||
import { GLOBAL_CONFIG } from '../../../../../../../config';
|
||||
import { FormComponent } from '../../../../form.component';
|
||||
import { AppState } from '../../../../../../app.reducer';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { Chips } from '../../../../../chips/models/chips.model';
|
||||
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
|
||||
import { DsDynamicInputModel } from '../ds-dynamic-input.model';
|
||||
import { createTestComponent } from '../../../../../testing/utils';
|
||||
import { getMockFormBuilderService } from '../../../../../mocks/mock-form-builder-service';
|
||||
import { getMockFormService } from '../../../../../mocks/mock-form-service';
|
||||
import { MockComponent } from 'ng-mocks';
|
||||
import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core';
|
||||
|
||||
export const FORM_GROUP_TEST_MODEL_CONFIG = {
|
||||
disabled: false,
|
||||
@@ -90,18 +91,13 @@ describe('DsDynamicGroupComponent test suite', () => {
|
||||
let groupComp: DsDynamicGroupComponent;
|
||||
let testFixture: ComponentFixture<TestComponent>;
|
||||
let groupFixture: ComponentFixture<DsDynamicGroupComponent>;
|
||||
let modelValue: any;
|
||||
// let modelValue: any;
|
||||
let html;
|
||||
let control1: FormControl;
|
||||
let model1: DsDynamicInputModel;
|
||||
let control2: FormControl;
|
||||
let model2: DsDynamicInputModel;
|
||||
|
||||
const store: Store<AppState> = jasmine.createSpyObj('store', {
|
||||
dispatch: {},
|
||||
select: observableOf(true)
|
||||
});
|
||||
|
||||
// async beforeEach
|
||||
beforeEach(async(() => {
|
||||
|
||||
@@ -114,19 +110,18 @@ describe('DsDynamicGroupComponent test suite', () => {
|
||||
TranslateModule.forRoot()
|
||||
],
|
||||
declarations: [
|
||||
FormComponent,
|
||||
MockComponent(FormComponent),
|
||||
DsDynamicGroupComponent,
|
||||
TestComponent,
|
||||
], // declare the test component
|
||||
providers: [
|
||||
ChangeDetectorRef,
|
||||
DsDynamicGroupComponent,
|
||||
DynamicFormValidationService,
|
||||
FormBuilderService,
|
||||
FormComponent,
|
||||
FormService,
|
||||
{provide: FormBuilderService, useValue: getMockFormBuilderService()},
|
||||
{provide: FormService, useValue: getMockFormService()},
|
||||
{provide: GLOBAL_CONFIG, useValue: config},
|
||||
{provide: Store, useValue: store},
|
||||
{provide: DynamicFormLayoutService, useValue: {}},
|
||||
{provide: DynamicFormValidationService, useValue: {}}
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
});
|
||||
@@ -140,7 +135,6 @@ describe('DsDynamicGroupComponent test suite', () => {
|
||||
<ds-dynamic-group [model]="model"
|
||||
[formId]="formId"
|
||||
[group]="group"
|
||||
[showErrorMessages]="showErrorMessages"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"></ds-dynamic-group>`;
|
||||
@@ -163,7 +157,6 @@ describe('DsDynamicGroupComponent test suite', () => {
|
||||
groupComp.formId = 'testForm';
|
||||
groupComp.group = FORM_GROUP_TEST_GROUP;
|
||||
groupComp.model = new DynamicGroupModel(FORM_GROUP_TEST_MODEL_CONFIG);
|
||||
groupComp.showErrorMessages = false;
|
||||
groupFixture.detectChanges();
|
||||
|
||||
control1 = service.getFormControlById('dc_contributor_author', (groupComp as any).formRef.formGroup, groupComp.formModel) as FormControl;
|
||||
@@ -179,123 +172,123 @@ describe('DsDynamicGroupComponent test suite', () => {
|
||||
groupComp = null;
|
||||
});
|
||||
|
||||
it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => {
|
||||
const formConfig = {rows: groupComp.model.formConfiguration} as SubmissionFormsModel;
|
||||
const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
|
||||
const chips = new Chips([], 'value', 'dc.contributor.author');
|
||||
|
||||
expect(groupComp.formCollapsed).toEqual(observableOf(false));
|
||||
expect(groupComp.formModel.length).toEqual(formModel.length);
|
||||
expect(groupComp.chips.getChipsItems()).toEqual(chips.getChipsItems());
|
||||
}));
|
||||
|
||||
it('should save a new chips item', () => {
|
||||
control1.setValue('test author');
|
||||
(model1 as any).value = new FormFieldMetadataValueObject('test author');
|
||||
control2.setValue('test affiliation');
|
||||
(model2 as any).value = new FormFieldMetadataValueObject('test affiliation');
|
||||
modelValue = [{
|
||||
'dc.contributor.author': new FormFieldMetadataValueObject('test author'),
|
||||
'local.contributor.affiliation': new FormFieldMetadataValueObject('test affiliation')
|
||||
}];
|
||||
groupFixture.detectChanges();
|
||||
|
||||
const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
|
||||
const btnEl = buttons[0];
|
||||
btnEl.click();
|
||||
|
||||
expect(groupComp.chips.getChipsItems()).toEqual(modelValue);
|
||||
expect(groupComp.formCollapsed).toEqual(observableOf(true));
|
||||
});
|
||||
|
||||
it('should clear form inputs', () => {
|
||||
control1.setValue('test author');
|
||||
(model1 as any).value = new FormFieldMetadataValueObject('test author');
|
||||
control2.setValue('test affiliation');
|
||||
(model2 as any).value = new FormFieldMetadataValueObject('test affiliation');
|
||||
|
||||
groupFixture.detectChanges();
|
||||
|
||||
const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
|
||||
const btnEl = buttons[2];
|
||||
btnEl.click();
|
||||
|
||||
expect(control1.value).toBeNull();
|
||||
expect(control2.value).toBeNull();
|
||||
expect(groupComp.formCollapsed).toEqual(observableOf(false));
|
||||
});
|
||||
});
|
||||
|
||||
describe('when init model value is not empty', () => {
|
||||
beforeEach(() => {
|
||||
|
||||
groupFixture = TestBed.createComponent(DsDynamicGroupComponent);
|
||||
groupComp = groupFixture.componentInstance; // FormComponent test instance
|
||||
groupComp.formId = 'testForm';
|
||||
groupComp.group = FORM_GROUP_TEST_GROUP;
|
||||
groupComp.model = new DynamicGroupModel(FORM_GROUP_TEST_MODEL_CONFIG);
|
||||
modelValue = [{
|
||||
'dc.contributor.author': new FormFieldMetadataValueObject('test author'),
|
||||
'local.contributor.affiliation': new FormFieldMetadataValueObject('test affiliation')
|
||||
}];
|
||||
groupComp.model.value = modelValue;
|
||||
groupComp.showErrorMessages = false;
|
||||
groupFixture.detectChanges();
|
||||
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
groupFixture.destroy();
|
||||
groupComp = null;
|
||||
});
|
||||
|
||||
it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => {
|
||||
const formConfig = {rows: groupComp.model.formConfiguration} as SubmissionFormsModel;
|
||||
const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
|
||||
const chips = new Chips(modelValue, 'value', 'dc.contributor.author');
|
||||
|
||||
expect(groupComp.formCollapsed).toEqual(observableOf(true));
|
||||
expect(groupComp.formModel.length).toEqual(formModel.length);
|
||||
expect(groupComp.chips.getChipsItems()).toEqual(chips.getChipsItems());
|
||||
}));
|
||||
|
||||
it('should modify existing chips item', inject([FormBuilderService], (service: FormBuilderService) => {
|
||||
groupComp.onChipSelected(0);
|
||||
groupFixture.detectChanges();
|
||||
|
||||
control1 = service.getFormControlById('dc_contributor_author', (groupComp as any).formRef.formGroup, groupComp.formModel) as FormControl;
|
||||
model1 = service.findById('dc_contributor_author', groupComp.formModel) as DsDynamicInputModel;
|
||||
|
||||
control1.setValue('test author modify');
|
||||
(model1 as any).value = new FormFieldMetadataValueObject('test author modify');
|
||||
|
||||
modelValue = [{
|
||||
'dc.contributor.author': new FormFieldMetadataValueObject('test author modify'),
|
||||
'local.contributor.affiliation': new FormFieldMetadataValueObject('test affiliation')
|
||||
}];
|
||||
groupFixture.detectChanges();
|
||||
|
||||
const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
|
||||
const btnEl = buttons[0];
|
||||
btnEl.click();
|
||||
|
||||
groupFixture.detectChanges();
|
||||
|
||||
expect(groupComp.chips.getChipsItems()).toEqual(modelValue);
|
||||
expect(groupComp.formCollapsed).toEqual(observableOf(true));
|
||||
}));
|
||||
|
||||
it('should delete existing chips item', () => {
|
||||
groupComp.onChipSelected(0);
|
||||
groupFixture.detectChanges();
|
||||
|
||||
const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
|
||||
const btnEl = buttons[1];
|
||||
btnEl.click();
|
||||
|
||||
expect(groupComp.chips.getChipsItems()).toEqual([]);
|
||||
expect(groupComp.formCollapsed).toEqual(observableOf(false));
|
||||
});
|
||||
// it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => {
|
||||
// const formConfig = {rows: groupComp.model.formConfiguration} as SubmissionFormsModel;
|
||||
// const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
|
||||
// const chips = new Chips([], 'value', 'dc.contributor.author');
|
||||
//
|
||||
// expect(groupComp.formCollapsed).toEqual(observableOf(false));
|
||||
// expect(groupComp.formModel.length).toEqual(formModel.length);
|
||||
// expect(groupComp.chips.getChipsItems()).toEqual(chips.getChipsItems());
|
||||
// }));
|
||||
//
|
||||
// it('should save a new chips item', () => {
|
||||
// control1.setValue('test author');
|
||||
// (model1 as any).value = new FormFieldMetadataValueObject('test author');
|
||||
// control2.setValue('test affiliation');
|
||||
// (model2 as any).value = new FormFieldMetadataValueObject('test affiliation');
|
||||
// modelValue = [{
|
||||
// 'dc.contributor.author': new FormFieldMetadataValueObject('test author'),
|
||||
// 'local.contributor.affiliation': new FormFieldMetadataValueObject('test affiliation')
|
||||
// }];
|
||||
// groupFixture.detectChanges();
|
||||
//
|
||||
// const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
|
||||
// const btnEl = buttons[0];
|
||||
// btnEl.click();
|
||||
//
|
||||
// expect(groupComp.chips.getChipsItems()).toEqual(modelValue);
|
||||
// expect(groupComp.formCollapsed).toEqual(observableOf(true));
|
||||
// });
|
||||
//
|
||||
// it('should clear form inputs', () => {
|
||||
// control1.setValue('test author');
|
||||
// (model1 as any).value = new FormFieldMetadataValueObject('test author');
|
||||
// control2.setValue('test affiliation');
|
||||
// (model2 as any).value = new FormFieldMetadataValueObject('test affiliation');
|
||||
//
|
||||
// groupFixture.detectChanges();
|
||||
//
|
||||
// const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
|
||||
// const btnEl = buttons[2];
|
||||
// btnEl.click();
|
||||
//
|
||||
// expect(control1.value).toBeNull();
|
||||
// expect(control2.value).toBeNull();
|
||||
// expect(groupComp.formCollapsed).toEqual(observableOf(false));
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// describe('when init model value is not empty', () => {
|
||||
// beforeEach(() => {
|
||||
//
|
||||
// groupFixture = TestBed.createComponent(DsDynamicGroupComponent);
|
||||
// groupComp = groupFixture.componentInstance; // FormComponent test instance
|
||||
// groupComp.formId = 'testForm';
|
||||
// groupComp.group = FORM_GROUP_TEST_GROUP;
|
||||
// groupComp.model = new DynamicGroupModel(FORM_GROUP_TEST_MODEL_CONFIG);
|
||||
// modelValue = [{
|
||||
// 'dc.contributor.author': new FormFieldMetadataValueObject('test author'),
|
||||
// 'local.contributor.affiliation': new FormFieldMetadataValueObject('test affiliation')
|
||||
// }];
|
||||
// groupComp.model.value = modelValue;
|
||||
// groupComp.showErrorMessages = false;
|
||||
// groupFixture.detectChanges();
|
||||
//
|
||||
// });
|
||||
//
|
||||
// afterEach(() => {
|
||||
// groupFixture.destroy();
|
||||
// groupComp = null;
|
||||
// });
|
||||
//
|
||||
// it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => {
|
||||
// const formConfig = {rows: groupComp.model.formConfiguration} as SubmissionFormsModel;
|
||||
// const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
|
||||
// const chips = new Chips(modelValue, 'value', 'dc.contributor.author');
|
||||
//
|
||||
// expect(groupComp.formCollapsed).toEqual(observableOf(true));
|
||||
// expect(groupComp.formModel.length).toEqual(formModel.length);
|
||||
// expect(groupComp.chips.getChipsItems()).toEqual(chips.getChipsItems());
|
||||
// }));
|
||||
//
|
||||
// it('should modify existing chips item', inject([FormBuilderService], (service: FormBuilderService) => {
|
||||
// groupComp.onChipSelected(0);
|
||||
// groupFixture.detectChanges();
|
||||
//
|
||||
// control1 = service.getFormControlById('dc_contributor_author', (groupComp as any).formRef.formGroup, groupComp.formModel) as FormControl;
|
||||
// model1 = service.findById('dc_contributor_author', groupComp.formModel) as DsDynamicInputModel;
|
||||
//
|
||||
// control1.setValue('test author modify');
|
||||
// (model1 as any).value = new FormFieldMetadataValueObject('test author modify');
|
||||
//
|
||||
// modelValue = [{
|
||||
// 'dc.contributor.author': new FormFieldMetadataValueObject('test author modify'),
|
||||
// 'local.contributor.affiliation': new FormFieldMetadataValueObject('test affiliation')
|
||||
// }];
|
||||
// groupFixture.detectChanges();
|
||||
//
|
||||
// const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
|
||||
// const btnEl = buttons[0];
|
||||
// btnEl.click();
|
||||
//
|
||||
// groupFixture.detectChanges();
|
||||
//
|
||||
// expect(groupComp.chips.getChipsItems()).toEqual(modelValue);
|
||||
// expect(groupComp.formCollapsed).toEqual(observableOf(true));
|
||||
// }));
|
||||
//
|
||||
// it('should delete existing chips item', () => {
|
||||
// groupComp.onChipSelected(0);
|
||||
// groupFixture.detectChanges();
|
||||
//
|
||||
// const buttons = groupFixture.debugElement.nativeElement.querySelectorAll('button');
|
||||
// const btnEl = buttons[1];
|
||||
// btnEl.click();
|
||||
//
|
||||
// expect(groupComp.chips.getChipsItems()).toEqual([]);
|
||||
// expect(groupComp.formCollapsed).toEqual(observableOf(false));
|
||||
// });
|
||||
});
|
||||
});
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import {of as observableOf, Observable , Subscription } from 'rxjs';
|
||||
import { of as observableOf, Subscription } from 'rxjs';
|
||||
import {
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
@@ -10,7 +10,14 @@ import {
|
||||
Output,
|
||||
ViewChild
|
||||
} from '@angular/core';
|
||||
import { DynamicFormControlModel, DynamicFormGroupModel, DynamicInputModel } from '@ng-dynamic-forms/core';
|
||||
import {
|
||||
DynamicFormControlComponent,
|
||||
DynamicFormControlModel,
|
||||
DynamicFormGroupModel,
|
||||
DynamicFormLayoutService,
|
||||
DynamicFormValidationService,
|
||||
DynamicInputModel
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { isEqual } from 'lodash';
|
||||
|
||||
import { DynamicGroupModel, PLACEHOLDER_PARENT_METADATA } from './dynamic-group.model';
|
||||
@@ -26,8 +33,6 @@ import { GlobalConfig } from '../../../../../../../config/global-config.interfac
|
||||
import { GLOBAL_CONFIG } from '../../../../../../../config';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
import { hasOnlyEmptyProperties } from '../../../../../object.util';
|
||||
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
|
||||
import { AuthorityValueModel } from '../../../../../../core/integration/models/authority-value.model';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-dynamic-group',
|
||||
@@ -35,12 +40,12 @@ import { AuthorityValueModel } from '../../../../../../core/integration/models/a
|
||||
templateUrl: './dynamic-group.component.html',
|
||||
animations: [shrinkInOut]
|
||||
})
|
||||
export class DsDynamicGroupComponent implements OnDestroy, OnInit {
|
||||
export class DsDynamicGroupComponent extends DynamicFormControlComponent implements OnDestroy, OnInit {
|
||||
|
||||
@Input() formId: string;
|
||||
@Input() group: FormGroup;
|
||||
@Input() model: DynamicGroupModel;
|
||||
@Input() showErrorMessages = false;
|
||||
// @Input() showErrorMessages = false;
|
||||
|
||||
@Output() blur: EventEmitter<any> = new EventEmitter<any>();
|
||||
@Output() change: EventEmitter<any> = new EventEmitter<any>();
|
||||
@@ -59,11 +64,16 @@ export class DsDynamicGroupComponent implements OnDestroy, OnInit {
|
||||
constructor(@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
|
||||
private formBuilderService: FormBuilderService,
|
||||
private formService: FormService,
|
||||
private cdr: ChangeDetectorRef) {
|
||||
private cdr: ChangeDetectorRef,
|
||||
protected layoutService: DynamicFormLayoutService,
|
||||
protected validationService: DynamicFormValidationService
|
||||
) {
|
||||
super(layoutService, validationService);
|
||||
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
const config = {rows: this.model.formConfiguration} as SubmissionFormsModel;
|
||||
const config = { rows: this.model.formConfiguration } as SubmissionFormsModel;
|
||||
if (!this.model.isEmpty()) {
|
||||
this.formCollapsed = observableOf(true);
|
||||
}
|
||||
|
@@ -9,7 +9,12 @@ import { DsDynamicListComponent } from './dynamic-list.component';
|
||||
import { DynamicListCheckboxGroupModel } from './dynamic-list-checkbox-group.model';
|
||||
import { AuthorityOptions } from '../../../../../../core/integration/models/authority-options.model';
|
||||
import { FormBuilderService } from '../../../form-builder.service';
|
||||
import { DynamicFormControlLayout, DynamicFormsCoreModule, DynamicFormValidationService } from '@ng-dynamic-forms/core';
|
||||
import {
|
||||
DynamicFormControlLayout,
|
||||
DynamicFormLayoutService,
|
||||
DynamicFormsCoreModule,
|
||||
DynamicFormValidationService
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap';
|
||||
import { AuthorityService } from '../../../../../../core/integration/authority.service';
|
||||
import { AuthorityServiceStub } from '../../../../../testing/authority-service-stub';
|
||||
@@ -90,12 +95,13 @@ describe('DsDynamicListComponent test suite', () => {
|
||||
TestComponent,
|
||||
], // declare the test component
|
||||
providers: [
|
||||
AuthorityService,
|
||||
ChangeDetectorRef,
|
||||
DsDynamicListComponent,
|
||||
DynamicFormValidationService,
|
||||
FormBuilderService,
|
||||
{provide: AuthorityService, useValue: authorityServiceStub},
|
||||
{provide: DynamicFormLayoutService, useValue: {}},
|
||||
{provide: DynamicFormValidationService, useValue: {}}
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
});
|
||||
@@ -110,7 +116,6 @@ describe('DsDynamicListComponent test suite', () => {
|
||||
[bindId]="bindId"
|
||||
[group]="group"
|
||||
[model]="model"
|
||||
[showErrorMessages]="showErrorMessages"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"></ds-dynamic-list>`;
|
||||
|
@@ -7,7 +7,11 @@ import { IntegrationSearchOptions } from '../../../../../../core/integration/mod
|
||||
import { hasValue, isNotEmpty } from '../../../../../empty.util';
|
||||
import { DynamicListCheckboxGroupModel } from './dynamic-list-checkbox-group.model';
|
||||
import { FormBuilderService } from '../../../form-builder.service';
|
||||
import { DynamicCheckboxModel } from '@ng-dynamic-forms/core';
|
||||
import {
|
||||
DynamicCheckboxModel,
|
||||
DynamicFormControlComponent, DynamicFormLayoutService,
|
||||
DynamicFormValidationService
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { AuthorityValueModel } from '../../../../../../core/integration/models/authority-value.model';
|
||||
import { DynamicListRadioGroupModel } from './dynamic-list-radio-group.model';
|
||||
import { IntegrationData } from '../../../../../../core/integration/integration-data';
|
||||
@@ -25,11 +29,11 @@ export interface ListItem {
|
||||
templateUrl: './dynamic-list.component.html'
|
||||
})
|
||||
|
||||
export class DsDynamicListComponent implements OnInit {
|
||||
export class DsDynamicListComponent extends DynamicFormControlComponent implements OnInit {
|
||||
@Input() bindId = true;
|
||||
@Input() group: FormGroup;
|
||||
@Input() model: DynamicListCheckboxGroupModel | DynamicListRadioGroupModel;
|
||||
@Input() showErrorMessages = false;
|
||||
// @Input() showErrorMessages = false;
|
||||
|
||||
@Output() blur: EventEmitter<any> = new EventEmitter<any>();
|
||||
@Output() change: EventEmitter<any> = new EventEmitter<any>();
|
||||
@@ -41,7 +45,11 @@ export class DsDynamicListComponent implements OnInit {
|
||||
|
||||
constructor(private authorityService: AuthorityService,
|
||||
private cdr: ChangeDetectorRef,
|
||||
private formBuilderService: FormBuilderService) {
|
||||
private formBuilderService: FormBuilderService,
|
||||
protected layoutService: DynamicFormLayoutService,
|
||||
protected validationService: DynamicFormValidationService
|
||||
) {
|
||||
super(layoutService, validationService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
@@ -110,7 +118,10 @@ export class DsDynamicListComponent implements OnInit {
|
||||
if (this.model.repeatable) {
|
||||
this.formBuilderService.addFormGroupControl(listGroup, (this.model as DynamicListCheckboxGroupModel), new DynamicCheckboxModel(item));
|
||||
} else {
|
||||
(this.model as DynamicListRadioGroupModel).options.push({label: item.label, value: option});
|
||||
(this.model as DynamicListRadioGroupModel).options.push({
|
||||
label: item.label,
|
||||
value: option
|
||||
});
|
||||
}
|
||||
tempList.push(item);
|
||||
itemsPerGroup++;
|
||||
|
@@ -6,7 +6,11 @@ import { async, ComponentFixture, fakeAsync, inject, TestBed, tick, } from '@ang
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
import { AuthorityOptions } from '../../../../../../core/integration/models/authority-options.model';
|
||||
import { DynamicFormsCoreModule, DynamicFormValidationService } from '@ng-dynamic-forms/core';
|
||||
import {
|
||||
DynamicFormLayoutService,
|
||||
DynamicFormsCoreModule,
|
||||
DynamicFormValidationService
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap';
|
||||
import { AuthorityService } from '../../../../../../core/integration/authority.service';
|
||||
import { AuthorityServiceStub } from '../../../../../testing/authority-service-stub';
|
||||
@@ -102,11 +106,9 @@ describe('Dynamic Lookup component', () => {
|
||||
providers: [
|
||||
ChangeDetectorRef,
|
||||
DsDynamicLookupComponent,
|
||||
DynamicFormValidationService,
|
||||
FormBuilderService,
|
||||
FormComponent,
|
||||
FormService,
|
||||
{provide: AuthorityService, useValue: authorityServiceStub},
|
||||
{provide: DynamicFormLayoutService, useValue: {}},
|
||||
{provide: DynamicFormValidationService, useValue: {}}
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
});
|
||||
@@ -121,7 +123,6 @@ describe('Dynamic Lookup component', () => {
|
||||
[bindId]="bindId"
|
||||
[group]="group"
|
||||
[model]="model"
|
||||
[showErrorMessages]="showErrorMessages"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"></ds-dynamic-lookup>`;
|
||||
|
@@ -13,17 +13,22 @@ import { Subscription } from 'rxjs';
|
||||
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
|
||||
import { AuthorityValueModel } from '../../../../../../core/integration/models/authority-value.model';
|
||||
import { DynamicLookupNameModel } from './dynamic-lookup-name.model';
|
||||
import {
|
||||
DynamicFormControlComponent,
|
||||
DynamicFormLayoutService,
|
||||
DynamicFormValidationService
|
||||
} from '@ng-dynamic-forms/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-dynamic-lookup',
|
||||
styleUrls: ['./dynamic-lookup.component.scss'],
|
||||
templateUrl: './dynamic-lookup.component.html'
|
||||
})
|
||||
export class DsDynamicLookupComponent implements OnDestroy, OnInit {
|
||||
export class DsDynamicLookupComponent extends DynamicFormControlComponent implements OnDestroy, OnInit {
|
||||
@Input() bindId = true;
|
||||
@Input() group: FormGroup;
|
||||
@Input() model: DynamicLookupModel | DynamicLookupNameModel;
|
||||
@Input() showErrorMessages = false;
|
||||
// @Input() showErrorMessages = false;
|
||||
|
||||
@Output() blur: EventEmitter<any> = new EventEmitter<any>();
|
||||
@Output() change: EventEmitter<any> = new EventEmitter<any>();
|
||||
@@ -39,7 +44,11 @@ export class DsDynamicLookupComponent implements OnDestroy, OnInit {
|
||||
protected sub: Subscription;
|
||||
|
||||
constructor(private authorityService: AuthorityService,
|
||||
private cdr: ChangeDetectorRef) {
|
||||
private cdr: ChangeDetectorRef,
|
||||
protected layoutService: DynamicFormLayoutService,
|
||||
protected validationService: DynamicFormValidationService
|
||||
) {
|
||||
super(layoutService, validationService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
@@ -6,7 +6,11 @@ import { async, ComponentFixture, fakeAsync, inject, TestBed, tick, } from '@ang
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
import { AuthorityOptions } from '../../../../../../core/integration/models/authority-options.model';
|
||||
import { DynamicFormsCoreModule } from '@ng-dynamic-forms/core';
|
||||
import {
|
||||
DynamicFormLayoutService,
|
||||
DynamicFormsCoreModule,
|
||||
DynamicFormValidationService
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap';
|
||||
import { AuthorityService } from '../../../../../../core/integration/authority.service';
|
||||
import { AuthorityServiceStub } from '../../../../../testing/authority-service-stub';
|
||||
@@ -77,6 +81,8 @@ describe('Dynamic Dynamic Scrollable Dropdown component', () => {
|
||||
ChangeDetectorRef,
|
||||
DsDynamicScrollableDropdownComponent,
|
||||
{provide: AuthorityService, useValue: authorityServiceStub},
|
||||
{provide: DynamicFormLayoutService, useValue: {}},
|
||||
{provide: DynamicFormValidationService, useValue: {}}
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
});
|
||||
@@ -90,7 +96,6 @@ describe('Dynamic Dynamic Scrollable Dropdown component', () => {
|
||||
<ds-dynamic-scrollable-dropdown [bindId]="bindId"
|
||||
[group]="group"
|
||||
[model]="model"
|
||||
[showErrorMessages]="showErrorMessages"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"></ds-dynamic-scrollable-dropdown>`;
|
||||
|
@@ -11,17 +11,22 @@ import { IntegrationSearchOptions } from '../../../../../../core/integration/mod
|
||||
import { IntegrationData } from '../../../../../../core/integration/integration-data';
|
||||
import { AuthorityValueModel } from '../../../../../../core/integration/models/authority-value.model';
|
||||
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap';
|
||||
import {
|
||||
DynamicFormControlComponent,
|
||||
DynamicFormLayoutService,
|
||||
DynamicFormValidationService
|
||||
} from '@ng-dynamic-forms/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-dynamic-scrollable-dropdown',
|
||||
styleUrls: ['./dynamic-scrollable-dropdown.component.scss'],
|
||||
templateUrl: './dynamic-scrollable-dropdown.component.html'
|
||||
})
|
||||
export class DsDynamicScrollableDropdownComponent implements OnInit {
|
||||
export class DsDynamicScrollableDropdownComponent extends DynamicFormControlComponent implements OnInit {
|
||||
@Input() bindId = true;
|
||||
@Input() group: FormGroup;
|
||||
@Input() model: DynamicScrollableDropdownModel;
|
||||
@Input() showErrorMessages = false;
|
||||
// @Input() showErrorMessages = false;
|
||||
|
||||
@Output() blur: EventEmitter<any> = new EventEmitter<any>();
|
||||
@Output() change: EventEmitter<any> = new EventEmitter<any>();
|
||||
@@ -33,7 +38,13 @@ export class DsDynamicScrollableDropdownComponent implements OnInit {
|
||||
|
||||
protected searchOptions: IntegrationSearchOptions;
|
||||
|
||||
constructor(private authorityService: AuthorityService, private cdr: ChangeDetectorRef) {}
|
||||
constructor(private authorityService: AuthorityService,
|
||||
private cdr: ChangeDetectorRef,
|
||||
protected layoutService: DynamicFormLayoutService,
|
||||
protected validationService: DynamicFormValidationService
|
||||
) {
|
||||
super(layoutService, validationService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.searchOptions = new IntegrationSearchOptions(
|
||||
|
@@ -4,7 +4,11 @@ import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angul
|
||||
import { async, ComponentFixture, fakeAsync, flush, inject, TestBed, } from '@angular/core/testing';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
|
||||
import { DynamicFormsCoreModule } from '@ng-dynamic-forms/core';
|
||||
import {
|
||||
DynamicFormLayoutService,
|
||||
DynamicFormsCoreModule,
|
||||
DynamicFormValidationService
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap';
|
||||
import { NgbModule, NgbTypeaheadSelectItemEvent } from '@ng-bootstrap/ng-bootstrap';
|
||||
|
||||
@@ -86,6 +90,8 @@ describe('DsDynamicTagComponent test suite', () => {
|
||||
DsDynamicTagComponent,
|
||||
{provide: AuthorityService, useValue: authorityServiceStub},
|
||||
{provide: GLOBAL_CONFIG, useValue: {} as GlobalConfig},
|
||||
{provide: DynamicFormLayoutService, useValue: {}},
|
||||
{provide: DynamicFormValidationService, useValue: {}}
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
});
|
||||
@@ -99,7 +105,6 @@ describe('DsDynamicTagComponent test suite', () => {
|
||||
<ds-dynamic-tag [bindId]="bindId"
|
||||
[group]="group"
|
||||
[model]="model"
|
||||
[showErrorMessages]="showErrorMessages"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"></ds-dynamic-tag>`;
|
||||
|
@@ -14,17 +14,22 @@ import { hasValue, isNotEmpty } from '../../../../../empty.util';
|
||||
import { isEqual } from 'lodash';
|
||||
import { GlobalConfig } from '../../../../../../../config/global-config.interface';
|
||||
import { GLOBAL_CONFIG } from '../../../../../../../config';
|
||||
import {
|
||||
DynamicFormControlComponent,
|
||||
DynamicFormLayoutService,
|
||||
DynamicFormValidationService
|
||||
} from '@ng-dynamic-forms/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-dynamic-tag',
|
||||
styleUrls: ['./dynamic-tag.component.scss'],
|
||||
templateUrl: './dynamic-tag.component.html'
|
||||
})
|
||||
export class DsDynamicTagComponent implements OnInit {
|
||||
export class DsDynamicTagComponent extends DynamicFormControlComponent implements OnInit {
|
||||
@Input() bindId = true;
|
||||
@Input() group: FormGroup;
|
||||
@Input() model: DynamicTagModel;
|
||||
@Input() showErrorMessages = false;
|
||||
// @Input() showErrorMessages = false;
|
||||
|
||||
@Output() blur: EventEmitter<any> = new EventEmitter<any>();
|
||||
@Output() change: EventEmitter<any> = new EventEmitter<any>();
|
||||
@@ -72,7 +77,11 @@ export class DsDynamicTagComponent implements OnInit {
|
||||
|
||||
constructor(@Inject(GLOBAL_CONFIG) protected EnvConfig: GlobalConfig,
|
||||
private authorityService: AuthorityService,
|
||||
private cdr: ChangeDetectorRef) {
|
||||
private cdr: ChangeDetectorRef,
|
||||
protected layoutService: DynamicFormLayoutService,
|
||||
protected validationService: DynamicFormValidationService
|
||||
) {
|
||||
super(layoutService, validationService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
@@ -4,10 +4,13 @@ import { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angul
|
||||
import { async, ComponentFixture, fakeAsync, inject, TestBed, } from '@angular/core/testing';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import 'rxjs/add/observable/of';
|
||||
|
||||
import { AuthorityOptions } from '../../../../../../core/integration/models/authority-options.model';
|
||||
import { DynamicFormsCoreModule } from '@ng-dynamic-forms/core';
|
||||
import {
|
||||
DynamicFormLayoutService,
|
||||
DynamicFormsCoreModule,
|
||||
DynamicFormValidationService
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { DynamicFormsNGBootstrapUIModule } from '@ng-dynamic-forms/ui-ng-bootstrap';
|
||||
import { AuthorityService } from '../../../../../../core/integration/authority.service';
|
||||
import { AuthorityServiceStub } from '../../../../../testing/authority-service-stub';
|
||||
@@ -70,7 +73,8 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
|
||||
ChangeDetectorRef,
|
||||
DsDynamicTypeaheadComponent,
|
||||
{provide: AuthorityService, useValue: authorityServiceStub},
|
||||
{provide: GLOBAL_CONFIG, useValue: {} as GlobalConfig},
|
||||
{provide: DynamicFormLayoutService, useValue: {}},
|
||||
{provide: DynamicFormValidationService, useValue: {}}
|
||||
],
|
||||
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
||||
});
|
||||
@@ -84,7 +88,6 @@ describe('DsDynamicTypeaheadComponent test suite', () => {
|
||||
<ds-dynamic-typeahead [bindId]="bindId"
|
||||
[group]="group"
|
||||
[model]="model"
|
||||
[showErrorMessages]="showErrorMessages"
|
||||
(blur)="onBlur($event)"
|
||||
(change)="onValueChange($event)"
|
||||
(focus)="onFocus($event)"></ds-dynamic-typeahead>`;
|
||||
|
@@ -11,13 +11,18 @@ import { DynamicTypeaheadModel } from './dynamic-typeahead.model';
|
||||
import { IntegrationSearchOptions } from '../../../../../../core/integration/models/integration-options.model';
|
||||
import { isEmpty, isNotEmpty } from '../../../../../empty.util';
|
||||
import { FormFieldMetadataValueObject } from '../../../models/form-field-metadata-value.model';
|
||||
import {
|
||||
DynamicFormControlComponent,
|
||||
DynamicFormLayoutService,
|
||||
DynamicFormValidationService
|
||||
} from '@ng-dynamic-forms/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-dynamic-typeahead',
|
||||
styleUrls: ['./dynamic-typeahead.component.scss'],
|
||||
templateUrl: './dynamic-typeahead.component.html'
|
||||
})
|
||||
export class DsDynamicTypeaheadComponent implements OnInit {
|
||||
export class DsDynamicTypeaheadComponent extends DynamicFormControlComponent implements OnInit {
|
||||
@Input() bindId = true;
|
||||
@Input() group: FormGroup;
|
||||
@Input() model: DynamicTypeaheadModel;
|
||||
@@ -67,7 +72,12 @@ export class DsDynamicTypeaheadComponent implements OnInit {
|
||||
tap(() => this.changeSearchingStatus(false)),
|
||||
merge(this.hideSearchingWhenUnsubscribed),);
|
||||
|
||||
constructor(private authorityService: AuthorityService, private cdr: ChangeDetectorRef) {
|
||||
constructor(private authorityService: AuthorityService,
|
||||
private cdr: ChangeDetectorRef,
|
||||
protected layoutService: DynamicFormLayoutService,
|
||||
protected validationService: DynamicFormValidationService
|
||||
) {
|
||||
super(layoutService, validationService);
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
@@ -49,6 +49,7 @@ import { FormFieldMetadataValueObject } from './models/form-field-metadata-value
|
||||
import { DynamicConcatModel } from './ds-dynamic-form-ui/models/ds-dynamic-concat.model';
|
||||
import { DynamicLookupNameModel } from './ds-dynamic-form-ui/models/lookup/dynamic-lookup-name.model';
|
||||
import { DynamicRowArrayModel } from './ds-dynamic-form-ui/models/ds-dynamic-row-array-model';
|
||||
import { getMockFormBuilderService } from '../../mocks/mock-form-builder-service';
|
||||
|
||||
describe('FormBuilderService test suite', () => {
|
||||
|
||||
@@ -69,9 +70,7 @@ describe('FormBuilderService test suite', () => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ReactiveFormsModule],
|
||||
providers: [
|
||||
FormBuilderService,
|
||||
DynamicFormService,
|
||||
DynamicFormValidationService,
|
||||
{provide: FormBuilderService, useValue: getMockFormBuilderService()},
|
||||
{provide: NG_VALIDATORS, useValue: testValidator, multi: true},
|
||||
{provide: NG_ASYNC_VALIDATORS, useValue: testAsyncValidator, multi: true}
|
||||
]
|
||||
|
@@ -3,15 +3,14 @@ import { async, ComponentFixture, inject, TestBed, } from '@angular/core/testing
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
import 'rxjs/add/observable/of';
|
||||
import {
|
||||
DynamicFormArrayModel,
|
||||
DynamicFormControlEvent,
|
||||
DynamicFormControlModel,
|
||||
DynamicFormValidationService,
|
||||
DynamicInputModel
|
||||
} from '@ng-dynamic-forms/core';
|
||||
import { Store } from '@ngrx/store';
|
||||
import { ActionsSubject, Store } from '@ngrx/store';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
@@ -19,11 +18,12 @@ import { FormComponent } from './form.component';
|
||||
import { FormService } from './form.service';
|
||||
import { FormBuilderService } from './builder/form-builder.service';
|
||||
import { FormState } from './form.reducer';
|
||||
import { FormChangeAction, FormStatusChangeAction } from './form.actions';
|
||||
import { MockStore } from '../testing/mock-store';
|
||||
import { FormAddError, FormChangeAction, FormStatusChangeAction } from './form.actions';
|
||||
import { FormFieldMetadataValueObject } from './builder/models/form-field-metadata-value.model';
|
||||
import { GLOBAL_CONFIG } from '../../../config';
|
||||
import { createTestComponent } from '../testing/utils';
|
||||
import { getMockFormService } from '../mocks/mock-form-service';
|
||||
import { getMockFormBuilderService } from '../mocks/mock-form-builder-service';
|
||||
|
||||
export const TEST_FORM_MODEL = [
|
||||
|
||||
@@ -93,7 +93,7 @@ export const TEST_FORM_MODEL_WITH_ARRAY = [
|
||||
})
|
||||
];
|
||||
|
||||
describe('FormComponent test suite', () => {
|
||||
fdescribe('FormComponent test suite', () => {
|
||||
let testComp: TestComponent;
|
||||
let formComp: FormComponent;
|
||||
let testFixture: ComponentFixture<TestComponent>;
|
||||
@@ -122,7 +122,7 @@ describe('FormComponent test suite', () => {
|
||||
};
|
||||
let html;
|
||||
|
||||
const store: MockStore<FormState> = new MockStore<FormState>(formState);
|
||||
const store = new Store<FormState>(observableOf({}), new ActionsSubject(), undefined);
|
||||
|
||||
// async beforeEach
|
||||
beforeEach(async(() => {
|
||||
@@ -142,10 +142,9 @@ describe('FormComponent test suite', () => {
|
||||
], // declare the test component
|
||||
providers: [
|
||||
ChangeDetectorRef,
|
||||
DynamicFormValidationService,
|
||||
FormBuilderService,
|
||||
{provide: FormBuilderService, useValue: getMockFormBuilderService()},
|
||||
FormComponent,
|
||||
FormService,
|
||||
{provide: FormService, useValue: getMockFormService()},
|
||||
{provide: GLOBAL_CONFIG, useValue: config},
|
||||
{
|
||||
provide: Store, useValue: store
|
||||
@@ -200,18 +199,17 @@ describe('FormComponent test suite', () => {
|
||||
|
||||
});
|
||||
|
||||
it('should display form errors when errors are added to the state', () => {
|
||||
const errors = [{
|
||||
fit('should display form errors when errors are added to the state', () => {
|
||||
const error = {
|
||||
fieldId: 'dc_title',
|
||||
fieldIndex: 0,
|
||||
message: 'error.validation.required'
|
||||
}];
|
||||
};
|
||||
|
||||
formState.testForm.errors = errors;
|
||||
store.nextState(formState);
|
||||
store.dispatch(new FormAddError(formComp.formId, error.fieldId, error.fieldIndex, error.message));
|
||||
formFixture.detectChanges();
|
||||
|
||||
expect((formComp as any).formErrors).toEqual(errors);
|
||||
expect((formComp as any).formErrors[0]).toEqual(error);
|
||||
|
||||
});
|
||||
|
||||
|
@@ -30,6 +30,7 @@ export interface FormState {
|
||||
const initialState: FormState = Object.create(null);
|
||||
|
||||
export function formReducer(state = initialState, action: FormAction): FormState {
|
||||
console.log('TEST');
|
||||
switch (action.type) {
|
||||
|
||||
case FormActionTypes.FORM_INIT: {
|
||||
@@ -67,6 +68,7 @@ export function formReducer(state = initialState, action: FormAction): FormState
|
||||
}
|
||||
|
||||
function addFormErrors(state: FormState, action: FormAddError) {
|
||||
console.log(state);
|
||||
const formId = action.payload.formId;
|
||||
if (hasValue(state[formId])) {
|
||||
const error: FormError = {
|
||||
|
@@ -3,7 +3,8 @@ import { async, inject, TestBed } from '@angular/core/testing';
|
||||
import { FormGroup } from '@angular/forms';
|
||||
|
||||
import {
|
||||
DynamicFormControlModel, DynamicFormGroupModel,
|
||||
DynamicFormControlModel,
|
||||
DynamicFormGroupModel,
|
||||
DynamicFormService,
|
||||
DynamicFormValidationService,
|
||||
DynamicInputModel
|
||||
@@ -13,7 +14,7 @@ import { FormService } from './form.service';
|
||||
import { FormBuilderService } from './builder/form-builder.service';
|
||||
import { AppState } from '../../app.reducer';
|
||||
import { formReducer } from './form.reducer';
|
||||
import { GlobalConfig } from '../../../config/global-config.interface';
|
||||
import { getMockFormBuilderService } from '../mocks/mock-form-builder-service';
|
||||
|
||||
describe('FormService test suite', () => {
|
||||
const config = {
|
||||
@@ -93,9 +94,7 @@ describe('FormService test suite', () => {
|
||||
StoreModule.forRoot({formReducer})
|
||||
],
|
||||
providers: [
|
||||
DynamicFormService,
|
||||
DynamicFormValidationService,
|
||||
FormBuilderService,
|
||||
{provide: FormBuilderService, useValue: getMockFormBuilderService()},
|
||||
]
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
18
src/app/shared/mocks/mock-form-builder-service.ts
Normal file
18
src/app/shared/mocks/mock-form-builder-service.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { FormBuilderService } from '../form/builder/form-builder.service';
|
||||
import { FormControl, FormGroup } from '@angular/forms';
|
||||
|
||||
export function getMockFormBuilderService(): FormBuilderService {
|
||||
return jasmine.createSpyObj('FormService', {
|
||||
modelFromConfiguration: [],
|
||||
createFormGroup: new FormGroup({}),
|
||||
getValueFromModel: {},
|
||||
getFormControlById: new FormControl(),
|
||||
findById: {},
|
||||
getPath: ['test', 'path'],
|
||||
clearAllModelsValue : {},
|
||||
insertFormArrayGroup: {},
|
||||
isQualdrop: false
|
||||
|
||||
});
|
||||
|
||||
}
|
12
src/app/shared/mocks/mock-form-service.ts
Normal file
12
src/app/shared/mocks/mock-form-service.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import { FormService } from '../form/form.service';
|
||||
|
||||
export function getMockFormService(
|
||||
id$: string = 'random_id'
|
||||
): FormService {
|
||||
return jasmine.createSpyObj('FormService', {
|
||||
getUniqueId: id$,
|
||||
resetForm: {},
|
||||
validateAllFormFields: {}
|
||||
});
|
||||
|
||||
}
|
@@ -1,15 +1,4 @@
|
||||
import { Store } from '@ngrx/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
|
||||
|
||||
export function getMockStore<T>(): Store<T> {
|
||||
return jasmine.createSpyObj('store', [
|
||||
'select',
|
||||
'dispatch',
|
||||
'lift',
|
||||
'next',
|
||||
'error',
|
||||
'complete',
|
||||
'addReducer',
|
||||
'removeReducer'
|
||||
]);
|
||||
}
|
||||
|
@@ -5,7 +5,6 @@ import { NotificationComponent } from './notification/notification.component';
|
||||
import { Store, StoreModule } from '@ngrx/store';
|
||||
import { notificationsReducer } from './notifications.reducers';
|
||||
import { of as observableOf } from 'rxjs';
|
||||
import 'rxjs/add/observable/of';
|
||||
import {
|
||||
NewNotificationAction,
|
||||
RemoveAllNotificationsAction,
|
||||
|
@@ -156,7 +156,6 @@ class TestComponent {
|
||||
public max = 100;
|
||||
public min = 0;
|
||||
public initValue = 0;
|
||||
public showErrorMessages = false;
|
||||
public size = 4;
|
||||
public value;
|
||||
|
||||
|
@@ -22,7 +22,7 @@ const ENV = process.env.ENV = process.env.NODE_ENV = 'test';
|
||||
*/
|
||||
module.exports = function (options) {
|
||||
return {
|
||||
|
||||
mode: 'development',
|
||||
/**
|
||||
* Source map for Karma from the help of karma-sourcemap-loader & karma-webpack
|
||||
*
|
||||
|
Reference in New Issue
Block a user