Skip to content

Commit 7a063c6

Browse files
committed
[ionic] Add text for rule behavior in detail page
1 parent b72dd99 commit 7a063c6

File tree

7 files changed

+215
-20
lines changed

7 files changed

+215
-20
lines changed

packages/angular/src/jsonforms.component.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ import { JsonFormsControl } from './control';
5454
export class JsonFormsOutlet extends JsonFormsBaseRenderer implements OnInit, OnDestroy {
5555

5656
private subscription: Subscription;
57-
private componentRef: ComponentRef<any>;
57+
private currentComponentRef: ComponentRef<any>;
5858

5959
constructor(
6060
private viewContainerRef: ViewContainerRef,
@@ -100,17 +100,16 @@ export class JsonFormsOutlet extends JsonFormsBaseRenderer implements OnInit, On
100100

101101
const componentFactory =
102102
this.componentFactoryResolver.resolveComponentFactory(bestComponent);
103-
const component: ComponentRef<any> =
104-
this.viewContainerRef.createComponent(componentFactory);
105103

106-
if (this.componentRef === undefined ||
107-
this.componentRef.componentType !== component.componentType) {
104+
if (this.currentComponentRef === undefined) {
105+
this.currentComponentRef = this.viewContainerRef.createComponent(componentFactory);
106+
} else if (this.currentComponentRef.componentType !== componentFactory.componentType) {
108107
this.viewContainerRef.clear();
109-
this.componentRef = this.viewContainerRef.createComponent(componentFactory);
108+
this.currentComponentRef = this.viewContainerRef.createComponent(componentFactory);
110109
}
111110

112-
if (this.componentRef.instance instanceof JsonFormsBaseRenderer) {
113-
const instance = (this.componentRef.instance as JsonFormsBaseRenderer);
111+
if (this.currentComponentRef.instance instanceof JsonFormsBaseRenderer) {
112+
const instance = (this.currentComponentRef.instance as JsonFormsBaseRenderer);
114113
instance.uischema = uischema;
115114
instance.schema = schema;
116115
instance.path = this.path;

packages/core/src/util/renderer.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -306,17 +306,17 @@ export interface ControlState {
306306
export const mapStateToControlProps =
307307
(state: JsonFormsState, ownProps: OwnPropsOfControl): StatePropsOfControl => {
308308
const { uischema } = ownProps;
309-
const path = composeWithUi(ownProps.uischema, ownProps.path);
310-
const rulePath = _.has(ownProps.uischema, 'rule')
309+
const path = composeWithUi(uischema, ownProps.path);
310+
const rulePath = _.has(uischema, 'rule')
311311
&& composeWithUi(uischema.rule.condition, ownProps.path);
312312
const visible = _.has(ownProps, 'visible') ?
313313
ownProps.visible : isVisible(ownProps, state, rulePath);
314314
const enabled = _.has(ownProps, 'enabled') ?
315315
ownProps.enabled : isEnabled(ownProps, state, rulePath);
316-
const labelDesc = createLabelDescriptionFrom(ownProps.uischema);
316+
const labelDesc = createLabelDescriptionFrom(uischema);
317317
const label = labelDesc.show ? labelDesc.text : '';
318318
const errors = _.union(getErrorAt(path)(state).map(error => error.message));
319-
const controlElement = ownProps.uischema as ControlElement;
319+
const controlElement = uischema as ControlElement;
320320
const id = ownProps.id;
321321
const required =
322322
controlElement.scope !== undefined && isRequired(ownProps.schema, controlElement.scope);

packages/core/src/util/runtime.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ const isConditionFulfilled =
6767
const condition = uischema.rule.condition;
6868

6969
if (isLeafCondition(condition)) {
70-
const value = resolveData(data, toDataPath(condition.scope));
70+
const value = resolveData(data, conditionScope);
7171
return value === condition.expectedValue;
7272
} else if (isSchemaCondition(condition)) {
7373
const value = resolveData(data, conditionScope);

packages/ionic/src/layouts/JsonFormsIonicLayout.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ export class JsonFormsIonicLayout extends JsonFormsBaseRenderer implements OnIni
3535
}
3636

3737
ngOnDestroy() {
38-
this.subscription.unsubscribe();
38+
if (this.subscription) {
39+
this.subscription.unsubscribe();
40+
}
3941
}
4042
}

packages/ionic/src/layouts/group/group-layout.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {
2-
GroupLayout, JsonFormsProps,
2+
GroupLayout,
3+
JsonFormsProps,
34
JsonFormsState,
45
RankedTester,
56
rankWith,

packages/ionic/src/other/master-detail/master-detail.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ import { MasterDetailNavService } from './master-detail-nav.service';
2020
import { MasterPage } from './pages/master/master';
2121
import { DetailPage } from './pages/detail/detail';
2222
import { removeSchemaKeywords } from '../../common';
23-
import { map } from 'rxjs/operators/map';
2423

2524
export interface MasterItem {
2625
label: string;
@@ -67,10 +66,8 @@ export class MasterDetailComponent extends JsonFormsControl {
6766

6867
this.subscription = this.ngRedux
6968
.select()
70-
.pipe(
71-
map((s: JsonFormsState) => this.mapToProps(s))
72-
)
73-
.subscribe(({ data, schema, uischema, }) => {
69+
.subscribe((state: JsonFormsState) => {
70+
const { data, schema, uischema } = this.mapToProps(state);
7471
const controlElement = uischema as ControlElement;
7572
const instancePath = toDataPath(`${controlElement.scope}/items`);
7673
const resolvedSchema = resolveSchema(schema, `${controlElement.scope}/items`);

packages/ionic/test/detail.spec.ts

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*
2+
The MIT License
3+
4+
Copyright (c) 2018 EclipseSource Munich
5+
https://github.com/eclipsesource/jsonforms
6+
7+
Permission is hereby granted, free of charge, to any person obtaining a copy
8+
of this software and associated documentation files (the "Software"), to deal
9+
in the Software without restriction, including without limitation the rights
10+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11+
copies of the Software, and to permit persons to whom the Software is
12+
furnished to do so, subject to the following conditions:
13+
14+
The above copyright notice and this permission notice shall be included in
15+
all copies or substantial portions of the Software.
16+
17+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23+
THE SOFTWARE.
24+
*/
25+
import { By } from '@angular/platform-browser';
26+
import { NgRedux } from '@angular-redux/store';
27+
import { MockNgRedux } from '@angular-redux/store/testing';
28+
import { IonicModule, Item, NavParams, Platform, TextInput } from 'ionic-angular';
29+
import { BrowserDynamicTestingModule } from '@angular/platform-browser-dynamic/testing';
30+
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
31+
import { JsonFormsOutlet } from '@jsonforms/angular';
32+
import {
33+
StringControlRenderer,
34+
stringControlTester,
35+
VerticalLayoutRenderer,
36+
verticalLayoutTester
37+
} from '../src';
38+
import { PlatformMock, } from '../test-config/mocks-ionic';
39+
import { DetailPage } from '../src/other/master-detail/pages/detail/detail';
40+
41+
describe('Master detail', () => {
42+
43+
let fixture: ComponentFixture<any>;
44+
let component: any;
45+
46+
const data = {
47+
orders: [
48+
{
49+
customer: {
50+
name: 'ACME'
51+
},
52+
title: 'Carrots'
53+
}
54+
]
55+
};
56+
const schema = {
57+
definitions: {
58+
order: {
59+
type: 'object',
60+
properties: {
61+
customer: {
62+
type: 'object',
63+
properties: {
64+
name: { type: 'string' }
65+
}
66+
},
67+
title: {
68+
type: 'string'
69+
}
70+
}
71+
}
72+
},
73+
type: 'object',
74+
properties: {
75+
orders: {
76+
type: 'array',
77+
items: {
78+
$ref: '#/definitions/order'
79+
}
80+
}
81+
}
82+
};
83+
84+
const pageData = {
85+
addToNavStack: true,
86+
get() {
87+
return {
88+
label: 'ACME',
89+
data: {
90+
customer: {
91+
name: 'ACME'
92+
},
93+
title: 'Carrots'
94+
},
95+
path: 'orders.0',
96+
schema: schema.definitions.order,
97+
uischema: {
98+
type: 'Control',
99+
scope: '#/properties/customer/properties/name',
100+
rule: {
101+
effect: 'HIDE',
102+
condition: {
103+
scope: '#/properties/customer/properties/name',
104+
schema: {
105+
const: 'ACME'
106+
}
107+
}
108+
}
109+
}
110+
};
111+
}
112+
};
113+
114+
beforeEach(() => {
115+
TestBed.configureTestingModule({
116+
declarations: [
117+
JsonFormsOutlet,
118+
StringControlRenderer,
119+
DetailPage
120+
],
121+
imports: [IonicModule.forRoot(DetailPage)],
122+
providers: [
123+
{provide: Platform, useClass: PlatformMock},
124+
{provide: NgRedux, useFactory: MockNgRedux.getInstance},
125+
{provide: NavParams, useValue: pageData },
126+
],
127+
}).overrideModule(BrowserDynamicTestingModule, {
128+
set: {
129+
entryComponents: [StringControlRenderer]
130+
}
131+
}).compileComponents();
132+
133+
MockNgRedux.reset();
134+
fixture = TestBed.createComponent(DetailPage);
135+
component = fixture.componentInstance;
136+
});
137+
138+
it('should render detail page with inactive rule', fakeAsync(() => {
139+
const mockSubStore = MockNgRedux.getSelectorStub();
140+
141+
mockSubStore.next({
142+
jsonforms: {
143+
core: {
144+
data: {
145+
orders: [
146+
{
147+
customer: {
148+
name: 'foo'
149+
},
150+
title: 'Carrots'
151+
}
152+
]
153+
},
154+
schema: schema.definitions.order,
155+
},
156+
renderers: [
157+
{ tester: stringControlTester, renderer: StringControlRenderer },
158+
{ tester: verticalLayoutTester, renderer: VerticalLayoutRenderer }
159+
]
160+
}
161+
});
162+
mockSubStore.complete();
163+
fixture.detectChanges();
164+
tick();
165+
fixture.detectChanges();
166+
const textInputs = fixture.debugElement.queryAll(By.directive(TextInput));
167+
const items = fixture.debugElement.queryAll(By.directive(Item));
168+
expect(textInputs.length).toBe(1);
169+
expect(items[0].nativeElement.hidden).toBe(false);
170+
}));
171+
172+
it('should render detail page with active rule', fakeAsync(() => {
173+
const mockSubStore = MockNgRedux.getSelectorStub();
174+
175+
mockSubStore.next({
176+
jsonforms: {
177+
core: {
178+
data,
179+
schema: schema.definitions.order,
180+
},
181+
renderers: [
182+
{ tester: stringControlTester, renderer: StringControlRenderer },
183+
{ tester: verticalLayoutTester, renderer: VerticalLayoutRenderer }
184+
]
185+
}
186+
});
187+
mockSubStore.complete();
188+
fixture.detectChanges();
189+
tick();
190+
fixture.detectChanges();
191+
const textInputs = fixture.debugElement.queryAll(By.directive(TextInput));
192+
const items = fixture.debugElement.queryAll(By.directive(Item));
193+
expect(textInputs.length).toBe(1);
194+
expect(items[0].nativeElement.hidden).toBe(true);
195+
}));
196+
});

0 commit comments

Comments
 (0)