-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtemplate-104.html
258 lines (240 loc) · 11.5 KB
/
template-104.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
<h1 id="event-handling-and-event-listeners-in-formatter">Event handling and event listeners in formatter</h1>
<p>If your custom formatter contains some input elements or controls, it's important to bind data back to Grid's internal data source when users input new data through the UI from your custom formatter. Remember, the same element will be used on different rows due to the row virtualization mechanic. If the data is changed by user actions, you need to update the change back to Grid's data source, or else the binding mechanism will replace what the user has changed with the data stored from the Grid's internal source. </p>
<p>In short, data should be updated after users interact with the UI input. <code>getRelativePosition()</code> method should be used to resolve current positions relative to the grid element.</p>
<blockquote>
<p>APIs for data manipulation can be found <a href="#/data/update">here</a>. APIs for Grid and <code>getRelativePosition()</code> method description can be found <a href="#/apis/rt-grid/grid">here</a>.</p>
</blockquote>
<h2 id="the-reverted-problem">The 'reverted' problem</h2>
<p>When we don't set data back, row virtualization will not work properly and content will not be rendered properly. Suppose that we have a dropdown element in one of the grid columns. Any change that is done to the dropdown box will be reverted if we don't update the data.</p>
<p>In the live example below, try the following steps to produce the problem:</p>
<ol>
<li>Change the selected option from the dropdown box on the first row. Remember the new selected option</li>
<li>Scroll down to the bottom of the grid</li>
<li>Scroll back up to the top of the grid</li>
</ol>
<code-sandbox hash="397c9c8d"><pre><code class="language-css">efx-grid {
height: 200px;
margin-bottom: 40px;
}
</code></pre>
<pre><code class="language-html"><efx-grid></efx-grid>
</code></pre>
<pre><code class="language-javascript">import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
await halo(); // This line is only required for demo purpose. It is not relevant for your application.
/* ---------------------------------- Note ----------------------------------
DataGenerator, Formatters and extensions are exposed to global scope
in the bundle file to make it easier to create live examples.
Importing formatters and extensions is still required in your application.
Please see the document for further information.
---------------------------------------------------------------------------*/
var fields = ["id", "dropdownVal", "boolean", "text"];
// For static data initialization
var records = [];
for (var i = 0; i < 50; i++) {
var record = {};
record[fields[0]] = i;
record[fields[1]] = i % 4;
record[fields[2]] = i & 1 ? true : false;
record[fields[3]] = i + " Some Texts";
records.push(record);
}
var dropdownFormatter = function(e) {
var cell = e.cell;
var dropdown = cell.getContent();
if (!dropdown || !dropdown._myDropdown) {
dropdown = document.createElement("select");
dropdown._myDropdown = true;
[0, 1, 2, 3].forEach(function(val) {
var option = document.createElement("option");
option.value = val;
option.textContent = "Value " + val;
dropdown.appendChild(option);
});
}
dropdown.selectedIndex = e.data;
cell.setContent(dropdown);
};
var configObj = {
columns: [
{ name: "Row Index", field: fields[0], width: 80 },
{ name: "Dropdown", field: fields[1], binding: dropdownFormatter },
{ name: "Dropdown Value", field: fields[1] },
{ name: "Column 3", field: fields[2], alignment: "center" },
{ name: "Column 4", field: fields[3] }
],
staticDataRows: records
};
var grid = document.getElementsByTagName("efx-grid")[0];
grid.config = configObj;
</code></pre>
</code-sandbox><p>You will see that the selected option is reverted back to the original option.</p>
<h2 id="the-fix">The fix</h2>
<p>To avoid the problem, we have to add an event listener to our custom formatter for binding the change from users. You have added <code>dropdownChangeHandler</code> to fix the problem as shown below:</p>
<code-sandbox hash="1ab010b7"><pre><code class="language-css">efx-grid {
height: 200px;
margin-bottom: 40px;
}
</code></pre>
<pre><code class="language-html"><efx-grid></efx-grid>
</code></pre>
<pre><code class="language-javascript">import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
await halo(); // This line is only required for demo purpose. It is not relevant for your application.
/* ---------------------------------- Note ----------------------------------
DataGenerator, Formatters and extensions are exposed to global scope
in the bundle file to make it easier to create live examples.
Importing formatters and extensions is still required in your application.
Please see the document for further information.
---------------------------------------------------------------------------*/
var fields = ["id", "dropdownVal", "boolean", "text"];
// For static data initialization
var records = [];
for (var i = 0; i < 50; i++) {
var record = {};
record[fields[0]] = i;
record[fields[1]] = i % 4;
record[fields[2]] = i & 1 ? true : false;
record[fields[3]] = i + " Some Texts";
records.push(record);
}
// Show how to render custom content with an event listener
var dropdownFormatter = function(e) {
var cell = e.cell;
var dropdown = cell.getContent();
if (!dropdown || !dropdown._myDropdown) {
dropdown = document.createElement("select");
dropdown._myDropdown = true;
[0, 1, 2, 3].forEach(function(val) {
var option = document.createElement("option");
option.value = val;
option.textContent = "Value " + val;
dropdown.appendChild(option);
});
dropdown.addEventListener("change", dropdownChangeHandler);
}
dropdown.selectedIndex = e.data;
cell.setContent(dropdown);
};
// Show how to set data based on interaction from custom content
var dropdownChangeHandler = function(e) {
var dropdown = e.currentTarget;
var selectedIndex = +(dropdown.options[dropdown.selectedIndex].value);
var pos = grid.api.getRelativePosition(e);
var rowDef = grid.api.getRowDefinition(pos.rowIndex);
rowDef.setData(grid.api.getColumnField(pos.colIndex), selectedIndex);
};
var configObj = {
columns: [
{ name: "Row Index", field: fields[0], width: 80 },
{ name: "Dropdown", field: fields[1], binding: dropdownFormatter },
{ name: "Dropdown Value", field: fields[1] },
{ name: "Column 3", field: fields[2], alignment: "center" },
{ name: "Column 4", field: fields[3] }
],
staticDataRows: records
};
var grid = document.getElementsByTagName("efx-grid")[0];
grid.config = configObj;
</code></pre>
</code-sandbox><h2 id="writing-event-listeners">Writing event listeners</h2>
<p>Since the same element will be used on different rows, you cannot use closure variables that are created or given from the event arguments. Row index, column index, or cell reference must be resolved at runtime inside the event listener. You can resolve the position by using Grid's <code>getRelativePosition()</code> method.</p>
<pre><code class="language-js"> var dropdownChangeHandler = function(e) {
var dropdown = e.currentTarget;
var selectedIndex = +(dropdown.options[dropdown.selectedIndex].value);
var pos = grid.api.getRelativePosition(e);
var rowDef = grid.api.getRowDefinition(pos.rowIndex);
rowDef.setData(grid.api.getColumnField(pos.colIndex), selectedIndex);
};
</code></pre>
<ul>
<li><code>currentTarget</code> property will always give an element attached by the event listener</li>
<li><code>getRelativePosition()</code> method resolves the position when the dropdown value is changed</li>
</ul>
<blockquote>
<p>See <a href="#/data/update">this page</a> on how to update data.</p>
</blockquote>
<h3 id="getting-column-and-row-information-from-clicked-content-example">Getting column and row information from clicked content example</h3>
<code-sandbox hash="9f180ff2"><pre><code class="language-css">html hr {
margin: 5px;
}
textarea {
width: 100%;
height: 80px;
font-size: 18px;
}
efx-grid {
height: 300px;
}
</code></pre>
<pre><code class="language-html"><textarea id="msg_ta"></textarea>
<hr>
<efx-grid></efx-grid>
</code></pre>
<pre><code class="language-javascript">import { halo } from './theme-loader.js'; // This line is only required for demo purpose. It is not relevant for your application.
await halo(); // This line is only required for demo purpose. It is not relevant for your application.
/* ---------------------------------- Note ----------------------------------
DataGenerator, Formatters and extensions are exposed to global scope
in the bundle file to make it easier to create live examples.
Importing formatters and extensions is still required in your application.
Please see the document for further information.
---------------------------------------------------------------------------*/
var onButtonClicked = function(e) {
var pos = grid.api.getRelativePosition(e);
var field = grid.api.getColumnField(pos.colIndex);
var rowDef = grid.api.getRowDefinition(pos.rowIndex);
var ary = [
"Field: " + field,
"Row Data: " + JSON.stringify(rowDef.getRowData())
];
msg_ta.textContent = ary.join("\n");
};
var fields = ["id", "companyName", "market", "CF_NETCHNG"];
var columnNames = ["Id", "Company Name", "Market", "Net Chng."];
var columns = fields.map(function(f, idx) {
return {
field: f,
name: columnNames[idx]
}
});
columns.push({
field: "Field A",
name: "Action 1",
width: 70,
alignment: "c",
binding: function(e) {
var cell = e.cell;
var content = cell.getContent();
if(!content) {
content = document.createElement("button");
content.textContent = "A";
content.addEventListener("click", onButtonClicked);
}
cell.setContent(content);
}
});
columns.push({
field: "Field B",
name: "Action 2",
width: 70,
alignment: "c",
binding: function(e) {
var cell = e.cell;
var content = cell.getContent();
if(!content) {
content = document.createElement("button");
content.textContent = "B";
content.addEventListener("click", onButtonClicked);
}
cell.setContent(content);
}
});
var records = DataGenerator.generateRecords(fields, {seed: 1, rowCount: 30});
var configObj = {
columns: columns,
staticDataRows: records
};
var grid = document.getElementsByTagName("efx-grid")[0];
grid.config = configObj;
</code></pre>
</code-sandbox><br>
<br>
<br>