On sorting a jsp <select> element items vanishes - sorting

I have two listbox in a .jsp page with Add(+) and Remove(-) buttons in between. Two list boxes are 'Available Items' (left) and 'Selected Items'(right). 'Available Items' list box displays all the available items on page load fetching from DB, and 'Selected Items' listbox displays blank. User can add one item from left to right in 'Selected Items' listbox.
I have written code to move the items from both sides and vice versa. But the problem is when I am clicking 'Add' button to move the item from left to right, the item is moved properly to right listbox but the left list ('Available Items') items are getting vanished and reappears only after doing a click event the listbox which is weird from UI devlpment perspective. The same is happening for Remove button click. I hope there is some refresh issue underline. I am posting the codes below.
N.B : I have written a sort method to sort the items in the listbox. I troubleshooted that if I close calling the method sortItemsList() then everything is working fine.
Code for the listbox :
<tr>
<td>
<select id="leftItemList" size="8" multiple="multiple" style="height:auto"></select>
<input type="button" name="moveItemsToLeft" id="buttonAddItems" class="selectBoxAddButton checkboxDependent" value="Add >>" />
<input type="button" id="buttonRemoveItems" class="selectBoxRemoveButton checkboxDependent" value="<< Remove" />
<select id="rightItemList" size="8" multiple="multiple" style="height:auto"></select>
</td>
</tr>
Corresponding code for sort in javascript that is causing the issue :
Code for adding and removing items:
$('#buttonAddItems').click(function(){ //Moving items from left to right
var elementFrom = document.getElementById('leftItemList');
var element = document.getElementById('rightItemList');
var len = element.options.length;
var elementFromLength = elementFrom.length;
for ( var i = (elementFromLength - 1); i >= 0; i--) {
if ((elementFrom.options[i] != null) && (elementFrom.options[i].selected == true)) {
var selectedItemLength = $("#leftItemList :selected").length;
element.options[len] = new Option(
elementFrom.options[i].text,
elementFrom.options[i].value);
len++;
elementFrom.options[i] = null;
}
}
sortItemsList(); //Commenting this call fixes the problem
});
$('#buttonRemoveItems').click(function(){ //Moving items from right to left
var element = document.getElementById('rightItemList');
var elementTo = document.getElementById('leftItemList');
var len = element.options.length;
var elementFromLength = elementTo.length;
for ( var i = (len - 1); i >= 0; i--) {
if ((element.options[i] != null) && (element.options[i].selected == true)) {
elementTo.options[elementFromLength] = new Option(
element.options[i].text,
element.options[i].value);
elementFromLength++;
element.options[i] = null;
}
}
sortItemsList(); //Commenting this call fixes the problem
});
function sortItemsList(){
var options = $("#leftItemList option"); // Collect options
options.detach().sort(function(a,b) { // Detach from select, then Sort
var at = $(a).text();
var bt = $(b).text();
return (at > bt)?1:((at < bt)?-1:0); // Tell the sort function how to order
});
options.appendTo("#leftItemList");
}
N.B : The code for sorting that I used is taken from reference whose URL is below. Have tried both Approaches. None of them is working. I do have same '3.4.1/jquery.min.js' as in reference -
https://www.geeksforgeeks.org/how-to-sort-option-elements-alphabetically-using-jquery/

#Swati I am having the same problem running your code in jsfiddle (which you are running successfully). So the problem is with Chrome version. My chrome version is 'Version 81.0.4044.113 (Official Build) (64-bit)'. I guess yours is 'Chrome version 80.0.3987.122' one version older than me with which it is working fine. Finally the observations are as below.
Observations
In the higher chrome version, the code is working fine till sorting. But when the code is trying to append the sorted itemList into existing itemList object, there was some issues with DOM manipulation with latest chrome version against appendTo() method, which means appendTo() method is adding sorted itemList into existing DOM element but refresh or reload is not happening with that DOM element. That's why the vanished itemList drop down is getting all the values after a mouse click event on the drop down manually.
In order to fix this issue, we need to do manual refresh. We can do the refresh or reload by two different ways as mentioned below.
Approach 1 :
Adding the below line after itemList append.
$("#leftItemList").html($("#leftItemList").html());
Approach 2 :
We can set the focus on leftItemList element after append. If we follow this approach, when we click Add button it will add the item list to right side but the focus will be there is the leftItemList drop down.
$("#leftItemList").focus();
So Approach 1 is the preferable solution.

Related

kendo ui grid programatically hide and show the filterable row

I have a kendo grid with filterable = true, mode=row.
I would like a way to have a button click, fire an event that will toggle hiding and showing the filter row.
Right now, I have it working by editing the innerHTML, but this is not what I want to do in the end, for several reasons.
1) I need to have a saved version of the filter row values before they are removed.
2) After they are removed and re-added they will not work
...
many other reasons, just bad practice and there has to be a better way.
A button that fires the event: toggleFilterClick:
<script type="text/x-kendo-template" id="gridFilter">
<button type="button" class="k-button" id="kendoFilterButton" data-click="toggleFilter"><span class="k-icon k-i-funnel"></span>Filter On/Off</button>
</script>
The Javascript code:
//Gets the innerHTML values before they are removed
var filterRowValues = $(".k-filter-row")[0].innerHTML;
//fired when the button is clicked
var toggleFilterClick = $('#kendoFilterButton').on("click", function () {
if ($(".k-filter-row")[0].innerHTML == '')
{
$(".k-filter-row")[0].innerHTML = filterRowValues;
}
else
{
$(".k-filter-row")[0].innerHTML = '';
}
});
Any thoughts suggestions would be appreciated/
I would just like to hide the actual filter row in the header
I'm not sure if i get the point but if you just want to hide it just simply remove everything except$(".k-filter-row").show(); and $(".k-filter-row").hide();. I create an example where when i hide the filter, the filter condtion will removed, but when it showed again the grid will refiltered with the previous value used to filter
$("#toggle").kendoButton({
click:function(){
if($(".k-filter-row").css("display") == "none"){
$(".k-filter-row").show();
//show again filter and execute previous filter condition
$("#grid").data("kendoGrid").dataSource.filter({field:"ShipName",operator:"contains",value:vm.get("filterOptions.ShipName").toString()});
$("#grid").data("kendoGrid").dataSource.filter({field:"OrderID",operator:"eq",value:vm.get("filterOptions.OrderID")});
}else{
//store the previous filter value
//autocomplete
vm.set("filterOptions.ShipName",$("input[data-role='autocomplete']").data("kendoAutoComplete").value());
vm.set("filterOptions.OrderID",$("input[data-role='numerictextbox']").data("kendoNumericTextBox").value());
//hide filter row
$(".k-filter-row").show();
//to reset filter of the grid when filterable hidden
$("#grid").data("kendoGrid").dataSource.filter({});
}
}
});
See the details in action
DEMO
Have you tried just hiding the row instead of removing it?
//fired when the button is clicked
var toggleFilterClick = $('#kendoFilterButton').on("click", function () {
if ($(".k-filter-row").is(":visible")){
$(".k-filter-row").hide();
}
else{
$(".k-filter-row").show();
}
});

VS2010 Coded UI Test - Test builder unable to map two checkboxes with same text

I'm trying to create a coded UI test (with VS2010 Ultimate) for a simple web form page with two checkboxes and a submit hyperlink. The checkboxes have the same text label; "I Agree".
Using the coded UI test builder to record actions, only one checkbox is captured because both checkboxes have the same text / same UIMap Name.
Using the crosshair tool to select the second checkbox, it replaces the previous checkbox instance because they have the same text / same UIMap Name.
When the test is run, the first checkbox is checked, the second is not, and the hyperlink is clicked to submitted the form (failing validation).
How can I add the second checkbox to the test map and differentiate between the two?
If there are no unique properties on the checkboxes themselves, specify the parent object of each checkbox to differentiate them.
Example:
For
<div id="box1Parent">
<input label="I Agree"/>
</div>
<div id=box2Parent">
<input label="I Agree"/>
</div>
You would define the object like this:
public HtmlCheckBox AgreementBox1()
{
HtmlDiv parent = new HtmlDiv(browser);
parent.SearchProperties["id"] = "box1Parent";
HtmlCheckBox target = new HtmlCheckBox(parent);
target.SearchProperties["label"] = "I Agree";
return target;
}
Then, do the same for the second box, but point the parent to box2Parent. This would be your code in the non-designer section of the .uitest class.
There are multiple ways to do this.
Try to find out unique property of object like id, name.
Try to find out parent control/container of checkbox, then use {TAB} or {UP}/{DOWN} keys.
Use {TAB} key of keyboard. find out previous control -> click on that control -> use {TAB} from that control to get focus on checkbox control and use {UP}/{DOWN} arrow key to navigate.
Find out text of document and click on first or second occurrence of that as per your need.
Code to find out document Text,
public string GetCurrentPageVisibleTexts()
{
var window = this.UIMap.<WindowObject>
UITestControlCollection c = window.GetChildren();
var pgContent = (string)c[0].GetProperty("OuterHtml");
var document = new HtmlAgilityPack.HtmlDocument();
document.LoadHtml(pgContent);
// We don't want these in our result
var exclusionText = new string[] { "<!--", "<![CDATA", "function()", "</form>" };
var visibleTexts = new List<string>();
//var nodes = document.DocumentNode.Descendants().Where(d => !d.Name.ToLower().Equals("span"));
foreach (var elem in document.DocumentNode.Descendants())
{
// Foreach element iterate its path back till root
// and look for "display: none" attribute in each one of its parent node
// to verify whether that element or any of its parent are marked as hidden
var tempElem = elem;
while (tempElem.ParentNode != null)
{
if (tempElem.Attributes["style"] != null)
{
// if hidden attribute found then break.
if (tempElem.Attributes["style"].Value.ToLower().Contains("display: none")) break;
}
tempElem = tempElem.ParentNode;
}
// If iteration reached to head and element is found clean of hidden property then proceed with text extraction.
if (tempElem.ParentNode == null)
{
if (!exclusionText.Any(e => elem.InnerText.Contains(e))
&& (!elem.InnerText.Trim().IsNullOrEmpty())
&& (!elem.HasChildNodes))
{
visibleTexts.Add(elem.InnerText);
}
}
} // Foreach close
var completeText = string.Join(" ", visibleTexts).Replace(" ", " ");
return Regex.Replace(completeText, #"\s+", " ");
}

Text selection in slickgrid

I have set 'enableTextSelectionOnCells' option to true to select text in slickgrid but I can only select text in IE and chrome but not in firefox. I know this is bug in slickgrid and it had been fixed in slickgrid 2.2 but I am using slickgrid V2.1 and don't want to upgrade to V2.2. Is there any way to select text in firefox using slickgrid 2.1
I had the same problem as you have and I finally found the solution from a pull request made by the user icoxfog417 (thanks mate), the pull request is not yet approved (hopefully soon) but I tried it and it works on all 3 browsers which I tried (in my case FF27, IE8, Chrome31). You do have to modify 1 of the core file slick.grid.js but it's worth it :) The pull request is this one: Pull Request #746: fix issue#739
The code change is simple and looks like this:
Modify the file slick.grid.js at line 2236, replace the code with this:
// if this click resulted in some cell child node getting focus,
// don't steal it back - keyboard events will still bubble up
// IE9+ seems to default DIVs to tabIndex=0 instead of -1, so check for cell clicks directly.
if (e.target != document.activeElement || $(e.target).hasClass("slick-cell")) {
var selection = getTextSelection(); //store text-selection and restore it after
setFocus();
setTextSelection(selection);
}
then insert at line 2418 (after the setFocus() function), insert this new code:
//This get/set methods are used for keeping text-selection. These don't consider IE because they don't loose text-selection.
function getTextSelection(){
var textSelection = null;
if (window.getSelection) {
var selection = window.getSelection();
if (selection.rangeCount > 0) {
textSelection = selection.getRangeAt(0);
}
}
return textSelection;
}
function setTextSelection(selection){
if (window.getSelection && selection) {
var target = window.getSelection();
target.removeAllRanges();
target.addRange(selection);
}
}
VoilĂ !!! Quite happy about it :)

KendoUI PanelBar remember expanded items

I try implement Kendo UI PanelBar (see http://demos.kendoui.com/web/panelbar/images.html) If I open some items (Golf, Swimming) and next click to "Videos Records", I have expanded items. But when I do refresh page (click on some link), all expanded structure is lost.
On KendoUI forum I found, that I can get only possition of selected item and after reload page I must calculate all noded. Is there any way, how can I have expanded items in my situation? If do not need, I don't want to use the html frames.
Best regards,
Peter
Thank you for your answer, was very usefull. I add here code of skeleton of jQuery which remember 1 selected item now. Required add jquery.cookie.js [https://github.com/carhartl/jquery-cookie]
function onSelect(e) {
var item = $(e.item),
index = item.parentsUntil(".k-panelbar", ".k-item").map(function () {
return $(this).index();
}).get().reverse();
index.push(item.index());
$.cookie("KendoUiPanelBarSelectedIndex", index);
//alert(index);
}
var panel = $("#panelbar").kendoPanelBar({
select: onSelect
}).data("kendoPanelBar");
//$("button").click(function () {
// select([0, 2]);
//});
function select(position) {
var ul = panel.element;
for (var i = 0; i < position.length; i++) {
var item = ul.children().eq(position[i]);
if (i != position.length - 1) {
ul = item.children("ul");
if (!ul[0])
ul = item.children().children("ul");
panel.expand(item, false);
} else {
panel.select(item);
}
}
}
// on page ready select value from cookies
$(document).ready(function () {
if ($.cookie("KendoUiPanelBarSelectedIndex") != null) {
//alert($.cookie("KendoUiPanelBarSelectedIndex"));
var numbersArray = $.cookie("KendoUiPanelBarSelectedIndex").split(',');
select(numbersArray);
}
else {
// TEST INIT MESSAGE, ON REAL USE DELETE
alert("DocumenReadyFunction: KendoUiPanelBarSelectedIndex IS NULL");
}
});
The opening of the panels happens on the client. When the page is refreshed, the browser will render the provided markup, which does not include any additional markup for the selected panel.
In order to accomplish this, you will need to somehow store a value indicating the opened panel. The easiest way to accomplish this would be with a cookie (either set by JavaScript or do an AJAX call to the server).
Then, when the panelBar is being rendered, it will use the value in the cookie to set the correct tab as the selected one.
You can use this block to work withe the selected. in this example, i am just expanding the panel item. You can do other things such as saving panel item in your dom for later use or may be saving it somewhere to use it later:
var panelBar = $("#importCvPanelbar").data("kendoPanelBar");
panelBar.bind("select", function(e) {
var itemId = $(e.item)[0].id;
panelBar.expand(itemId);// will expand the selected one
});

Livequery fires click no matter where the user clicks in the document

I have replaced the traditional select/option form elements with a nifty little popup window when a triggering image is clicked. The page is for accounting purposes and so multiple line items are to be expected. I've written the javascript that will dynamically generate new line item select/option elements. When the page loads, the initial set of choices loads and the user can click on them, get a pop up with some choices, choose one and then the box closes. The move to the next choice and so on and so forth. I've added livequery to my code for those dynamic elements. However... the livequery("click"...) seems to fire no matter where the user clicks on the page. Very frustrating.
I've read on here how great "live()" is in jQuery 1.3, but I am not able to upgrade fully to jquery 1.3 because a custom JS file depends on 1.2, so using live() is out of the question, however I have invoked the livequery() plugin and I really need to understand if I'm using it correctly.
I will post partial code. There's just way too much to post all of it.
Basically, I'm searching for divs starting with "bubble" and then a number afterwards. Then run the event on each them. Only bubble1 is static, 2 and up are dynamic. Am I missing the whole usage of livequery?
>$jb('div[id^="bubble"]').each(function () {
> var divid = $jb('div[id^="bubble"]').filter(":first").attr("id");
>var pref = "bubble";
>var i = divid.substring((pref.length));
>var trigger = $jb('#trigger' + i, this);
>var popup = $jb('#pop'+ i, this).css('opacity', 0);
>var selectedoption = $jb('selectedOption' + i, this);
>var selectedtext = $jb('selectedOptionText' + i, this);
>$jb([trigger.get(0), popup.get(0)]).livequery("click",
> function () {
>//alert(i);
// code removed for brevity (just the contents of the popups)
>});
Live works by using event delegation. A click event is attached to the body, and anytime something is clicked the selector is tested against the target. If it passes the selector test it calls the function (thus simulating a click event).
You probably want something like this:
$('div[id^="bubble"]').livequery("click", function() {
var divId = $(this).attr("id");
var i = divId.substring("bubble".length);
var trigger = $("#trigger" + i, this);
var popup = $("#pop" + i, this).css("opacity", 0);
// alert(i);
}

Resources