Documente Academic
Documente Profesional
Documente Cultură
In this section, I shall discuss some special tips and techniques offered by
Forms with respect to lists and list items.
List items appear as either drop-down list boxes, T-lists, or combo boxes in
Forms. Mostly, list items have static values as their elements, created during
design time. However, there arises a need to populate a list item with
elements based on runtime criteria or from a database table. For example, one
might populate a drop-down list box with all the state codes from a look-up
table named STATE_TAB. This can be done either using a query or adding
elements one by one at runtime. This way of populating list items
programmatically without hard-coding their values at design time is what is
termed dynamically populating list items.
This technique involves populating the list with a query or without a query. I
will discuss populating by means of a query because it is very powerful and
efficient.
Tip
Never try to populate a list item using a query directly. Always create and
populate a query record group, and use this record group to do the job.
DECLARE
rg_list_id RECORDGROUP;
ret_code NUMBER;
v_select VARCHAR2(300);
BEGIN
rg_list_id := FIND_GROUP(rg_name);
DELETE_GROUP(rg_list_id);
END IF;
ret_code := POPULATE_GROUP(rg_list_id);
POPULATE_LIST('LIST_ITEM','RG_LIST');
DELETE_GROUP(rg_list_id);
END;
Tip
Use a form procedure, passing the input query and list item name as
parameters.
A nonquery record group can also be used instead of a query record group,
provided that it is created programmatically using CREATE_GROUP and
populated using POPULATE_GROUP or POPULATE_GROUP_WITH_QUERY.
The label column has its values derived from the NAME column. The value
corresponding to each NAME is derived from the ID column and should be
stored in the list item as a character value. This requires the use of TO_CHAR.
Therefore, the query text in the preceding example changes to
After populating the list, the value can be accessed by doing a reconversion to
NUMBER using the TO_NUMBER function. The following shows how to access
the ith element from the list discussed in the preceding example:
DECLARE
v_id NUMBER;
v_id_char VARCHAR2(6);
item_id ITEM;
BEGIN
item_id := FIND_ITEM('LIST_ITEM');
IF ID_NULL(item_id) THEN
MESSAGE('Invalid List');
RAISE FORM_TRIGGER_FAILURE;
END IF;
v_id := TO_NUMBER(v_id);
END LOOP;
END;
Tip
On input to the list, use TO_CHAR for both date and numeric values that
correspond to the Value column of the list.
On output from the list, use TO_DATE and TO_NUMBER, respectively, for date
and numeric values.
Use these in the SELECT column list, which is used to populate the list.
How many of you are aware of the fact that in Forms, you can add elements
to the beginning of an already populated list item without repopulating it?
This seems trivial at first thought but is a very powerful and flexible
technique to be used in many demanding situations.
Use ADD_LIST_ELEMENT and specify the constant 1 for the element index.
This displaces all the existing elements to one position below and makes
room for the new element with index number 1. Do not specify the constant
0 instead of 1.
Use ADD_LIST_ELEMENT and specify the index number of the new element as
where current element is the element after which the new element should
be added. This displaces all the remaining elements to one position below and
makes room for the new element.
To add to the end of the list, specify the constant returned by
GET_LIST_ELEMENT_COUNT, which gives the number of existing elements,
and then specify the index of the new element as the value of this constant
incremented by 1.
DECLARE
cnt NUMBER := 0;
BEGIN
cnt := GET_LIST_ELEMENT_COUNT(list_id);
END;
In this example, you take the count of the list elements and increment it by 1.
This value serves as the index for the new list element to be added. This
works even when the list is wholly empty, because you initialize the count to
zero before incrementing it by 1. Therefore, it adds the first element in case
of an empty list.
Drill-down LOVs are very useful for tables involving recursive and/or parent-
child relationships. Examples of such relationships are those involving a
department and its employees, a manager and employees, or a company and
its hierarchical representation.
LOVs are a commonly required feature of any application involving this kind
of look-ups. The features of LOVs supported by Forms are limited in the
sense that
You will use a T-list and dynamically populate it using a record group. The
drill-down is achieved by dynamic replacement of the same record group
query again and again till there is no further drill-down. Double-clicking a
parent element will show this parent element and all its children one level
below. The user "drills down" the LOV to reach a deeper level. The operation
is repeatable until leaf elements are reached. The string '- Parent' is
appended to the parent element label to identify it as the parent. This element
is always the first element of the list, irrespective of whether it has children.
Double-clicking a parent element will show its parent and all its children, that
is, one level above. The user "drills up" the LOV to reach a higher level. The
operation is repeatable until the root element is reached. Once at the root, the
original list is restored; that is, all EMPNOs that exist as MGRs. The string '-
Parent' is still appended to the parent element label until the initial list is
restored.
The same T-list and the same record group are reused for the drill-down and
drill-up operations.
The property class PC_TLIST has its properties set as shown in Figure
1.7.
Figure 1.7. A property class named PC_TLIST for the T-list item LOV.
Tip
Remember to create a NULL list element; that is, both the label and its value
are NULL. NULL means a null value, not the string 'NULL'.
The LOV functions the following way. At first, all the employees at
the parent level are displayed. The query for doing this follows:
WHEN-NEW-FORM-INSTANCE
DECLARE
query_in VARCHAR2(32767) :=
FROM emp
BEGIN
RAISE FORM_TRIGGER_FAILURE;
END IF;
END;
88. The right place for the drill-down code is the WHEN-LIST-
ACTIVATED trigger:
89.
90. DECLARE
91.
92. query_in VARCHAR2(32767);
93.
94. item_name VARCHAR2(100) :=
NAME_IN('SYSTEM.TRIGGER_ITEM');
95.
96. retcd NUMBER;
97.
98. current_rows_mgr NUMBER;
99.
100. current_rows_empno NUMBER;
101.
102. BEGIN
103.
104. query_in :=
105.
106. 'select LPAD(ename, ((LEVEL-
1)*4+LENGTH(ename)), '''')||
107.
108. DECODE(TO_CHAR(empno), '||
109.
110. NAME_IN(item_name)||', ''- Parent'', NULL)
ename, TO_CHAR(empno) '||
111.
112. ' FROM emp '||'WHERE empno = '||
TO_NUMBER(NAME_IN(item_name))||
113.
114. 'or mgr = '||
TO_NUMBER(NAME_IN(item_name))||
115.
116. ' START WITH empno = '||
117.
118. TO_NUMBER(NAME_IN(item_name))||'CONNECT BY
PRIOR empno = mgr';
119.
120.
121.
122. ||
123.
124.
125.
126. p_populate_list(item_name, query_in, retcd);
127.
128. END;
129.
130. The WHEN-LIST-ACTIVATED trigger is modified as follows (the
following listing shows the complete code) to accomplish both drill-
down and drill-up:
131.
132. WHEN-LIST-ACTIVATED
133.
134.
135.
136. DECLARE
137.
138. query_in VARCHAR2(32767);
139.
140. item_name VARCHAR2(100) :=
NAME_IN('SYSTEM.TRIGGER_ITEM');
141.
142. retcd NUMBER;
143.
144. current_rows_mgr NUMBER;
145.
146. current_rows_empno NUMBER;
147.
148. BEGIN
149.
150. IF INSTR(GET_LIST_ELEMENT_LABEL(item_name,
1),'Parent', 1) = 0 THEN
151.
152. -- if current element is in the initial list
153.
154. query_in :=
155.
156. 'SELECT LPAD(ename, ((LEVEL-
1)*4+LENGTH(ename)), '''') ||
157.
158. DECODE(TO_CHAR(empno), '||
159.
160. NAME_IN(item_name)||',''- Parent'',NULL)
ename, TO_CHAR(empno)'||
161.
162. 'FROM emp '||
163.
164. 'WHERE empno = '||
TO_NUMBER(NAME_IN(item_name))||'or mgr = '||
165.
166. TO_NUMBER(NAME_IN(item_name))||
167.
168. 'START WITH empno = '||
TO_NUMBER(NAME_IN(item_name))||
169.
170. 'CONNECT BY PRIOR empno = mgr ';
171.
172. ELSIF INSTR(GET_LIST_ELEMENT_LABEL(item_name,
1),'Parent', 1) > 0 and
173.
174. (TO_NUMBER(GET_LIST_ELEMENT_VALUE(item_name
,1))
175.
176.
177.
178.
179.
180. != TO_NUMBER(NAME_IN(item_name))) THEN
181.
182. -- if current is a child of a parent
183.
184. query_in :=
185.
186. 'SELECT LPAD(ename, ((LEVEL-
1)*4+LENGTH(ename)), '''') ||
187.
188. DECODE(TO_CHAR(empno), '||
189.
190. NAME_IN(item_name)||', ''- Parent'',NULL)
ename, TO_CHAR(empno)'||
191.
192. 'FROM emp '||
193.
194. 'WHERE empno = '||
TO_NUMBER(NAME_IN(item_name))||'or mgr = '||
195.
196. TO_NUMBER(NAME_IN(item_name))||
197.
198. 'START WITH empno = '||
TO_NUMBER(NAME_IN(item_name))||
199.
200. 'CONNECT BY PRIOR empno = mgr ';
201.
202. ELSIF INSTR(GET_LIST_ELEMENT_LABEL(item_name,
1),'Parent', 1) > 0 AND
203.
204. (TO_NUMBER(GET_LIST_ELEMENT_VALUE(item_name,1)
)
205.
206. = TO_NUMBER(NAME_IN(item_name))) THEN
207.
208. -- if current element is a parent
209.
210. BEGIN
211.
212. current_rows_empno :=
TO_NUMBER(NAME_IN(item_name));
213.
214. MESSAGE(TO_CHAR(current_rows_empn
o), ACKNOWLEDGE);
215.
216. SELECT mgr
217.
218. INTO current_rows_mgr
219.
220. FROM emp
221.
222. WHERE empno =
current_rows_empno;
223.
224. EXCEPTION WHEN NO_DATA_FOUND THEN
NULL;
225.
226. END;
227.
228. IF current_rows_mgr IS NOT NULL THEN
229.
230. query_in :=
231.
232. 'SELECT LPAD(ename, ((LEVEL-
1)*4+LENGTH(ename)), '''') ||
233.
234. DECODE(TO_CHAR(empno), '||
TO_CHAR(current_rows_mgr)||
235.
236. ', ''- Parent'', NULL) ename,
TO_CHAR(empno) '||
237.
238. 'FROM emp '||
239.
240. 'WHERE empno = '||current_rows_mgr||'or mgr =
'||current_rows_mgr||
241.
242. 'START WITH empno = '||current_rows_mgr||
243.
244. 'CONNECT BY PRIOR empno = mgr ';
245.
246. ELSE
247.
248. query_in := 'SELECT ename, TO_CHAR(empno)
empno FROM emp WHERE
249.
250. empno IN (SELECT mgr FROM
emp)';
251.
252. END IF;;
253.
254. END IF;
255.
256. p_populate_list(item_name, query_in,
retcd);
257.
258. END;
259.
Figures 1.8 through 1.10 depict the drill-down operation on the sample list
discussed here. The parent for the second level is suffixed with the phrase '-
Parent' to mark it as the parent element for the children displayed below it.
The Find feature of LOVs enables you to enlarge or reduce the LOV list as
the user types in characters of the LOV element value. This feature can be
simulated using COMBO BOX and T-LIST type list items in Forms 4.5.
Although it doesn't use the exact mechanism offered by LOVs, the method
described here imitates the same functionality. You will assume that the list
to be displayed is SITE_NAME, based on the SITE_TAB table. The SITE_TAB
table has the following structure: