@memberjunction/ng-join-grid 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { AfterViewInit, ChangeDetectorRef } from '@angular/core';
|
|
2
|
+
import { BaseEntity, EntityInfo } from '@memberjunction/core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class JoinGridCell {
|
|
5
|
+
index: number;
|
|
6
|
+
RowForeignKeyValue: any;
|
|
7
|
+
ColumnForeignKeyValue: any;
|
|
8
|
+
data: BaseEntity | undefined;
|
|
9
|
+
}
|
|
10
|
+
export declare class JoinGridRow {
|
|
11
|
+
FirstColValue: any;
|
|
12
|
+
JoinExists: boolean;
|
|
13
|
+
RowForeignKeyValue: any;
|
|
14
|
+
ColumnData: JoinGridCell[];
|
|
15
|
+
}
|
|
16
|
+
export declare class JoinGridComponent implements AfterViewInit {
|
|
17
|
+
private cdr;
|
|
18
|
+
/**
|
|
19
|
+
* Required: the name of the entity that will be used for displaying data for rows. This means that each row in the RowsEntity will be shown as a row in the grid
|
|
20
|
+
* where the RowsEntityDisplayField will be used in the first column of the grid.
|
|
21
|
+
*/
|
|
22
|
+
RowsEntityName: string;
|
|
23
|
+
/**
|
|
24
|
+
* Required: the field name in the RowsEntityName that will be shown in the first column in the grid
|
|
25
|
+
*/
|
|
26
|
+
RowsEntityDisplayField: string;
|
|
27
|
+
/**
|
|
28
|
+
* Determines how the row data will be fetched.
|
|
29
|
+
* * When set to FullEntity, all rows in the specified RowEntityName will be used.
|
|
30
|
+
* * When set to ViewName, the RowsEntityViewName will be used to fetch the rows from a defined User View
|
|
31
|
+
* * When set to Array, the RowsEntityData array will be used to fetch the rows
|
|
32
|
+
*/
|
|
33
|
+
RowsEntityDataSource: 'FullEntity' | 'ViewName' | 'Array';
|
|
34
|
+
/**
|
|
35
|
+
* For RowsEntityDataSource = FullEntity or ViewName, this is the extra filter to apply to the rows entity when fetching data. This is optional.
|
|
36
|
+
*/
|
|
37
|
+
RowsExtraFilter?: string;
|
|
38
|
+
/**
|
|
39
|
+
* For RowsEntityDataSource = FullEntity or ViewName, this is the order by clause to apply to the rows entity when fetching data. This is optional.
|
|
40
|
+
*/
|
|
41
|
+
RowsOrderBy?: string;
|
|
42
|
+
/**
|
|
43
|
+
* Used when RowsEntityDataSource = ViewName, this will be the name of the User View for the specified RowsEntity to run to get data
|
|
44
|
+
*/
|
|
45
|
+
RowsEntityViewName?: string;
|
|
46
|
+
/**
|
|
47
|
+
* Required: provide an array of BaseEntity objects that will be used to display the rows in the grid.
|
|
48
|
+
*/
|
|
49
|
+
RowsEntityArray?: BaseEntity[];
|
|
50
|
+
/**
|
|
51
|
+
* When set to Entity, the ColumnsEntity and related settings will be used to build the columns in the grid. When set to Fields, fields from the JoinEntity will be used to build the columns in the grid.
|
|
52
|
+
*/
|
|
53
|
+
ColumnsMode: 'Entity' | 'Fields';
|
|
54
|
+
/**
|
|
55
|
+
* Required when ColumnsMode is set to Entity: the name of the entity that will be used for displaying data for columns. This means that each row in the ColumnsEntity will be shown as a column in the grid
|
|
56
|
+
*/
|
|
57
|
+
ColumnsEntityName: string;
|
|
58
|
+
/**
|
|
59
|
+
* Required when ColumnsMode is set to Entity: the field name in the ColumnsEntityName that will be shown as columns in the grid
|
|
60
|
+
*/
|
|
61
|
+
ColumnsEntityDisplayField: string;
|
|
62
|
+
/**
|
|
63
|
+
* Determines how the column data will be fetched.
|
|
64
|
+
* * When set to FullEntity, all columns in the specified ColumnsEntityName will be used.
|
|
65
|
+
* * When set to ViewName, the ColumnsEntityViewName will be used to fetch the columns from a defined User View
|
|
66
|
+
* * When set to Array, the ColumnsEntityArray array will be used to fetch the columns
|
|
67
|
+
*/
|
|
68
|
+
ColumnsEntityDataSource: 'FullEntity' | 'ViewName' | 'Array';
|
|
69
|
+
/**
|
|
70
|
+
* For ColumnsEntityDataSource = FullEntity or ViewName, this is the extra filter to apply to the columns entity when fetching data. This is optional.
|
|
71
|
+
*/
|
|
72
|
+
ColumnsExtraFilter?: string;
|
|
73
|
+
/**
|
|
74
|
+
* For ColumnsEntityDataSource = FullEntity or ViewName, this is the order by clause to apply to the columns entity when fetching data. This is optional.
|
|
75
|
+
*/
|
|
76
|
+
ColumnsOrderBy?: string;
|
|
77
|
+
/**
|
|
78
|
+
* Used when ColumnsEntityDataSource = ViewName, this will be the name of the User View for the specified ColumnsEntity to run to get data
|
|
79
|
+
*/
|
|
80
|
+
ColumnsEntityViewName?: string;
|
|
81
|
+
/**
|
|
82
|
+
* Required when ColumnsMode is set to Entity: provide an array of BaseEntity objects that will be used to display the columns in the grid.
|
|
83
|
+
*/
|
|
84
|
+
ColumnsEntityArray?: BaseEntity[];
|
|
85
|
+
/**
|
|
86
|
+
* The name of the entity that will be used for joining the RowsEntity and ColumnsEntity. Or, in the case of ColumnsMode = Fields, there is no true "joining" happening but we are joining the data from the RowsEntity and JoinEntity together.
|
|
87
|
+
*/
|
|
88
|
+
JoinEntityName: string;
|
|
89
|
+
/**
|
|
90
|
+
* The name of the foreign key field in the JoinEntity that will be used to link to the Primary Key field in the RowsEntity
|
|
91
|
+
*/
|
|
92
|
+
JoinEntityRowForeignKey: string;
|
|
93
|
+
/**
|
|
94
|
+
* The name of the foreign key field in the JoinEntity that will be used to link to the Primary Key field in the ColumnsEntity
|
|
95
|
+
*/
|
|
96
|
+
JoinEntityColumnForeignKey: string;
|
|
97
|
+
/**
|
|
98
|
+
* The names of the columns from the JoinEntity to display as columns in the grid. This is only used when ColumnsMode is set to Fields.
|
|
99
|
+
*/
|
|
100
|
+
JoinEntityDisplayColumns?: string[];
|
|
101
|
+
/**
|
|
102
|
+
* When this property is set to JoinRecordExists the grid will operate as follows:
|
|
103
|
+
* * When a user checks the checkbox in the grid, a record will be created in the JoinEntity with the Row and Column foreign keys.
|
|
104
|
+
* * When a user unchecks the checkbox in the grid, the record in the JoinEntity will be deleted.
|
|
105
|
+
* In comparison, when the CheckBoxValueMode is set to ColumnValue, the grid will operate as follows:
|
|
106
|
+
* * When a user checks the checkbox in the grid, a value in the JoinEntity will be set to true in the CheckBoxValueField field.
|
|
107
|
+
* * When a user unchecks the checkbox in the grid, the value in the JoinEntity will be set to false in the CheckBoxValueField field.
|
|
108
|
+
*/
|
|
109
|
+
CheckBoxValueMode: 'RecordExists' | 'ColumnValue';
|
|
110
|
+
/**
|
|
111
|
+
* Required when CheckBoxValueMode is set to ColumnValue: the name of the field in the JoinEntity that will be used to store the value of the checkbox.
|
|
112
|
+
*/
|
|
113
|
+
CheckBoxValueField: string;
|
|
114
|
+
/**
|
|
115
|
+
* When the CheckBoxValueMode is set to RecordExists this means the grid will be adding and removing records from the JoinEntity. In some cases, entities require additional values
|
|
116
|
+
* beyond the foreign keys that are automatically set, in those cases, use this property to provide additional default values for the new records that are created.
|
|
117
|
+
*/
|
|
118
|
+
NewRecordDefaultValues?: {
|
|
119
|
+
[key: string]: any;
|
|
120
|
+
};
|
|
121
|
+
ngAfterViewInit(): void;
|
|
122
|
+
constructor(cdr: ChangeDetectorRef);
|
|
123
|
+
_GridData: JoinGridRow[];
|
|
124
|
+
_IsLoading: boolean;
|
|
125
|
+
protected _rowsEntityInfo: EntityInfo | null;
|
|
126
|
+
protected _columnsEntityInfo: EntityInfo | null;
|
|
127
|
+
protected _columnsEntityData: BaseEntity[] | undefined;
|
|
128
|
+
protected _rowsEntityData: BaseEntity[] | undefined;
|
|
129
|
+
/**
|
|
130
|
+
* Saves all of the changes made in the grid. This includes adding new records, updating existing records, and deleting records.
|
|
131
|
+
*/
|
|
132
|
+
Save(): Promise<boolean>;
|
|
133
|
+
/**
|
|
134
|
+
* Cancels any changes and reverts to the prior state of the grid that reflects the last saved state.
|
|
135
|
+
*/
|
|
136
|
+
CancelEdit(): Promise<void>;
|
|
137
|
+
get NumDirtyRecords(): number;
|
|
138
|
+
IsRecordReallyDirty(row: JoinGridRow): boolean;
|
|
139
|
+
IsCellReallyDirty(cell: JoinGridCell): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* This method is called automatically when the component is first loaded. Call the method anytime if you want to refresh the grid.
|
|
142
|
+
*/
|
|
143
|
+
Refresh(): Promise<void>;
|
|
144
|
+
protected PopulateRowsAndColsData(): Promise<void>;
|
|
145
|
+
protected RunColumnsOrRowsView(dataSource: 'FullEntity' | 'ViewName', entityName: string, viewName?: string, extraFilter?: string, orderBy?: string): Promise<BaseEntity[]>;
|
|
146
|
+
protected PopulateGridData(joinEntityData: BaseEntity[]): Promise<void>;
|
|
147
|
+
protected _pendingDeletes: BaseEntity[];
|
|
148
|
+
protected _pendingInserts: BaseEntity[];
|
|
149
|
+
_FlipRecord(event: MouseEvent, row: JoinGridRow, cell: JoinGridCell, stopPropagation?: boolean): Promise<void>;
|
|
150
|
+
_IsColumnChecked(cell: JoinGridCell): boolean;
|
|
151
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<JoinGridComponent, never>;
|
|
152
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<JoinGridComponent, "mj-join-grid", never, { "RowsEntityName": { "alias": "RowsEntityName"; "required": false; }; "RowsEntityDisplayField": { "alias": "RowsEntityDisplayField"; "required": false; }; "RowsEntityDataSource": { "alias": "RowsEntityDataSource"; "required": false; }; "RowsExtraFilter": { "alias": "RowsExtraFilter"; "required": false; }; "RowsOrderBy": { "alias": "RowsOrderBy"; "required": false; }; "RowsEntityViewName": { "alias": "RowsEntityViewName"; "required": false; }; "RowsEntityArray": { "alias": "RowsEntityArray"; "required": false; }; "ColumnsMode": { "alias": "ColumnsMode"; "required": false; }; "ColumnsEntityName": { "alias": "ColumnsEntityName"; "required": false; }; "ColumnsEntityDisplayField": { "alias": "ColumnsEntityDisplayField"; "required": false; }; "ColumnsEntityDataSource": { "alias": "ColumnsEntityDataSource"; "required": false; }; "ColumnsExtraFilter": { "alias": "ColumnsExtraFilter"; "required": false; }; "ColumnsOrderBy": { "alias": "ColumnsOrderBy"; "required": false; }; "ColumnsEntityViewName": { "alias": "ColumnsEntityViewName"; "required": false; }; "ColumnsEntityArray": { "alias": "ColumnsEntityArray"; "required": false; }; "JoinEntityName": { "alias": "JoinEntityName"; "required": false; }; "JoinEntityRowForeignKey": { "alias": "JoinEntityRowForeignKey"; "required": false; }; "JoinEntityColumnForeignKey": { "alias": "JoinEntityColumnForeignKey"; "required": false; }; "JoinEntityDisplayColumns": { "alias": "JoinEntityDisplayColumns"; "required": false; }; "CheckBoxValueMode": { "alias": "CheckBoxValueMode"; "required": false; }; "CheckBoxValueField": { "alias": "CheckBoxValueField"; "required": false; }; "NewRecordDefaultValues": { "alias": "NewRecordDefaultValues"; "required": false; }; }, {}, never, never, false, never>;
|
|
153
|
+
}
|
|
@@ -0,0 +1,483 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { Component, Input } from '@angular/core';
|
|
11
|
+
import { Metadata, RunView } from '@memberjunction/core';
|
|
12
|
+
import * as i0 from "@angular/core";
|
|
13
|
+
import * as i1 from "@angular/common";
|
|
14
|
+
import * as i2 from "@progress/kendo-angular-buttons";
|
|
15
|
+
import * as i3 from "@progress/kendo-angular-indicators";
|
|
16
|
+
import * as i4 from "@memberjunction/ng-container-directives";
|
|
17
|
+
function JoinGridComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
|
|
18
|
+
i0.ɵɵelementStart(0, "div");
|
|
19
|
+
i0.ɵɵelement(1, "kendo-loader");
|
|
20
|
+
i0.ɵɵelementEnd();
|
|
21
|
+
} }
|
|
22
|
+
function JoinGridComponent_Conditional_6_Conditional_5_For_1_Template(rf, ctx) { if (rf & 1) {
|
|
23
|
+
i0.ɵɵelementStart(0, "th");
|
|
24
|
+
i0.ɵɵtext(1);
|
|
25
|
+
i0.ɵɵelementEnd();
|
|
26
|
+
} if (rf & 2) {
|
|
27
|
+
const colRecord_r6 = ctx.$implicit;
|
|
28
|
+
const ctx_r5 = i0.ɵɵnextContext(3);
|
|
29
|
+
i0.ɵɵadvance();
|
|
30
|
+
i0.ɵɵtextInterpolate(colRecord_r6.Get(ctx_r5.ColumnsEntityDisplayField));
|
|
31
|
+
} }
|
|
32
|
+
function JoinGridComponent_Conditional_6_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
33
|
+
i0.ɵɵrepeaterCreate(0, JoinGridComponent_Conditional_6_Conditional_5_For_1_Template, 2, 1, "th", null, i0.ɵɵrepeaterTrackByIdentity);
|
|
34
|
+
} if (rf & 2) {
|
|
35
|
+
const ctx_r2 = i0.ɵɵnextContext(2);
|
|
36
|
+
i0.ɵɵrepeater(ctx_r2._columnsEntityData);
|
|
37
|
+
} }
|
|
38
|
+
function JoinGridComponent_Conditional_6_Conditional_6_For_1_Template(rf, ctx) { if (rf & 1) {
|
|
39
|
+
i0.ɵɵelementStart(0, "th");
|
|
40
|
+
i0.ɵɵtext(1);
|
|
41
|
+
i0.ɵɵelementEnd();
|
|
42
|
+
} if (rf & 2) {
|
|
43
|
+
const colName_r12 = ctx.$implicit;
|
|
44
|
+
i0.ɵɵadvance();
|
|
45
|
+
i0.ɵɵtextInterpolate(colName_r12);
|
|
46
|
+
} }
|
|
47
|
+
function JoinGridComponent_Conditional_6_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
48
|
+
i0.ɵɵrepeaterCreate(0, JoinGridComponent_Conditional_6_Conditional_6_For_1_Template, 2, 1, "th", null, i0.ɵɵrepeaterTrackByIdentity);
|
|
49
|
+
} if (rf & 2) {
|
|
50
|
+
const ctx_r3 = i0.ɵɵnextContext(2);
|
|
51
|
+
i0.ɵɵrepeater(ctx_r3.JoinEntityDisplayColumns);
|
|
52
|
+
} }
|
|
53
|
+
function JoinGridComponent_Conditional_6_For_9_Conditional_4_td_0_Template(rf, ctx) { if (rf & 1) {
|
|
54
|
+
i0.ɵɵelementStart(0, "td");
|
|
55
|
+
i0.ɵɵelement(1, "input", 7);
|
|
56
|
+
i0.ɵɵelementEnd();
|
|
57
|
+
} }
|
|
58
|
+
function JoinGridComponent_Conditional_6_For_9_Conditional_4_Template(rf, ctx) { if (rf & 1) {
|
|
59
|
+
i0.ɵɵtemplate(0, JoinGridComponent_Conditional_6_For_9_Conditional_4_td_0_Template, 2, 0, "td", 6);
|
|
60
|
+
} if (rf & 2) {
|
|
61
|
+
const ctx_r22 = i0.ɵɵnextContext(3);
|
|
62
|
+
i0.ɵɵproperty("ngForOf", ctx_r22.JoinEntityDisplayColumns);
|
|
63
|
+
} }
|
|
64
|
+
function JoinGridComponent_Conditional_6_For_9_Conditional_5_For_1_Template(rf, ctx) { if (rf & 1) {
|
|
65
|
+
const _r34 = i0.ɵɵgetCurrentView();
|
|
66
|
+
i0.ɵɵelementStart(0, "td", 8);
|
|
67
|
+
i0.ɵɵlistener("click", function JoinGridComponent_Conditional_6_For_9_Conditional_5_For_1_Template_td_click_0_listener($event) { const restoredCtx = i0.ɵɵrestoreView(_r34); const cell_r27 = restoredCtx.$implicit; const row_r17 = i0.ɵɵnextContext(2).$implicit; const ctx_r32 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r32._FlipRecord($event, row_r17, cell_r27)); });
|
|
68
|
+
i0.ɵɵelementStart(1, "input", 9);
|
|
69
|
+
i0.ɵɵlistener("click", function JoinGridComponent_Conditional_6_For_9_Conditional_5_For_1_Template_input_click_1_listener($event) { const restoredCtx = i0.ɵɵrestoreView(_r34); const cell_r27 = restoredCtx.$implicit; const row_r17 = i0.ɵɵnextContext(2).$implicit; const ctx_r35 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r35._FlipRecord($event, row_r17, cell_r27, true)); });
|
|
70
|
+
i0.ɵɵelementEnd()();
|
|
71
|
+
} if (rf & 2) {
|
|
72
|
+
const cell_r27 = ctx.$implicit;
|
|
73
|
+
const ctx_r26 = i0.ɵɵnextContext(4);
|
|
74
|
+
i0.ɵɵproperty("ngClass", ctx_r26.IsCellReallyDirty(cell_r27) ? "dirty-cell" : "");
|
|
75
|
+
i0.ɵɵadvance();
|
|
76
|
+
i0.ɵɵproperty("checked", ctx_r26._IsColumnChecked(cell_r27));
|
|
77
|
+
} }
|
|
78
|
+
function JoinGridComponent_Conditional_6_For_9_Conditional_5_Template(rf, ctx) { if (rf & 1) {
|
|
79
|
+
i0.ɵɵrepeaterCreate(0, JoinGridComponent_Conditional_6_For_9_Conditional_5_For_1_Template, 2, 2, "td", 4, i0.ɵɵrepeaterTrackByIdentity);
|
|
80
|
+
} if (rf & 2) {
|
|
81
|
+
const row_r17 = i0.ɵɵnextContext().$implicit;
|
|
82
|
+
i0.ɵɵrepeater(row_r17.ColumnData);
|
|
83
|
+
} }
|
|
84
|
+
function JoinGridComponent_Conditional_6_For_9_Template(rf, ctx) { if (rf & 1) {
|
|
85
|
+
i0.ɵɵelementStart(0, "tr", 4)(1, "td", 5)(2, "span");
|
|
86
|
+
i0.ɵɵtext(3);
|
|
87
|
+
i0.ɵɵelementEnd()();
|
|
88
|
+
i0.ɵɵtemplate(4, JoinGridComponent_Conditional_6_For_9_Conditional_4_Template, 1, 1, "td")(5, JoinGridComponent_Conditional_6_For_9_Conditional_5_Template, 2, 0);
|
|
89
|
+
i0.ɵɵelementEnd();
|
|
90
|
+
} if (rf & 2) {
|
|
91
|
+
const row_r17 = ctx.$implicit;
|
|
92
|
+
const ctx_r4 = i0.ɵɵnextContext(2);
|
|
93
|
+
i0.ɵɵproperty("ngClass", ctx_r4.IsRecordReallyDirty(row_r17) ? "dirty-row" : "");
|
|
94
|
+
i0.ɵɵadvance(3);
|
|
95
|
+
i0.ɵɵtextInterpolate(row_r17.FirstColValue);
|
|
96
|
+
i0.ɵɵadvance();
|
|
97
|
+
i0.ɵɵconditional(4, ctx_r4.ColumnsMode === "Fields" ? 4 : 5);
|
|
98
|
+
} }
|
|
99
|
+
function JoinGridComponent_Conditional_6_Template(rf, ctx) { if (rf & 1) {
|
|
100
|
+
i0.ɵɵelementStart(0, "table", 3)(1, "thead")(2, "tr")(3, "th");
|
|
101
|
+
i0.ɵɵtext(4);
|
|
102
|
+
i0.ɵɵelementEnd();
|
|
103
|
+
i0.ɵɵtemplate(5, JoinGridComponent_Conditional_6_Conditional_5_Template, 2, 0)(6, JoinGridComponent_Conditional_6_Conditional_6_Template, 2, 0);
|
|
104
|
+
i0.ɵɵelementEnd()();
|
|
105
|
+
i0.ɵɵelementStart(7, "tbody");
|
|
106
|
+
i0.ɵɵrepeaterCreate(8, JoinGridComponent_Conditional_6_For_9_Template, 6, 3, "tr", 4, i0.ɵɵrepeaterTrackByIdentity);
|
|
107
|
+
i0.ɵɵelementEnd()();
|
|
108
|
+
} if (rf & 2) {
|
|
109
|
+
const ctx_r1 = i0.ɵɵnextContext();
|
|
110
|
+
i0.ɵɵadvance(4);
|
|
111
|
+
i0.ɵɵtextInterpolate(ctx_r1.RowsEntityName);
|
|
112
|
+
i0.ɵɵadvance();
|
|
113
|
+
i0.ɵɵconditional(5, ctx_r1.ColumnsMode === "Entity" ? 5 : 6);
|
|
114
|
+
i0.ɵɵadvance(3);
|
|
115
|
+
i0.ɵɵrepeater(ctx_r1._GridData);
|
|
116
|
+
} }
|
|
117
|
+
export class JoinGridCell {
|
|
118
|
+
}
|
|
119
|
+
export class JoinGridRow {
|
|
120
|
+
constructor() {
|
|
121
|
+
this.JoinExists = false;
|
|
122
|
+
this.ColumnData = [];
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
export class JoinGridComponent {
|
|
126
|
+
ngAfterViewInit() {
|
|
127
|
+
// load up the grid
|
|
128
|
+
this.Refresh();
|
|
129
|
+
}
|
|
130
|
+
constructor(cdr) {
|
|
131
|
+
this.cdr = cdr;
|
|
132
|
+
/**
|
|
133
|
+
* Determines how the row data will be fetched.
|
|
134
|
+
* * When set to FullEntity, all rows in the specified RowEntityName will be used.
|
|
135
|
+
* * When set to ViewName, the RowsEntityViewName will be used to fetch the rows from a defined User View
|
|
136
|
+
* * When set to Array, the RowsEntityData array will be used to fetch the rows
|
|
137
|
+
*/
|
|
138
|
+
this.RowsEntityDataSource = 'FullEntity';
|
|
139
|
+
/**
|
|
140
|
+
* When set to Entity, the ColumnsEntity and related settings will be used to build the columns in the grid. When set to Fields, fields from the JoinEntity will be used to build the columns in the grid.
|
|
141
|
+
*/
|
|
142
|
+
this.ColumnsMode = 'Entity';
|
|
143
|
+
/**
|
|
144
|
+
* Determines how the column data will be fetched.
|
|
145
|
+
* * When set to FullEntity, all columns in the specified ColumnsEntityName will be used.
|
|
146
|
+
* * When set to ViewName, the ColumnsEntityViewName will be used to fetch the columns from a defined User View
|
|
147
|
+
* * When set to Array, the ColumnsEntityArray array will be used to fetch the columns
|
|
148
|
+
*/
|
|
149
|
+
this.ColumnsEntityDataSource = 'FullEntity';
|
|
150
|
+
/**
|
|
151
|
+
* When this property is set to JoinRecordExists the grid will operate as follows:
|
|
152
|
+
* * When a user checks the checkbox in the grid, a record will be created in the JoinEntity with the Row and Column foreign keys.
|
|
153
|
+
* * When a user unchecks the checkbox in the grid, the record in the JoinEntity will be deleted.
|
|
154
|
+
* In comparison, when the CheckBoxValueMode is set to ColumnValue, the grid will operate as follows:
|
|
155
|
+
* * When a user checks the checkbox in the grid, a value in the JoinEntity will be set to true in the CheckBoxValueField field.
|
|
156
|
+
* * When a user unchecks the checkbox in the grid, the value in the JoinEntity will be set to false in the CheckBoxValueField field.
|
|
157
|
+
*/
|
|
158
|
+
this.CheckBoxValueMode = 'RecordExists';
|
|
159
|
+
/*The below members are public because the Angular template needs access to them, but by naming convention we prefix with an _ so that it is clear they are not to be used outside of the component */
|
|
160
|
+
this._GridData = [];
|
|
161
|
+
this._IsLoading = false;
|
|
162
|
+
/* protected internal members */
|
|
163
|
+
this._rowsEntityInfo = null;
|
|
164
|
+
this._columnsEntityInfo = null;
|
|
165
|
+
this._columnsEntityData = undefined;
|
|
166
|
+
this._rowsEntityData = undefined;
|
|
167
|
+
this._pendingDeletes = [];
|
|
168
|
+
this._pendingInserts = [];
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Saves all of the changes made in the grid. This includes adding new records, updating existing records, and deleting records.
|
|
172
|
+
*/
|
|
173
|
+
Save() {
|
|
174
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
175
|
+
// for each pending delete, we need to delete the record
|
|
176
|
+
// for each pending insert, we need to save the record
|
|
177
|
+
// do it all in one transaction
|
|
178
|
+
const md = new Metadata();
|
|
179
|
+
const tg = yield md.CreateTransactionGroup();
|
|
180
|
+
let validated = true;
|
|
181
|
+
const valErrors = [];
|
|
182
|
+
this._pendingDeletes.forEach(obj => {
|
|
183
|
+
obj.TransactionGroup = tg;
|
|
184
|
+
obj.Delete();
|
|
185
|
+
});
|
|
186
|
+
this._pendingInserts.forEach(obj => {
|
|
187
|
+
obj.TransactionGroup = tg;
|
|
188
|
+
const valResult = obj.Validate();
|
|
189
|
+
validated = validated && valResult.Success;
|
|
190
|
+
valErrors.push(valResult.Errors);
|
|
191
|
+
obj.Save();
|
|
192
|
+
});
|
|
193
|
+
if (validated) {
|
|
194
|
+
if (!(yield tg.Submit())) {
|
|
195
|
+
alert('Error saving changes');
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
yield this.Refresh(); // refresh afterwards
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
alert('Error validating changes, details in console');
|
|
205
|
+
console.log(valErrors);
|
|
206
|
+
return false;
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Cancels any changes and reverts to the prior state of the grid that reflects the last saved state.
|
|
212
|
+
*/
|
|
213
|
+
CancelEdit() {
|
|
214
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
215
|
+
// go through all of the pending deletes and remove them from the array
|
|
216
|
+
// and go through all of the pending inserts and remove them from the array
|
|
217
|
+
// before removing stuff from arrays we need to go back through all of hte grid cells and restore to original data
|
|
218
|
+
this._GridData.forEach(row => {
|
|
219
|
+
row.ColumnData.forEach(cell => {
|
|
220
|
+
// for each cell, if we have a data object, look for a match in the pending inserts array, that means it is a NEW record
|
|
221
|
+
if (cell.data) {
|
|
222
|
+
const match = this._pendingInserts.find(obj => obj.Get(this.JoinEntityColumnForeignKey) === cell.ColumnForeignKeyValue && obj.Get(this.JoinEntityRowForeignKey) === row.RowForeignKeyValue);
|
|
223
|
+
if (match) {
|
|
224
|
+
// means that the current cell is a new record, so we need to remove it
|
|
225
|
+
cell.data = undefined;
|
|
226
|
+
this._pendingInserts.splice(this._pendingInserts.indexOf(match), 1);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
// we need to check if a match exists in the pending deletes array, if so, we need to restore the data
|
|
231
|
+
const match = this._pendingDeletes.find(obj => obj.Get(this.JoinEntityColumnForeignKey) === cell.ColumnForeignKeyValue && obj.Get(this.JoinEntityRowForeignKey) === row.RowForeignKeyValue);
|
|
232
|
+
if (match) {
|
|
233
|
+
cell.data = match;
|
|
234
|
+
this._pendingDeletes.splice(this._pendingDeletes.indexOf(match), 1);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
get NumDirtyRecords() {
|
|
242
|
+
return this._pendingDeletes.length + this._pendingInserts.length;
|
|
243
|
+
}
|
|
244
|
+
IsRecordReallyDirty(row) {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
IsCellReallyDirty(cell) {
|
|
248
|
+
if (cell.data) {
|
|
249
|
+
// we have a record here, check if it is dirty or not as step 1
|
|
250
|
+
if (cell.data.Dirty)
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
// we need to see if we previoulsy HAD a data element in the cell but we removed it and it is located in the pendingDeletes array
|
|
255
|
+
const record = this._pendingDeletes.find(obj => obj.Get(this.JoinEntityColumnForeignKey) === cell.ColumnForeignKeyValue &&
|
|
256
|
+
obj.Get(this.JoinEntityRowForeignKey) === cell.RowForeignKeyValue);
|
|
257
|
+
if (record)
|
|
258
|
+
return true; // found a pending delete, we're dirty
|
|
259
|
+
}
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* This method is called automatically when the component is first loaded. Call the method anytime if you want to refresh the grid.
|
|
264
|
+
*/
|
|
265
|
+
Refresh() {
|
|
266
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
267
|
+
this._IsLoading = true; // turn on the loading spinner
|
|
268
|
+
this.cdr.detectChanges(); // let angular know we have changes
|
|
269
|
+
this._pendingDeletes = [];
|
|
270
|
+
this._pendingInserts = [];
|
|
271
|
+
// we are provided an array of Column and Row objects. We need to get the rows from the JoinEntity that link them up.
|
|
272
|
+
const md = new Metadata();
|
|
273
|
+
this._rowsEntityInfo = md.EntityByName(this.RowsEntityName);
|
|
274
|
+
this._columnsEntityInfo = md.EntityByName(this.ColumnsEntityName);
|
|
275
|
+
if (!this._rowsEntityInfo)
|
|
276
|
+
throw new Error('Invalid entity name provided for rows entity.');
|
|
277
|
+
if (!this._columnsEntityInfo)
|
|
278
|
+
throw new Error('Invalid entity name provided for columns entity.');
|
|
279
|
+
yield this.PopulateRowsAndColsData();
|
|
280
|
+
const rowQuotes = this._rowsEntityInfo.FirstPrimaryKey.NeedsQuotes ? "'" : "";
|
|
281
|
+
let filter = `${this.JoinEntityRowForeignKey} IN (${this._rowsEntityData.map(obj => `${rowQuotes}${obj.Get(this._rowsEntityInfo.FirstPrimaryKey.Name)}${rowQuotes}`).join(',')})`;
|
|
282
|
+
if (this.ColumnsMode === 'Entity') {
|
|
283
|
+
const colQuotes = this._columnsEntityInfo.FirstPrimaryKey.NeedsQuotes ? "'" : "";
|
|
284
|
+
filter += ` AND ${this.JoinEntityColumnForeignKey} IN (${this._columnsEntityData.map(obj => `${colQuotes}${obj.Get(this._columnsEntityInfo.FirstPrimaryKey.Name)}${colQuotes}`).join(',')})`;
|
|
285
|
+
}
|
|
286
|
+
const rv = new RunView();
|
|
287
|
+
const result = yield rv.RunView({
|
|
288
|
+
EntityName: this.JoinEntityName,
|
|
289
|
+
ExtraFilter: filter,
|
|
290
|
+
ResultType: 'entity_object'
|
|
291
|
+
});
|
|
292
|
+
if (result && result.Success) {
|
|
293
|
+
// we have the data, now we need to build the grid
|
|
294
|
+
this.PopulateGridData(result.Results);
|
|
295
|
+
}
|
|
296
|
+
this._IsLoading = false; // turn off the loading spinner
|
|
297
|
+
this.cdr.detectChanges(); // let Angular know we have changes
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
PopulateRowsAndColsData() {
|
|
301
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
302
|
+
const rv = new RunView();
|
|
303
|
+
if (this.ColumnsEntityDataSource === 'Array') {
|
|
304
|
+
this._columnsEntityData = this.ColumnsEntityArray;
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
this._columnsEntityData = yield this.RunColumnsOrRowsView(this.ColumnsEntityDataSource, this.ColumnsEntityName, this.ColumnsEntityViewName, this.ColumnsExtraFilter, this.ColumnsOrderBy);
|
|
308
|
+
}
|
|
309
|
+
if (this.RowsEntityDataSource === 'Array') {
|
|
310
|
+
this._rowsEntityData = this.RowsEntityArray;
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
this._rowsEntityData = yield this.RunColumnsOrRowsView(this.RowsEntityDataSource, this.RowsEntityName, this.RowsEntityViewName, this.RowsExtraFilter, this.RowsOrderBy);
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
RunColumnsOrRowsView(dataSource, entityName, viewName, extraFilter, orderBy) {
|
|
318
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
319
|
+
const rv = new RunView();
|
|
320
|
+
const params = dataSource === 'FullEntity' ? { EntityName: entityName } : { ViewName: viewName };
|
|
321
|
+
if (extraFilter)
|
|
322
|
+
params.ExtraFilter = extraFilter;
|
|
323
|
+
if (orderBy)
|
|
324
|
+
params.OrderBy = orderBy;
|
|
325
|
+
params.ResultType = 'entity_object';
|
|
326
|
+
const data = yield rv.RunView(params);
|
|
327
|
+
if (data && data.Success) {
|
|
328
|
+
return data.Results;
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
return [];
|
|
332
|
+
}
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
PopulateGridData(joinEntityData) {
|
|
336
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
337
|
+
// we have the data, now we need to build the grid
|
|
338
|
+
// we need to build the grid data
|
|
339
|
+
const gridData = [];
|
|
340
|
+
this._rowsEntityData.forEach(row => {
|
|
341
|
+
let rowData = {
|
|
342
|
+
FirstColValue: row.Get(this.RowsEntityDisplayField),
|
|
343
|
+
JoinExists: false,
|
|
344
|
+
RowForeignKeyValue: row.Get(this._rowsEntityInfo.FirstPrimaryKey.Name),
|
|
345
|
+
ColumnData: [] // start off with an empty array
|
|
346
|
+
};
|
|
347
|
+
// for the mode where we are using columns, do the following
|
|
348
|
+
if (this.ColumnsMode === 'Entity') {
|
|
349
|
+
for (let i = 0; i < this._columnsEntityData.length; i++) {
|
|
350
|
+
const column = this._columnsEntityData[i];
|
|
351
|
+
const join = joinEntityData.find(j => j.Get(this.JoinEntityRowForeignKey) === row.Get(this._rowsEntityInfo.FirstPrimaryKey.Name) &&
|
|
352
|
+
j.Get(this.JoinEntityColumnForeignKey) === column.Get(this._columnsEntityInfo.FirstPrimaryKey.Name));
|
|
353
|
+
rowData.ColumnData.push({
|
|
354
|
+
index: i,
|
|
355
|
+
ColumnForeignKeyValue: column.Get(this._columnsEntityInfo.FirstPrimaryKey.Name),
|
|
356
|
+
RowForeignKeyValue: rowData.RowForeignKeyValue,
|
|
357
|
+
data: join
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
// we are display the values from the JoinEntity as columns from the JoinEntityDisplayColumns array
|
|
363
|
+
}
|
|
364
|
+
gridData.push(rowData);
|
|
365
|
+
});
|
|
366
|
+
this._GridData = gridData;
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
_FlipRecord(event, row, cell, stopPropagation = false) {
|
|
370
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
371
|
+
if (stopPropagation)
|
|
372
|
+
event.stopPropagation();
|
|
373
|
+
if (!cell)
|
|
374
|
+
throw new Error('cell is a required parameter');
|
|
375
|
+
if (cell.data) {
|
|
376
|
+
if (cell.data.IsSaved) {
|
|
377
|
+
// If this is a record that is saved, put into an array of pending deletes
|
|
378
|
+
this._pendingDeletes.push(cell.data);
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
// we need to find the record in the pending inserts and remove it from that array
|
|
382
|
+
const index = this._pendingInserts.indexOf(cell.data);
|
|
383
|
+
if (index >= 0)
|
|
384
|
+
this._pendingInserts.splice(index, 1);
|
|
385
|
+
}
|
|
386
|
+
// Now take data off the item
|
|
387
|
+
cell.data = undefined;
|
|
388
|
+
}
|
|
389
|
+
else {
|
|
390
|
+
// We need to add the record, first see if the record is in the _pendingDeletes array
|
|
391
|
+
let record = this._pendingDeletes.find(obj => obj.Get(this.JoinEntityColumnForeignKey) === cell.ColumnForeignKeyValue && obj.Get(this.JoinEntityRowForeignKey) === row.RowForeignKeyValue);
|
|
392
|
+
if (!record) {
|
|
393
|
+
const md = new Metadata();
|
|
394
|
+
record = yield md.GetEntityObject(this.JoinEntityName);
|
|
395
|
+
record.Set(this.JoinEntityRowForeignKey, row.RowForeignKeyValue);
|
|
396
|
+
record.Set(this.JoinEntityColumnForeignKey, cell.ColumnForeignKeyValue);
|
|
397
|
+
for (const key in this.NewRecordDefaultValues) {
|
|
398
|
+
record.Set(key, this.NewRecordDefaultValues[key]);
|
|
399
|
+
}
|
|
400
|
+
this._pendingInserts.push(record);
|
|
401
|
+
}
|
|
402
|
+
cell.data = record;
|
|
403
|
+
}
|
|
404
|
+
this.cdr.detectChanges();
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
_IsColumnChecked(cell) {
|
|
408
|
+
return (cell === null || cell === void 0 ? void 0 : cell.data) !== undefined;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
JoinGridComponent.ɵfac = function JoinGridComponent_Factory(t) { return new (t || JoinGridComponent)(i0.ɵɵdirectiveInject(i0.ChangeDetectorRef)); };
|
|
412
|
+
JoinGridComponent.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: JoinGridComponent, selectors: [["mj-join-grid"]], inputs: { RowsEntityName: "RowsEntityName", RowsEntityDisplayField: "RowsEntityDisplayField", RowsEntityDataSource: "RowsEntityDataSource", RowsExtraFilter: "RowsExtraFilter", RowsOrderBy: "RowsOrderBy", RowsEntityViewName: "RowsEntityViewName", RowsEntityArray: "RowsEntityArray", ColumnsMode: "ColumnsMode", ColumnsEntityName: "ColumnsEntityName", ColumnsEntityDisplayField: "ColumnsEntityDisplayField", ColumnsEntityDataSource: "ColumnsEntityDataSource", ColumnsExtraFilter: "ColumnsExtraFilter", ColumnsOrderBy: "ColumnsOrderBy", ColumnsEntityViewName: "ColumnsEntityViewName", ColumnsEntityArray: "ColumnsEntityArray", JoinEntityName: "JoinEntityName", JoinEntityRowForeignKey: "JoinEntityRowForeignKey", JoinEntityColumnForeignKey: "JoinEntityColumnForeignKey", JoinEntityDisplayColumns: "JoinEntityDisplayColumns", CheckBoxValueMode: "CheckBoxValueMode", CheckBoxValueField: "CheckBoxValueField", NewRecordDefaultValues: "NewRecordDefaultValues" }, decls: 7, vars: 4, consts: [["mjFillContainer", "", 1, "wrapper"], ["kendoButton", "", 3, "disabled", "click"], ["class", "grid"], [1, "grid"], [3, "ngClass"], [1, "first-column"], [4, "ngFor", "ngForOf"], ["type", "checkbox", "kendoCheckBox", ""], [3, "ngClass", "click"], ["type", "checkbox", "kendoCheckBox", "", 3, "checked", "click"]], template: function JoinGridComponent_Template(rf, ctx) { if (rf & 1) {
|
|
413
|
+
i0.ɵɵelementStart(0, "div", 0);
|
|
414
|
+
i0.ɵɵtemplate(1, JoinGridComponent_Conditional_1_Template, 2, 0, "div");
|
|
415
|
+
i0.ɵɵelementStart(2, "button", 1);
|
|
416
|
+
i0.ɵɵlistener("click", function JoinGridComponent_Template_button_click_2_listener() { return ctx.Save(); });
|
|
417
|
+
i0.ɵɵtext(3, "Save");
|
|
418
|
+
i0.ɵɵelementEnd();
|
|
419
|
+
i0.ɵɵelementStart(4, "button", 1);
|
|
420
|
+
i0.ɵɵlistener("click", function JoinGridComponent_Template_button_click_4_listener() { return ctx.CancelEdit(); });
|
|
421
|
+
i0.ɵɵtext(5, "Cancel");
|
|
422
|
+
i0.ɵɵelementEnd();
|
|
423
|
+
i0.ɵɵtemplate(6, JoinGridComponent_Conditional_6_Template, 10, 2, "table", 2);
|
|
424
|
+
i0.ɵɵelementEnd();
|
|
425
|
+
} if (rf & 2) {
|
|
426
|
+
i0.ɵɵadvance();
|
|
427
|
+
i0.ɵɵconditional(1, ctx._IsLoading ? 1 : -1);
|
|
428
|
+
i0.ɵɵadvance();
|
|
429
|
+
i0.ɵɵproperty("disabled", ctx.NumDirtyRecords === 0);
|
|
430
|
+
i0.ɵɵadvance(2);
|
|
431
|
+
i0.ɵɵproperty("disabled", ctx.NumDirtyRecords === 0);
|
|
432
|
+
i0.ɵɵadvance(2);
|
|
433
|
+
i0.ɵɵconditional(6, !ctx._IsLoading ? 6 : -1);
|
|
434
|
+
} }, dependencies: [i1.NgClass, i1.NgForOf, i2.ButtonComponent, i3.LoaderComponent, i4.FillContainer], styles: [".wrapper[_ngcontent-%COMP%] {\n overflow: auto;\n}\n\n\n\ntable[_ngcontent-%COMP%] {\n margin-left: 5px;\n margin-top: 5px;\n border-collapse: collapse; \n\n}\n\nbutton[_ngcontent-%COMP%] {\n margin-left: 5px;\n margin-top: 5px;\n width: 125px;\n}\n \ntable[_ngcontent-%COMP%] th[_ngcontent-%COMP%] {\n background-color: #f2f2f2; \n\n color: black; \n\n font-weight: bold; \n\n cursor: pointer;\n}\n\n.permission-left-col[_ngcontent-%COMP%] {\n cursor: pointer;\n}\n\n\n\ntable[_ngcontent-%COMP%] th[_ngcontent-%COMP%], table[_ngcontent-%COMP%] td[_ngcontent-%COMP%] {\n border: 1px solid gray; \n\n height: 36px; \n\n text-align: center;\n padding: 0 8px; \n\n}\n\n\n\ntable[_ngcontent-%COMP%] th[_ngcontent-%COMP%]:first-child, table[_ngcontent-%COMP%] td[_ngcontent-%COMP%]:first-child {\n min-width: 150px; \n\n text-align: left;\n}\n\n\n\ntable[_ngcontent-%COMP%] th[_ngcontent-%COMP%]:not(:first-child), table[_ngcontent-%COMP%] td[_ngcontent-%COMP%]:not(:first-child) {\n width: 100px; \n\n}\n\n\n\ntable[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:nth-child(odd) {\n background-color: white; \n\n}\n\ntable[_ngcontent-%COMP%] tr[_ngcontent-%COMP%]:nth-child(even) {\n background-color: #e7f4ff; \n\n}\n\ntable[_ngcontent-%COMP%] tr.dirty-row[_ngcontent-%COMP%] {\n font-style: italic;\n background-color: #ffcccc;\n}\n\ntable[_ngcontent-%COMP%] td.dirty-cell[_ngcontent-%COMP%] {\n font-style: italic;\n background-color: #ffcccc;\n}"] });
|
|
435
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(JoinGridComponent, [{
|
|
436
|
+
type: Component,
|
|
437
|
+
args: [{ selector: 'mj-join-grid', template: "<div mjFillContainer class=\"wrapper\"> \n @if (_IsLoading) {\n <div><kendo-loader></kendo-loader></div>\n }\n <button [disabled]=\"NumDirtyRecords === 0\" kendoButton (click)=\"Save()\">Save</button>\n <button [disabled]=\"NumDirtyRecords === 0\" kendoButton (click)=\"CancelEdit()\">Cancel</button>\n @if (!_IsLoading) {\n <table class=\"grid\">\n <thead>\n <tr>\n <!-- First column is the name of the Rows Entity -->\n <th>{{RowsEntityName}}</th>\n @if (ColumnsMode === 'Entity') {\n @for (colRecord of this._columnsEntityData; track colRecord) {\n <th>{{colRecord.Get(this.ColumnsEntityDisplayField)}}</th>\n }\n }\n @else {\n <!-- we need one column for each of the fields in the JoinEntityDisplayColumns array -->\n @for (colName of JoinEntityDisplayColumns; track colName) {\n <th>{{colName}}</th>\n }\n }\n </tr>\n </thead>\n <tbody>\n @for (row of _GridData; track row) {\n <tr [ngClass]=\"IsRecordReallyDirty(row) ? 'dirty-row' : ''\">\n <td class=\"first-column\">\n <span>{{row.FirstColValue}}</span>\n </td>\n @if (ColumnsMode === 'Fields') {\n <td *ngFor=\"let colName of JoinEntityDisplayColumns\">\n <input type=\"checkbox\" kendoCheckBox>\n </td>\n }\n @else {\n @for (cell of row.ColumnData; track cell) {\n <!-- loop through all the columns and display a checkbox and check it if we have a match in the current row -->\n <td (click)=\"_FlipRecord($event, row, cell)\"\n [ngClass]=\"IsCellReallyDirty(cell) ? 'dirty-cell' : ''\">\n <input type=\"checkbox\" \n kendoCheckBox \n [checked]=\"_IsColumnChecked(cell)\" \n (click)=\"_FlipRecord($event, row, cell, true)\">\n </td>\n }\n }\n </tr> \n } \n </tbody>\n </table>\n }\n</div>", styles: [".wrapper {\n overflow: auto;\n}\n\n/* Style for the whole table */\ntable {\n margin-left: 5px;\n margin-top: 5px;\n border-collapse: collapse; /* Ensures border collapse for a cleaner look */\n}\n\nbutton {\n margin-left: 5px;\n margin-top: 5px;\n width: 125px;\n}\n \ntable th {\n background-color: #f2f2f2; /* Light gray background for headers */\n color: black; /* Black text color for headers */\n font-weight: bold; /* Bold font weight for headers */\n cursor: pointer;\n}\n\n.permission-left-col {\n cursor: pointer;\n}\n\n/* Style for all table cells */\ntable th, table td {\n border: 1px solid gray; /* Gray border for cells */\n height: 36px; /* Fixed height for all rows */\n text-align: center;\n padding: 0 8px; /* Add some padding inside cells */\n}\n\n/* Specific styles for the first column */\ntable th:first-child, table td:first-child {\n min-width: 150px; /* Set width for the first column */\n text-align: left;\n}\n\n/* Specific styles for the \"Can\" columns */\ntable th:not(:first-child), table td:not(:first-child) {\n width: 100px; /* Set width for \"Can\" columns */\n}\n\n/* Alternating row background colors */\ntable tr:nth-child(odd) {\n background-color: white; /* Light color for odd rows */\n}\n\ntable tr:nth-child(even) {\n background-color: #e7f4ff; /* Light blue for even rows */\n}\n\ntable tr.dirty-row {\n font-style: italic;\n background-color: #ffcccc;\n}\n\ntable td.dirty-cell {\n font-style: italic;\n background-color: #ffcccc;\n}"] }]
|
|
438
|
+
}], () => [{ type: i0.ChangeDetectorRef }], { RowsEntityName: [{
|
|
439
|
+
type: Input
|
|
440
|
+
}], RowsEntityDisplayField: [{
|
|
441
|
+
type: Input
|
|
442
|
+
}], RowsEntityDataSource: [{
|
|
443
|
+
type: Input
|
|
444
|
+
}], RowsExtraFilter: [{
|
|
445
|
+
type: Input
|
|
446
|
+
}], RowsOrderBy: [{
|
|
447
|
+
type: Input
|
|
448
|
+
}], RowsEntityViewName: [{
|
|
449
|
+
type: Input
|
|
450
|
+
}], RowsEntityArray: [{
|
|
451
|
+
type: Input
|
|
452
|
+
}], ColumnsMode: [{
|
|
453
|
+
type: Input
|
|
454
|
+
}], ColumnsEntityName: [{
|
|
455
|
+
type: Input
|
|
456
|
+
}], ColumnsEntityDisplayField: [{
|
|
457
|
+
type: Input
|
|
458
|
+
}], ColumnsEntityDataSource: [{
|
|
459
|
+
type: Input
|
|
460
|
+
}], ColumnsExtraFilter: [{
|
|
461
|
+
type: Input
|
|
462
|
+
}], ColumnsOrderBy: [{
|
|
463
|
+
type: Input
|
|
464
|
+
}], ColumnsEntityViewName: [{
|
|
465
|
+
type: Input
|
|
466
|
+
}], ColumnsEntityArray: [{
|
|
467
|
+
type: Input
|
|
468
|
+
}], JoinEntityName: [{
|
|
469
|
+
type: Input
|
|
470
|
+
}], JoinEntityRowForeignKey: [{
|
|
471
|
+
type: Input
|
|
472
|
+
}], JoinEntityColumnForeignKey: [{
|
|
473
|
+
type: Input
|
|
474
|
+
}], JoinEntityDisplayColumns: [{
|
|
475
|
+
type: Input
|
|
476
|
+
}], CheckBoxValueMode: [{
|
|
477
|
+
type: Input
|
|
478
|
+
}], CheckBoxValueField: [{
|
|
479
|
+
type: Input
|
|
480
|
+
}], NewRecordDefaultValues: [{
|
|
481
|
+
type: Input
|
|
482
|
+
}] }); })();
|
|
483
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(JoinGridComponent, { className: "JoinGridComponent", filePath: "src/lib/join-grid/join-grid.component.ts", lineNumber: 24 }); })();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as i0 from "@angular/core";
|
|
2
|
+
import * as i1 from "./join-grid/join-grid.component";
|
|
3
|
+
import * as i2 from "@angular/common";
|
|
4
|
+
import * as i3 from "@angular/forms";
|
|
5
|
+
import * as i4 from "@progress/kendo-angular-dialog";
|
|
6
|
+
import * as i5 from "@progress/kendo-angular-grid";
|
|
7
|
+
import * as i6 from "@progress/kendo-angular-buttons";
|
|
8
|
+
import * as i7 from "@progress/kendo-angular-dropdowns";
|
|
9
|
+
import * as i8 from "@progress/kendo-angular-indicators";
|
|
10
|
+
import * as i9 from "@memberjunction/ng-container-directives";
|
|
11
|
+
export declare class JoinGridModule {
|
|
12
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<JoinGridModule, never>;
|
|
13
|
+
static ɵmod: i0.ɵɵNgModuleDeclaration<JoinGridModule, [typeof i1.JoinGridComponent], [typeof i2.CommonModule, typeof i3.FormsModule, typeof i4.DialogsModule, typeof i5.GridModule, typeof i6.ButtonsModule, typeof i7.DropDownsModule, typeof i4.DialogsModule, typeof i8.IndicatorsModule, typeof i9.ContainerDirectivesModule], [typeof i1.JoinGridComponent]>;
|
|
14
|
+
static ɵinj: i0.ɵɵInjectorDeclaration<JoinGridModule>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { NgModule } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { FormsModule } from '@angular/forms';
|
|
4
|
+
// Kendo UI Angular imports
|
|
5
|
+
import { DialogsModule } from "@progress/kendo-angular-dialog";
|
|
6
|
+
import { ButtonsModule } from '@progress/kendo-angular-buttons';
|
|
7
|
+
import { DropDownsModule } from '@progress/kendo-angular-dropdowns';
|
|
8
|
+
import { IndicatorsModule } from '@progress/kendo-angular-indicators';
|
|
9
|
+
// LOCAL
|
|
10
|
+
import { JoinGridComponent } from './join-grid/join-grid.component';
|
|
11
|
+
import { GridModule } from '@progress/kendo-angular-grid';
|
|
12
|
+
import { ContainerDirectivesModule } from '@memberjunction/ng-container-directives';
|
|
13
|
+
import * as i0 from "@angular/core";
|
|
14
|
+
export class JoinGridModule {
|
|
15
|
+
}
|
|
16
|
+
JoinGridModule.ɵfac = function JoinGridModule_Factory(t) { return new (t || JoinGridModule)(); };
|
|
17
|
+
JoinGridModule.ɵmod = /*@__PURE__*/ i0.ɵɵdefineNgModule({ type: JoinGridModule });
|
|
18
|
+
JoinGridModule.ɵinj = /*@__PURE__*/ i0.ɵɵdefineInjector({ imports: [CommonModule,
|
|
19
|
+
FormsModule,
|
|
20
|
+
DialogsModule,
|
|
21
|
+
GridModule,
|
|
22
|
+
ButtonsModule,
|
|
23
|
+
DropDownsModule,
|
|
24
|
+
DialogsModule,
|
|
25
|
+
IndicatorsModule,
|
|
26
|
+
ContainerDirectivesModule] });
|
|
27
|
+
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(JoinGridModule, [{
|
|
28
|
+
type: NgModule,
|
|
29
|
+
args: [{
|
|
30
|
+
declarations: [
|
|
31
|
+
JoinGridComponent
|
|
32
|
+
],
|
|
33
|
+
imports: [
|
|
34
|
+
CommonModule,
|
|
35
|
+
FormsModule,
|
|
36
|
+
DialogsModule,
|
|
37
|
+
GridModule,
|
|
38
|
+
ButtonsModule,
|
|
39
|
+
DropDownsModule,
|
|
40
|
+
DialogsModule,
|
|
41
|
+
IndicatorsModule,
|
|
42
|
+
ContainerDirectivesModule
|
|
43
|
+
],
|
|
44
|
+
exports: [
|
|
45
|
+
JoinGridComponent
|
|
46
|
+
]
|
|
47
|
+
}]
|
|
48
|
+
}], null, null); })();
|
|
49
|
+
(function () { (typeof ngJitMode === "undefined" || ngJitMode) && i0.ɵɵsetNgModuleScope(JoinGridModule, { declarations: [JoinGridComponent], imports: [CommonModule,
|
|
50
|
+
FormsModule,
|
|
51
|
+
DialogsModule,
|
|
52
|
+
GridModule,
|
|
53
|
+
ButtonsModule,
|
|
54
|
+
DropDownsModule,
|
|
55
|
+
DialogsModule,
|
|
56
|
+
IndicatorsModule,
|
|
57
|
+
ContainerDirectivesModule], exports: [JoinGridComponent] }); })();
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@memberjunction/ng-join-grid",
|
|
3
|
+
"version": "1.4.1",
|
|
4
|
+
"description": "MemberJunction: Grid component that is able to display/edit the relationship between two entities. For example being able to edit Users + Roles in a single grid.",
|
|
5
|
+
"main": "./dist/public-api.js",
|
|
6
|
+
"typings": "./dist/public-api.d.ts",
|
|
7
|
+
"files": [
|
|
8
|
+
"/dist"
|
|
9
|
+
],
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
12
|
+
"build": "ngc"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [],
|
|
15
|
+
"author": "",
|
|
16
|
+
"license": "ISC",
|
|
17
|
+
"devDependencies": {
|
|
18
|
+
"@angular/compiler": "~17.2.2",
|
|
19
|
+
"@angular/compiler-cli": "~17.2.2"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@angular/common": "~17.2.2",
|
|
23
|
+
"@angular/core": "~17.2.2",
|
|
24
|
+
"@angular/forms": "~17.2.2",
|
|
25
|
+
"@angular/router": "~17.2.2"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@memberjunction/core-entities": "~1.4.1",
|
|
29
|
+
"@memberjunction/global": "~1.4.1",
|
|
30
|
+
"@memberjunction/core": "~1.4.1",
|
|
31
|
+
"@memberjunction/ng-shared": "~1.4.1",
|
|
32
|
+
"@memberjunction/ng-container-directives": "~1.4.1",
|
|
33
|
+
"@progress/kendo-angular-buttons": "~15.1.0",
|
|
34
|
+
"@progress/kendo-angular-dialog": "~15.1.0",
|
|
35
|
+
"@progress/kendo-angular-layout": "~15.1.0",
|
|
36
|
+
"@progress/kendo-angular-grid": "~15.1.0",
|
|
37
|
+
"@progress/kendo-angular-indicators": "~15.1.0",
|
|
38
|
+
"tslib": "^2.3.0"
|
|
39
|
+
},
|
|
40
|
+
"sideEffects": false
|
|
41
|
+
}
|