if (theData.hasOwnProperty("#id1")) {
var myObj:Hello = new Hello();
textArea.visible = false;
panel.addChild(myObj);
} else if (theData.hasOwnProperty("#id2")) {
textArea.visible = false;
var vijay:MCQ = new MCQ();
panel.addChild(vijay);
}
When i click on the next item, the previous window is still visible. How can i destroy myObj. I am not able to do it through removeChild.
If panel only ever contains one object, you could use the following before adding the new one:
panel.removeAllChildren();
If there are a known number of "static" children in panel, you could conditionally remove the additional ones:
while (panel.numChildren > EXPECTED) {
panel.removeChildAt(panel.numChildren - 1);
}
The best option would be to hold a reference to the object you added so that you can remove it explicitly using removeChild(). If these alternatives won't work, perhaps you could explain your constraints.
Related
from the last version update (from openui5 1.36.12 to openui5 1.38.4) the following code is not working anymore:
var myTable = new sap.ui.table.Table();
myTable ._oVSb.attachScroll(function() {
colorTheTableRows();
})
I'm using the "attachScroll" event in order to color the table rows with a specific logic.
Since last openui5 version update I get this error in console:
Uncaught TypeError: Cannot read property 'attachScroll' of undefined
I've tried to debug the problem and it seems that the object _oVSb has be removed from sap.ui.table.Table.
My final goal is to paint the rows with different colors based on the content ... is there any other way to reach this feature?
Thanks
Even i want this event some how came to this thread. i tried #Dopedev solution it was not working then i changed bit in that as below
$("#<tablid>-vsb").scroll(function() {
console.log("Table is scrolled")
});
instead of getting the tbody get the table-id-vsb and attach the scroll function
You can still get scroll event for your table using .scroll() of jQuery.
onAfterRendering: function(){
//Register handler for scroll event
$("tbody").scroll(function(){
// your stuff
});
}
Demo
I know that one of the earlier posts was already marked as the 'right' answer, but it did not work for me, so I thought I would post my working solution, as it might be helpful to others. The following code will work to effectively 'attach' to the vertical scroll event of a table in 1.38:
onAfterRendering: function() {
if (this.firstTime) { //You only want to override this once
var oTable = this.getView().byId("<YOUR_ID_HERE>");
//Get a reference to whatever your custom handler is
var oHandler = this.handleScroll;
//Store a reference to the default handler method
var oVScroll = oTable.onvscroll;
oTable.origVScrollHandler = oVScroll;
oTable.onvscroll = function(i) {
//Call the 'default' UI5 handler
oTable.origVScrollHandler(i);
//Call your handler function, or whatever else you want to do
oHandler();
};
this.firstTime = false;
}
},
var myTable = new sap.ui.table.Table("myTable");
After rendering:
sap.ui.getCore().byId("myTable-vsb").attachScroll(function() {
colorTheTableRows();
})
I'm working in flex and I made a custom drop down where there are check boxes to allow the user to select multiple options. I used this template.
However this does not have scrolling because if you allow scrolling for some reason the checkboxes start to mess up. For instance if you have options 1 to 8 and only 1 to 5 are shown. You select option 1 and then scroll down to select option 7. When you scroll up the checkboxes start to switch around like option 3 all of a sudden is showing selected. Keep scrolling up and down and the checkbox selection just changes on it's own. I think this is a rendering issue and the actual selection data isn't changed at all (it knows only option 1 and option 7 were selected). Any ideas on how to fix this?
public function onOpen(event:DropDownEvent):void
{//load the checkboxes and set the mouse tracker
activateAllCheckBoxes();
this.scroller.verticalScrollBar.addEventListener(Event.CHANGE, list_verticalScrollBar_change);
callLater(observeMouse);
}
private function list_verticalScrollBar_change(evt:Event):void
{
//currentlySelectedCheckBoxes = selectedCheckboxes;
UpdateCheckBoxesWhenScrolling();
selectedIndex = -1;
}
protected function UpdateCheckBoxesWhenScrolling():void
{
for (var c:int = 0; c < dataGroup.numElements; c++) {
var obj:DropDownCheckBox = dataGroup.getElementAt(c) as DropDownCheckBox;
if(obj!=null)
{
var judgDebtorFromCheckBox:JudgDebtor = (obj.data) as JudgDebtor;
if(FindInCurrentList(judgDebtorFromCheckBox.JudgmentDebtorId)>0)
{
obj.checkbox.selected = true;
}
else
{
obj.checkbox.selected = false;
}
}
}
}
private function FindInCurrentList(ID:int):int
{
for(var i:int=0;i<currentlySelectedCheckBoxes.length;i++)
{
var JD:JudgDebtor = currentlySelectedCheckBoxes.getItemAt(i) as JudgDebtor;
if(JD.JudgmentDebtorId == ID)
return 1;
}
return -1;
}
So above code I register a scroll event listener on the drop down. It will update the drop down entries which has a check box and it uses an array collection called: currentlySelectedCheckBoxes. I debug the UpdateCheckBoxesWhenScrolling function and it's working fine, in other words it will check off the ones selected but for some reason it still is showing the wrong results for instance 11 entries in the list and only the second one is selected I scroll down and I can't see the the second entry but all of a sudden the last entry is showing that it's checked off.
This happens because the drop down list reuses the renderers when you scroll. For example if you have checked 1st item and scroll, the renderer for that is reused to display the item that becomes visible when you scroll. So the last item shows as checked. To avoid messing up the selection, you will have to do the following in the renderer that you are using
override public function set data(value:Object):void
{
super.data = value;
//inspect the property which indicates whether to select the checkbox or not
//and set the value of selected property accordingly
}
Hope this helps
I have a simple list and a background refresh protocol.
When the list is scrolled down, the refresh scrolls it back to the top. I want to stop this.
I have tried catching the COLLECTION_CHANGE event and
validateNow(); // try to get the component to reset to the new data
list.ensureIndexIsVisible(previousIndex); // actually, I search for the previous data id in the IList, but that's not important
This fails because the list resets itself after the change (in DataGroup.commitProperties).
I hate to use a Timer, ENTER_FRAME, or callLater(), but I cannot seem to figure out a way.
The only other alternatives I can see is sub-classing the List so it can catch the dataProviderChanged event the DataGroup in the skin is throwing.
Any ideas?
Actually MUCH better solution to this is to extend DataGroup. You need to override this.
All the solutions here create a flicker as the scrollbar gets resetted to 0 and the it's set back to the previous value. That looks wrong. This solution works without any flicker and the best of all, you just change DataGroup to FixedDataGroup in your code and it works, no other changes in code are needed ;).
Enjoy guys.
public class FixedDataGroup extends spark.components.DataGroup
{
private var _dataProviderChanged:Boolean;
private var _lastScrollPosition:Number = 0;
public function FixedDataGroup()
{
super();
}
override public function set dataProvider(value:IList):void
{
if ( this.dataProvider != null && value != this.dataProvider )
{
dataProvider.removeEventListener(CollectionEvent.COLLECTION_CHANGE, onDataProviderChanged);
}
super.dataProvider = value;
if ( value != null )
{
value.addEventListener(CollectionEvent.COLLECTION_CHANGE, onDataProviderChanged);
}
}
override protected function commitProperties():void
{
var lastScrollPosition:Number = _lastScrollPosition;
super.commitProperties();
if ( _dataProviderChanged )
{
verticalScrollPosition = lastScrollPosition;
}
}
private function onDataProviderChanged(e:CollectionEvent):void
{
_dataProviderChanged = true;
invalidateProperties();
}
override public function set verticalScrollPosition(value:Number):void
{
super.verticalScrollPosition = value;
_lastScrollPosition = value;
}
}
I ll try to explain my approach...If you are still unsure let me know and I ll give you the source code as well.
1) Create a variable to store the current scroll position of the viewport.
2) Add Event listener for Event.CHANGE and MouseEvent.MOUSE_WHEEL on the scroller and update the variable created in step 1 with the current scroll position;
3) Add a event listener on your viewport for FlexEvent.UpdateComplete and set the scroll position to the variable stored.
In a nutshell, what we are doing is to have the scroll position stored in variable every time user interacts with it and when our viewport is updated (due to dataprovider change) we just set the scroll position we have stored previously in the variable.
I have faced this problem before and solved it by using a data proxy pattern with a matcher. Write a matcher for your collection that supports your list by updating only changed objects and by updating only attributes for existing objects. The goal is to avoid creation of new objects when your data source refreshes.
When you have new data for the list (after a refresh), loop through your list of new data objects, copying attributes from these objects into the objects in the collection supporting your list. Typically you will match the objects based on id. Any objects in the new list that did not exist in the old one get added. Your scroll position will normally not change and any selections are usually kept.
Here is an example.
for each(newObject:Object in newArrayValues){
var found:Boolean = false;
for each(oldObject:Object in oldArrayValues){
if(oldObject.id == newObject.id){
found = true;
oldObject.myAttribute = newObject.myAttribute;
oldObject.myAttribute2 = newObject.myAttribute2;
}
}
if(!found){
oldArrayValues.addItem(newObject);
}
}
My solution for this problem was targeting a specific situation, but it has the advantage of being very simple so perhaps you can draw something that fits your needs from it. Since I don't know exactly what issue you're trying to solve I'll give you a description of mine:
I had a List that was progressively loading data from the server. When the user scrolled down and the next batch of items would be added to the dataprovider, the scrollposition would jump back to the start.
The solution for this was as simple as stopping the propagation of the COLLECTION_CHANGE event so that the List wouldn't catch it.
myDataProvider.addEventListener(
CollectionEvent.COLLECTION_CHANGE, preventRefresh
);
private function preventRefresh(event:CollectionEvent):void {
event.stopImmediatePropagation();
}
You have to know that this effectively prevents a redraw of the List component, hence any added items would not be shown. This was not an issue for me since the items would be added at the end of the List (outside the viewport) and when the user would scroll, the List would automatically be redrawn and the new items would be displayed. Perhaps in your situation you can force the redraw if need be.
When all items had been loaded I could then remove the event listener and return to the normal behavior of the List component.
I've done a lot of C# programming with both Winforms and WPF. I'm working on a Flex/Air app now for cross platform support. But this is my first flex project, so I'm learning as I go.
I've got a window that I want to popup, that the user will fill out a form, then hit OK or CANCEL. I set it up the same way I would've in C#, but it doesn't work, and I can't really see a way to make it do what I want.
EDIT:
So I'm trying events now, the events just don't seem to be handled...
EDIT again:
Oh, It's because the popup manager seems to create a new instance of the Form object, rather than using the one I created already.
so in the showWindow method, I put in this code rather than the popup manager:
parent.addChild(this);
then I remove it when I close it. The only problem is, it doesn't disable the rest of the parent like the popup manager does. Any suggestions on that?
PARENT:
private function btnAdd_Clicked():void
{
var form:Form = new Form();
form.addEventListener(CloseEvent.CLOSE, onFormClosed, false, 0, true);
recipeForm.showWindow(this);
}
private function onFormClosed(e:CloseEvent):void
{
//none of these Alerts are ever shown. I also tried breakpoints in debug to try an follow the code, with no luck
Alert.show("Closed");
if(e.detail == Alert.OK)
{
Alert.show("OK");
}
else if(e.detail == Alert.CANCEL)
{
Alert.show("Cancel");
}
}
CHILD:
private function btnCancel_Clicked():void
{
okClicked = false;
closeWindow();
}
public function closeWindow():void
{
var e:CloseEvent = new CloseEvent(CloseEvent.CLOSE);
e.detail = okClicked ? Alert.OK : Alert.CANCEL;
dispatchEvent(e);
PopUpManager.removePopUp(this);
}
public function showWindow(parent:WindowedApplication):void
{
var window:IFlexDisplayObject = PopUpManager.createPopUp(parent, RecipeForm, true);
PopUpManager.centerPopUp(window);
}
You can do this at least two different ways:
FIRST WAY: Using events
Let your Form class dispatch an event when either of the buttons is clicked. After Form is instantiated from the parent view, add an eventListener for the event(s) it's known to dispatch. When the Form dispatches the event, the eventListener will be invoked. You can even reuse Flex's CloseEvent and set the "detail" property to either Alert.OK or Alert.CANCEL before dispatching it.
In Form:
var e:CloseEvent = new CloseEvent(CloseEvent.CLOSE);
e.detail = okClicked ? Alert.OK : Alert.CANCEL;
dispatchEvent(e);
In parent:
var f:Form = new Form();
f.addEventListener(CloseEvent.CLOSE, onClose, false, 0, true);
...
private function onClose(e:CloseEvent):void
{
if (e.detail == Alert.OK)
// do something
else if (e.detail == Alert.CANCEL)
// do something else
}
SECOND WAY: Using callbacks
Add a public var of type "Function" to your Form class and supply a callback function from the parent. This does basically the same thing as #1 except with little less abstraction / indirection.
I would recommend #1 since the event model in Flex is pretty well-conceived and more flexible than the callback.
In Form:
var e:CloseEvent = new CloseEvent(CloseEvent.CLOSE);
e.detail = okClicked ? Alert.OK : Alert.CANCEL;
dispatchEvent(e);
In parent:
var f:Form = new Form();
f.addEventListener(CloseEvent.CLOSE, onClose, false, 0, true);
...
private function onClose(e:CloseEvent):void
{
if (e.detail == Alert.OK)
// do something
else if (e.detail == Alert.CANCEL)
// do something else
}
Not sure if this is still an open issue. I ran into this very same problem and I think I figured out what is wrong. At least I did for my problem.
I implemented things exactly as you did. I also have the close attribute set to closeWindow (I'm using a TitleWindow for my dialog).
So when the window is closed via the X at the top, it will call closeWindow, also if you click on the Cancel button, it will also call closeWindow.
The problem for me was that clicking cancel, dispatches a CloseEvent which seems to be caught by a Listener which calls closeWindow again (possibly via the close attribute which probably creates its own internal listener). I'm not sure if its an infinite loop but Flex does not like this.
My solution was to create two functions, one for the X close window to call and one for the Cancel button to dispatch a CloseEvent of its own. This seemed to work for me. Hope it helps you.
I have a hidden field on my page
<input runat="server" type="hidden" id="selectedIndex" />
and it is being set by this bunch of code, an onclick event to a gridview's row:
var gridViewCtlId = '<%=GridView.ClientID%>';
var selectedIndex = '#<%=selectedIndex.ClientID%>';
var itemVisible = '<%=ItemVisible.ClientID%>';
var gridViewCtl = null;
var curSelRow = null;
var previousRowIndx = null;
window.onload = function showQuery()
{
if ($(selectedIndex).val() != undefined)
{
if ($(selectedIndex).val() != '')
{
var prevRowID = $(selectedIndex).val();
var prevRow = getSelectedRow(prevRowID);
prevRow.style.backgroundColor = '#1A8CD4';
}
}
}
function getGridViewControl(rowIdx)
{
if (gridViewCtl == null)
{
gridViewCtl = document.getElementById(gridViewCtlId);
}
}
function onGridViewRowSelected(rowIdx)
{
if (document.getElementById(gridViewCtlId).disabled == false)
{
var selRowCCA = getSelectedRow(rowIdx);
if (curSelRow != null)
{
var previousRow = getSelectedRow(previousRowIndx);
var CountIdx = previousRowIndx % 2;
if (document.getElementById(itemVisible) == null)
{
if (CountIdx == 0)
{
previousRow.style.backgroundColor = 'Silver';
}
else
{
previousRow.style.backgroundColor = 'White';
}
}
}
if (null != selRow)
{
previousRowIndx = rowIdx;
curSelRow = selRow;
selRow.style.backgroundColor = '#1A8CD4';
}
}
}
function getSelectedRow(rowIdx)
{
getGridViewControl(rowIdx);
if (gridViewCtl != null)
{
$(selectedIndex).val(rowIdx);
return gridViewCtl.rows[rowIdx];
}
return null;
}
This is what happens: When The page first loads, the hidden field is undefined, which it should be. When I click on a row and then click the 'select' button which then calls this:
GridView.Attributes.Add("disabled", "true");
The gridview becomes disabled (along with the select button) and another gridview comes up (which should happen depending on what is seleted in the first gridview). So now, here is the problem. When I click on a row in the gridview (I'm only talking about the initial gridview, not the secondary one which comes up, that's not an issue here), and click select, everything gets greyed out and most of the time, the selected row will highlight when the page loads (the other times for some reason it defaults to row #2). Then, say you click on row 4 then click on row 1 and then click select, for some reason row 4 will remain highlighted and row 4's data will then populate the second gridview, like you never clicked row 1. But if I click row 4 then click row 1 then click row 1 again, does it save. Does anyone know why that happens?
Also, I'm pretty much trying to disable the first gridview when select is hit so I do
GridView.Attributes.Add("disabled", "true");
rather than
GridView.Enabled = false;
If a user re-clicks the search button (another button located previously on the page which makes this gridview become visible), I would like the secondary gridview to become hidden, and the primary gridview (this one in question) to become re-enabled. But doing
GridView.Attributes.Add("disabled", "false");
when the search button is fired only disables the gridview, which is very weird. Now I know that the disabled field is not supported by any other browser except IE, and i only use it because I need to check if the gridview is disabled so a user cant click on another row after they've made their selection (which happens if I dont do the following:
if (document.getElementById(gridViewCtlId).disabled == false)
So could anyone let me know of another way of accomplishing that task? Thanks again in advance.
Some bits of info on disabled:
Browsers won't send any disabled control's value to the server. This is by definition.
Disabled field is supported by other browsers, but it uses a different model. Note list of supported browsers: http://www.w3schools.com/tags/att_input_disabled.asp (also how it is defined disabled='disabled').
Also see how it compares to the read-only: http://www.w3.org/TR/html401/interact/forms.html#h-17.12.2
Also note according to the standard its support its limited to certain elements. This is important, as you are applying it at an unsupported html element, which is also a likely cause of it not working in other browsers in your scenario. You can disable the supported control by using an script, getting the controls to apply it like $get("someClientID").getElementsByTagName("input");