[KULRICE-10302] Analysis - Results not on the current page are not returned by multivalue lookup's "return selected" action Created: 27/Aug/13  Updated: 21/Apr/14  Resolved: 15/Oct/13

Status: Closed
Project: Kuali Rice Development
Component/s: Analysis, KNS Equivalency
Affects Version/s: None
Fix Version/s: 2.4
Security Level: Public (Public: Anyone can view)

Type: Task Priority: Major
Reporter: Steve Manning (Inactive) Assignee: Sona Sona (Inactive)
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: 0 minutes
Time Spent: 2 days
Original Estimate: 1 day, 4 hours

Attachments: XML File DemoCollectionLookup.xml     Text File krad_widget_js_.patch    
Issue Links:
Discovered
discovered KULRICE-10892 Multi Value Return lookup not working... Closed
Relate
relates to KULRICE-10534 Multivalue lookup server side select ... Closed
Rely
relies on KULRICE-10534 Multivalue lookup server side select ... Closed
Similar issues:
KULRICE-3219Move 'return selected' button location on multivalue lookups
KULRICE-7223Multivalue lookup not returning results
KULRICE-7256Multivalue lookup return not refreshing
KULRICE-11214MultiValue Lookup - select only on this page and then deselect only on this page the return select button stays clickable.
KULRICE-124012.4.0 CDT: Multivalue Lookup returned incident report on return selected
KULRICE-10535Multivalue Global Hander Disable/Enable of return selected button
KULRICE-9914Hitting certain buttons on a multivalue Lookup Results page after items have been selected results in a stack trace
KULRICE-9938Field values for a multivalue lookup aren't returned correctly if lookup results fields are null
KULRICE-10977Multi Value Lookup : Implement server side paging for both rich and non rich tables when data selected is not on current page
KULRICE-3616Return Selected button on multivalue lookup has black border
Rice Module:
KRAD
KRAD Feature Area:
Multi-Value Lookup
Sprint: 2.4.0-m2 KRAD Sprint 4
KAI Review Status: Not Required
KTI Review Status: Not Required
Code Review Status: Not Required
Include in Release Notes?:
Yes

 Description   

If a user opens a multivalue lookup, selects all rows available, and some of the rows are not on the current page (for instance, a results set limit size of 10 is being used, and there are 25 results), the rows on the current page will be returned successfully, but the rows on non-displayed pages will not be returned to the original form.

Do the requisite analysis to determine what needs to be done.



 Comments   
Comment by Sona Sona (Inactive) [ 03/Oct/13 ]

Data table only retains elements on the visible page within the DOM. To be able to preserve selections from hidden pages, we need to extract those elements from the datatable and re-insert them back into the form
http://datatables.net/forums/discussion/185/submitting-forms-with-fields-on-hidden-pages/p1

A solution has been proposed at this link
http://datatables.net/examples/api/form.html

Based on the above solution I have added this logic to the setupMultiValueReturn() in krad.widgets.js. This is a presubmit call to the return selected action. Here is the code:

  // Find all the input type: hidden elements in the data table
    var oTable = jQuery('.dataTable').dataTable();
    var sData = jQuery('input:hidden', oTable.fnGetNodes()).serializeArray();

    // For each hidden element insert it back to the form
    jQuery.each(sData, function(i, field){

        jQuery('<input>').attr({
            type: 'hidden',
            id: field.id,
            name: field.name,
            value: field.value
        }).appendTo('#'+kradVariables.KUALI_FORM);    });

I tested it locally and the solution works for MVL returns from multiple pages.

Comment by Sona Sona (Inactive) [ 03/Oct/13 ]

Attached is a patch file with the above code. Created a review for the same https://fisheye.kuali.org/cru/rice-300

Comment by Sona Sona (Inactive) [ 11/Oct/13 ]

There are three issues that I am looking at which are intertwined and related to multivalue lookup.

1. With pagination on the lookup results, only selections from the visible page are returned
2. When server side paging is enabled, selection from the non visible pages are not retained as you move through the pages.
3. With server side paging and non dataTable rendering "Return Selected" button does not get enabled when clicking on a checkbox.

Currently in multi value lookup, the results are displayed client side (no server paging) using dataTables. All the javascript functions to enable return selected, process result submission assume that there is a dataTable in the DOM.

I have setup examples to enable server side paging both with and without dataTable by providing a custom viewName to the quickFinder. I have attached the XML for reference.

For item 1. The pagination causes the dataTable to remove all rows from the DOM except the ones on the visible page. So, dataTables need to be handled differently in javascript, so that it can use the plugin api to extract the selected records from non visible page. This is also why we can't use the jQuery class based selector for retrieving selected checkbox input fields.

For item 2. Server side paging with or without dataTable causes only one page worth of content to be present in the DOM. Selection made client side are not being saved anywhere to be accessed later as the user pages through the results.

For item 3. onChange event listener is written only for dataTable based rendering of results.

I can think of two solutions

1. Use a client side JSON object to store the user selections. The JSON object won't be replaced as part of component refresh in case of server side paging. We can then use the JSON object to calculate if 'Return Selected' button should be enabled and also to populate hidden variables on submit. In this approach, once a page is retrieved from the server, we would have to reset any selections that were present on the page from the JSON object. This solution will work for both serverPaging and default paging provided by dataTable.

2. In the other solution, for every select/deselect event a call will be made to a controller method that will record the event server side. This will fix the issue of preserving selections as the user moves through different pages. To solve the problem of retaining the right state for "Return Selected" button we would need to use a counter logic instead of boolean that is there right now. With every selection we increment the counter and with every deselection we decrement the counter. If the counter is at 0, we disable the button else the button stays enabled. This way even if the user moves to a new page the button would know what state it is in. In this solution on submit, instead of reading the selections from request, the collection stored on the server needs to be read to identify which line items need to be processed.

Also for solution 2, the JS function 'handleCheckboxLabelClick' needs to be updated so that it sends a request to the server if server paging is enabled.

Solution 1, has lower performance impact as it would not require a server call for every select/deselect. It is also a single solution that can be applied to all use cases (client side dataTable only, with server paging and dataTable and with server paging without dataTable)

Comment by Sona Sona (Inactive) [ 11/Oct/13 ]

Jerry's thoughts:

I gave this some more thought as well. Let me first take the problem of getting all the records selected for ‘select all’. Since you don’t have all the records on the client, I think there needs to be a server call made. The server call would get all the results for collection, add the keys to the selected keys map. This would only be done when they choose ‘select all’ from the header (we can refresh the collection group so the page checkboxes become selected).

For enabling/disabling the return selected button, I was thinking something similar. You can keep an array of selected checkbox ids in the data for the document (jQuery data). So on the checkbox handler, if the value is checked add the id to the data array, if unchecked remove the id. Then have a check to see if there are any items in the data array and enable or disable the button accordingly. The data array will stay around as long as the page is not fully refreshed. Then you can also use this array to repopulate checkboxes when a page occurs. An alternative approach is look at how we might pass additional data to the paging call, so the selected items for the current page get passed and populated client side, then they will be correct when paged back.

There is a still a slight issue I see, full page refreshes. All the checkbox state will be posted so they selected items will appear correctly on refresh, but the array will be lost and the button disabled as a consequence. One way to solve this will be on load to iterate through the checkboxes and initialize the array.

This is a tricky issue!

Comment by Sona Sona (Inactive) [ 14/Oct/13 ]

Hi Jerry,

I thought more about it also and found a flaw in our design. On a 5 page result with server side paging "ON", if the user clicks on "Select All", we would make a note on the server side as you suggested and update the client to select all the check boxes on the visible page. Now if the user deselects a single item from that page and hits return the current solution will break as that action would cause the "Select All" to be reset on the server side but really the user expects all but one item to be selected. Since the user has not visited any other page, the client does not know of those values. The more I think about this the more I realize that we need either a full client side solution or a full server side solution.

In a full client side solution when the select all is checked, instead of noting server side of that choice, we will pull all the values from the server and add it to the data attribute you suggested. After this everything will work as noted by your email for a client side solution. In this there is a one time performance hit when the user clicks on select all. The impact could be quite big based on the result set size, but only if the user decides to click on select all. To reduce the impact I was thinking using JSON response with only values of the select control.

In the full server side solution every click will have to be recorded server side and then a return selected is processed from values stored server side. This will have a higher performance impact for every click by making round trip server requests for select and deselect and potentially impact the user experience as they click through the check boxes.

Please let me know how you would like me to proceed? As you said it is a tricky issue .

Thanks

Comment by Jerry Neal (Inactive) [ 14/Oct/13 ]

Hi Sona,

Good point. We need to figure out the binding behavior here as well. The checkboxes bind to an entry in the Map property: protected Map<String, Set<String>> selectedCollectionLines;. When the return selected button is clicked, the form will post to the server. The checkbox state of all the lines present in the DOM will then update the selectedCollectionLines map. If the checkbox is selected, the value will get added (since the value is already there and it is a set it will not actually get added). Spring also keeps track of whether a checkbox was present, and if unselected will remove the value. The question is, whether spring initializes a new Set for the value before it does the population, I don’t think it does. So if the select all was chosen before, the values for all the lines will be added to this property by a server side method. Then just the checkbox values for the visible page should update when return selected is chosen. If all this is correct, it would work out. The value for the one checkbox that was unselected will be removed, and the other values will remain. If this is not the case, I agree going with the client side solution would be best.

Thanks,
Jerry

Generated at Mon Jul 13 12:14:07 CDT 2020 using JIRA 6.1.5#6160-sha1:a61a0fc278117a0da0ec9b89167b8f29b6afdab2.