Drag and Drop Regions in Oracle Apex Application
Recently we have worked on a project and we needed to implement drag and drop functionality into a classic report region to enable our users to drag some items and drop them in a drop region. The objective was to give the users a good User Experience when they work on the Application. At that time, we implemented the functionality using some JavaScript and CSS tricks. It worked fine, but it was not the best practice solution to use in Apex. By the time at working in Apex, we have learned some cool features which will make our drag and drop regions more efficient and it was worth to rebuild the regions again.
Now we would like to share our solution with you and show you how we have implemented this cool feature into our Application.
You will need a Workspace to follow with us. If you don't have one, go to apex.oracle.com and request a free Workspace.
To demonstrate the Idea we will work on a simple Project. Suppose we have a To-do list, and we want to change the To-do's status by dragging the Finished To-do from the Open To-do's Region and drop it into the Finished To-do's Region.
Here is the Table which we will work on:
CREATE TABLE TB_TODOS (
ID NUMBER GENERATED ALWAYS AS IDENTITY(START with 1 INCREMENT by 1),
TITLE VARCHAR2(50),
STATUS VARCHAR2(10)
);
Let's insert some dummy data to work with:
INSERT INTO TB_TODOS (TITLE, STATUS) values ('Buy bananas', 'open');
INSERT INTO TB_TODOS (TITLE, STATUS) values ('Buy apple', 'open');
INSERT INTO TB_TODOS (TITLE, STATUS) values ('Go to doctor', 'open');
INSERT INTO TB_TODOS (TITLE, STATUS) values ('Call Mohamad', 'open');
INSERT INTO TB_TODOS (TITLE, STATUS) values ('Go to Bank', 'open');
INSERT INTO TB_TODOS (TITLE, STATUS) values ('Buy orange', 'open');
So with this done let's create a new Project in Apex, navigate to the Project, go to Shared Component, choose Templates then click Create.
We will start by creating a custom template, the template type we need is a Report type and we will create it from scratch.
make sure to choose "Named Column (row template)"
Each row in the Report will have the structure:
<div>
<li data-id='#ID#' data-status='#STATUS#' class='todo-el' draggable=true>#TITLE#</li>
</div>
but we have to open an Html unordered list tag before all the list elements and close the tag after we finish rendering all the list items, we can achieve that by adding a ul open tag in Before Rows and ul close tag in After Rows like this:
Notice that all the list elements will have the class todo-el, and the unordered list element will have the class todos so we can target those elements in CSS. Also, each list element has the following attributes:
- data-id: to store custom data in each li element. In this case, we are storing an ID that will be replaced by the ID value of the Todo from our table. we will use this attribute later in Javascript.
- data-status: to store the To-do's status.
- draggable: specifies whether an element is draggable or not (Html5).
We can now create a classic report for the Open Todos based on our template.
Navigate to Page1 in our Application and add a new Classic Report region.
For the Report source choose the Table which we have already created:
Notice the Where Clause, we are querying only the Todos that have the status open.
Then go to the Report attributes, under the appearance options choose the template which we have already created:
(optional) Add the following CSS code in the page Inline Css:
.todos{
list-style-type: none;
}
.todo-el {
padding: 10px;
}
the CSS code is simply removing the default list style of the unordered list and it adds some padding to each list element.
Now we create the Finished Todo's Region, to do that we follow the same steps we did to create the Open Todo's Region but for the new Region we want only to show the Finished Todos:
We want to give the Region static Id finished and do some changes in the Layout so the two regions will be displayed next to each other:
We should now listen to the drop event, to achieve that we will add ondragover and ondrop event attributes for both Region, select both regions, go to Advanced > Custome Attributes and add the code below:
ondragover='handleDragover(event)'
ondrop='handleDrop(event)'
- ondragover: fires when a draggable element is being dragged over a valid drop target.
- ondrop: occurs when a draggable element is dropped on a valid drop target.
With this done, we can now start handling the drag and drop events...
First, let's handle the drag functionality by defining the handledrag function at the page level. Copy the code below into the Global Functions in your page:
function handleDrag(event) {
var data = {id: event.target.dataset.id, status: event.target.dataset.status};
var json_data = JSON.stringify(data);
event.dataTransfer.setData('data', json_data);
}
Before we handle the drop event we should create an Ajax callback process which we will call when we drop a Todo item. The process then will update the Todo's status in the Database.
Go to the page processes and create an Ajax Process:
Add the code below:
IF apex_application.g_x01 = 'open' THEN
UPDATE TB_TODOS SET STATUS = 'finished' WHERE ID = apex_application.g_x02;
ELSE
UPDATE TB_TODOS SET STATUS = 'open' WHERE ID = apex_application.g_x02;
END IF;
Now go back to the page's global function and add the code below to handle the drop event:
function handleDragover(event){
event.preventDefault();
}
function handleDrop(event){
var id = JSON.parse(event.dataTransfer.getData('data')).id;
var status = JSON.parse(event.dataTransfer.getData('data')).status;
apex.server.process(
'Update Todo',
{
x01: status,
x02: id
},
{
success: function(){
apex.event.trigger('#open', 'apexrefresh');
apex.event.trigger('#finished', 'apexrefresh')
},
dataType: 'text'
});
}
So that's it :), we hope you liked it. In the next post, we will configure the functionality to make it works on the Touch screen devices.
Here is a demo application if you want to test the functionality demo.
You can find the source code on Github.
we also have published a video on Youtube while we are creating a demo application, you can also watch it:
Some References:
- https://www.w3schools.com/tags/att_global_draggable.asp
- https://www.w3schools.com/jsref/event_ondrag.asp
- https://www.w3schools.com/tags/ev_ondrop.asp
- https://www.w3schools.com/tags/ev_ondragover.asp
- https://docs.oracle.com/cd/E71588_01/AEAPI/apex-server-namespace.htm#GUID-45B43DB1-9601-4BD6-9B7C-6C41C35BEE49
Labels: apex, javascript, lowcode
7 Comments:
thank you for the great tutorial :)
I am looking forward to more!
This comment has been removed by the author.
Thanks for this tutorial.
I encountered one problem. Every drag and drop no matter where you drop it results with update. If dragged and dropped in the same div, it will always execute update.
Hi Goran,
Thank you for reporting the problem. The solution is simply to add a different handleDrop function for each Region and check the value of the todo's status when you drop it.
This will be the drop handler when you drop an item into the finished region:
function handleDropFinished(event){
var id = JSON.parse(event.dataTransfer.getData('data')).id;
var status = JSON.parse(event.dataTransfer.getData('data')).status;
if(status === 'open'){
apex.server.process(
'Update Todo',
{
x01: status,
x02: id
},
{
success: function(pData){
apex.event.trigger('#open', 'apexrefresh');
apex.event.trigger('#finished', 'apexrefresh')
},
dataType: 'text'
}
);
}
}
Don't forget to change the ondrop handler in the region attribute. And do the same for the Open Region.
Thanks alot for this tutorial , how to implement order in this scenario.
Thank you very much for sharing, they are very good and very useful.
Cheers
Many Thanks, All working fine.
Dear, I need your support why this drag and drop not working in Touch Punch. I need your guidance ASAP.
Post a Comment
Note: Only a member of this blog may post a comment.
Subscribe to Post Comments [Atom]
<< Home