Drag and Drop – Ask Me Anything April 2023

One of the cool things that came out of the latest in our regular Ask Me Anything about OIA Sessions (the most recent one was on April 21, so look out for the next monthly event, it’s completely free and a fun opportunity to share and discuss how Oracle Intelligent Advisor is going, or you would like it to go!) was a discussion about the User Experience and how to achieve various things in a current version Interview. So it was with a good heart that we decided to look at that very common modern user experience feature in the next couple of articles – the “drag and drop”. We will consider how to create a drag and drop feature to let the user “select” some instances of an entity.

In these articles we will consider the mechanics of the process and how we can implement drag and drop in Oracle Intelligent Advisor without too much code. So let’s get stuck in.

Entity Collect or Container

For our drag and drop example, we included an entity collect – so you can create entity instances and then drag them somewhere. But the process would work with an Entity Container as well. In both cases, we need to have a Tabular experience – because with a Tabular layout, we can see multiple rows and choose which ones to drag (or not). We can begin by placing two containers on our layout, and adding an Entity Container to one of them. This assumes you have created the entity that you want people to “drag“. I have added a few attributes to the entity just to make it look a little more interesting. And the most important attribute in our case is the “selected” control. We will use this to work out which instances have been “dragged and dropped”. The other Container is the place to “drop“.

And we can add some styling to be able to distinguish the drag and drop areas. The idea of using Containers and styling them with a specific style will come in very useful shortly. The container on the left will hold the Entity Container and the container on the right will be the “droppable” zone.

This gives the following in the debugger, once you fiddle about with the window size.

Draggable

With current version interviews leveraging jQuery out of the box, it seems logical to use the jQuery UI “draggable” and “droppable” widgets. This means we only have to add the jQuery UI files to our project in the usual location.

Once we have these files in place, we need to handle three different situations in the case demonstrated:

  1. When the initial mount occurs, ensure that any instances that are displayed (because they exist already) can be “dragged”.
  2. Every time the list of instances is updated (because someone is adding or removing an instance) that the new instance is “draggable”
  3. Ensuring that any instance that is already “dragged” cannot be “dragged” again.

The final scenario which we will deal with in the next post in this series, is what happens when a user deletes an instance that has already been “dragged”.

There are quite a few things to be aware of:

Newly created instances will only exist in the client side – so doing interview.getValue() for an instance that has just been created will return nothing at all. You’ll need to go and dig into the interview._session and retrieve the clientSide values.

The styles we applied to the Containers will allow us to target the entity container, for example:

	$(".ContainerClassDrag > div > table > tr").draggable({
							revert: function () {
								if (instanceref.dragged_selected == true) {
									return false;
								} 
							},
							opacity: 0.7,
							helper: "clone"
						});

The jQuery draggable widget lets us specify that each row of the entity collect is “draggable” and should be shown on screen as a “clone” of the row with an opacity of 0.7. Note the check to see if the “selected” attribute is “true”. That will have to be a reference to the instance via the clientSide. Something like this (just for fun, and not suggested as a real-life answer but you will get the idea:

var instanceref = interview._session.screen.clientState.draggable_ent[$(ui.draggable).closest("[aria-label != ''][aria-label]").attr("aria-label")];

This evaluates to:

In the interview session, in the client, find the entity named “draggable_ent” and in the array of instances, select the instance that possesses an aria-label. Why? Because the “aria-label” contains the instance identifier – which we can use in our code later. So instanceref might be “the draggable entity1” or “the draggable entity31” or whatever is the instance you are “dragging”. If it helps, here is the HTML :

Clearly we are relying on the tabular structure of the entity collect to be able to get the identifier. Notice how each “row” represents the entity instance. Inside the “TR” you will find the “TD” collection and the “INPUT” controls that represent the entity instance attribute values.

So the update code (which should fire each time something interesting happens, to ensure that every TR is “draggable”) needs to fire frequently. You could put it in any control that has an update key – we’ve used a label for this demo.

Droppable

So what happens when we drop the item on the “droppable” container? That’s entirely up to us. We want to

  1. Update the “selected” flag to be able to see which instances have already been dragged and dropped
  2. Display something useful in the dropped area to remind us which items have been dropped
  3. Offer the user a way to remove the dropped item, resetting the “selected” flag and removing the item.

The jQuery UI widget provides $(ui.draggable) which is a reference to the thing you are dragging. So we can extract information from it (since it will be our TR from the entity collect) and decide what to do. In the demonstration, we remove most of the contents of the TR and just show some text to remind you which item you dragged.

We will also leverage the entity instance to update the “selected” flag. And we can stop the drag if you are dragging something that has already been selected.

Finally we can append a button to the TR and let the user click it to remove the dragged item, and unset the selected flag.

That’s a lot going on. Here’s the result so far:

The “drop” part of the code looks a little like this, as an example:

drop: function (event, ui) {
							var instanceref = interview._session.screen.clientState.draggable_ent[$(ui.draggable).closest("[aria-label != ''][aria-label]").attr("aria-label")];
							var droppperref = $(ui.draggable).closest("[aria-label != ''][aria-label]").attr("aria-label");
							
									if (instanceref.dragged_selected == false) {
										var button = document.createElement("button");
										button.id = "button_" + droppperref;
										var extracell = document.createElement("td");
										extracell.id = "cell_" + droppperref;
										extracell.innerHTML = "( Entity Id " + instanceref.dragged_entity + " Entity # " + instanceref.dragged_number + " Entity Date " + instanceref.dragged_date + ")"
											button.innerHTML = "Remove";
										button.type = "button";
										extracell.appendChild(button);
										button.onclick = function () {
											interview.setInputValue("dragged_selected", false, "draggable_ent", $(ui.draggable)[0].getAttribute("aria-label"));
											$(this).closest("tr").remove();
											return true;
										}
										$(event.target).append($(ui.draggable.clone()));
										$(event.target).find('.opa-control').remove();
										$(event.target).find('td:last').after(extracell);
										interview.setInputValue("dragged_selected", true, "draggable_ent", $(ui.draggable)[0].getAttribute("aria-label"));
									}
							}

Most of it is concerned with either updating the “dragged_selected” attribute depending on whether you are dropping (“true”) or removing from the dropped list (“false”). The rest is mostly cosmetic to either remove things from the TR or add things (the extra TD with our button in it, for example).

In the next part of the post we will tidy up various parts of the process and we will provide a complete walk-through of the example with the code attached for your own entertainment.

Author: Richard Napier

After 8 years in case management and ERP software roles, Richard Napier joined Siebel Systems in 1999 and took up the role of managing the nascent Siebel University in Southern Europe. He subsequently was Director of Business Development and Education for InFact Group (now part of Business & Decisions) for 8 years. He now runs Intelligent Advisor IT Consulting OÜ. Owner of intelligent-advisor.com, he also is Co-Founder of the Siebel Hub.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Intelligent Advisor IT Consulting Serving Customers Worldwide
Hide picture