Pooling and children removal - qooxdoo

I try to use pooling with my qx.application, because it gives me a significant performance boost on mobile devices (especially Android devices).
For structuring (and for setting huge widget selections to “excluded” with one command) I use many widgets including qx.ui.core.MChildrenHandling.
After leaving a menu I iterate through all containers recursively and add them and their children to a pool.
For object creation I try to get an instance from the pool.
This is working really fine but after some time I get the following error (on Chrome for Android):
“Uncaught HierarchyRequestError: Failed to execute 'appendChild' on 'Node': The new child element contains the parent”
With disposal of the objects, everything runs fine.
This leads me to the conclusion that the objects aren’t always removed from their DOM parent which leads to recursion (a node is added to an old child node of itself).
Can someone point me in right direction how to ensure the removal of the child nodes before pooling them?
Below is the code I use for pooling:
function getPoolElement(type) {
var elem = pool.getObject(type);
//console.log(type.toString() + " " + elem.$$hash + " " + elem.classname);
return elem;
}
function poolElements(container) {
var children = container.removeAll();
for(var i = 0; i < children.length; i++) {
if(children[i].classname == "guibuilder.group"
|| children[i].classname == "guibuilder.picgroup"
|| children[i].classname == "guibuilder.tablegroup"
|| children[i].classname == "guibuilder.bordergroup") {
poolElements(children[i]);
} else if(children[i].classname == "guibuilder.smallchoice"
|| children[i].classname == "guibuilder.choice") {
var opts = children[i].removeAll();
for(var j = 0; j < opts.length; j++) {
pool.poolObject(opts[j]);
//opts[j].dispose();
}
}
pool.poolObject(children[i]);
//children[i].dispose();
}
}
Regards, Johannes

Related

I am trying to create multiple loops but if one loop returns null it doesn't run the rest of the loop. How do I get around this?

I have multiple for loops in one code, as I am trying to collect data based off identifier "Y". There are some sheets that do not have identifier "Y" and those sheets always cause my script to stop running as the error cannot find the length in that specific for loop since there is none.
How do I get around this? I've tried if/else in everywhere I think would work and it's not working.
I've tried if/else statements and breaks but I must not be putting them in the right spot.
var VDSLr = VDSL.getRange('A:AS');
var VDSLraw = VDSLr.getValues();
var VDSLdata = []
for (var i = 0; i< VDSLraw.length ; i++){
if (VDSLraw[i][44] == "Y")
{
VDSLdata.push(VDSLraw[i])
}
Pull.getRange(Pull.getLastRow()+1,1, VDSLdata.length,
VDSLdata[0].length).setValues(VDSLdata);
}
var ITr = IT.getRange('A:AS');
var ITrawdata = ITr.getValues();
var ITd= []
for (var i = 0; i< ITrawdata.length ; i++){
if(ITrawdata[i][44] == "Y")
{
ITd.push(ITrawdata[i])
}
Pull.getRange(Pull.getLastRow()+1,1, ITd.length,
ITd[0].length).setValues(ITd);
}
**Edit: it won't let me post a picture of my error yet. Here's a few
examples though:
Error (1):**
var VDSLr = VDSL.getRange('A:AS');
var VDSLraw = VDSLr.getValues();
var VDSLdata = []
for (var i = 0; i< VDSLraw.length ; i++){
if (VDSLraw[i][44] != "Y")**continue**;
if (VDSLraw[i][44] == "Y");
{
VDSLdata.push(VDSLraw[i])
}
}
Pull.getRange(Pull.getLastRow()+1,1, VDSLdata.length,
VDSLdata[0].length).setValues(VDSLdata);
var ITr = IT.getRange('A:AS');
var ITrawdata = ITr.getValues();
var ITd= []
for (var i = 0; i< ITrawdata.length ; i++){
if (ITrawdata[i][44] != "Y")continue;
if (ITrawdata[i][44] == "Y")
{
ITd.push(ITrawdata[i])
}
}
Pull.getRange(Pull.getLastRow()+1,1, ITd.length,
ITd[0].length).setValues(ITd);
So if I put a continue here, it won't read the length. Error code is "Cannot read property "length" from undefined. Which I know is correct. This is what I'm trying to bypass. "VDSL" is a sheet that normally does not have what I am looking for. But since it won't find the length it won't continue to sheet "IT."
I have also moved around the continues to different spots, and even a break (in the same spot as continue) but my combinations seem to provide a never ending loop of the same info.
The other attempt is with if else statements. When I use those I get a synthax error. On this error(2) I've tried:
if (VDSLraw[i][44] == "Y")
{//code here}
else if (VDSLraw[i][44] != "Y"){break};
I feel like I'm making this more complicated than it is, should be a simple if/then statement but since I have to pull the data and compile it to one sheet the for loop is the best way to go. Just can't figure out the last piece. I could do them separately but that's my last resort. There's 12 sheets, so clicking 12 scripts each time I need to do this doesn't seem efficient.
as soon as you provided limited information about your data I made some assumptions, I hope it matches your needs.
function getY_Data(){
// get the current Spreadsheet;
var currentSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// get all tabs on the file, so you wont need to keep track of how many tabs you have
var tabsArray = currentSpreadsheet.getSheets();
var resultsSheet = currentSpreadsheet.getSheetByName("results");
var currentSheetValues;
var collected_Y_Rows = [];
// iterate over all tabs
tabsArray.forEach(function(tabObject,index){
// skip the results tab
if(tabObject.getName() === "results"){ continue; }
// set the current sheet data to currentSheetValues variable
currentSheetValues = tabsArray[0].getDataRange().getValues();
// Im considering that all your sheets has the same row size
currentSheetValues.forEach(function(row,index){
if(row[44] == "Y"){
collected_Y_Rows.push(row);
}
});
});
// if it hasnt find any row with "Y" it won't clear the "results" tab or try do add empty data to the "results" sheet
if(collected_Y_Rows.length === 0){
return;
}
// clear the current values and formats
resultsSheet.clear();
// append new data starting on row 1 and col 2;
// Im considering that all your sheets has the same row size;
// if the sheets tabs has different sizes of data (columns) it will throw an error because when using the range.setValues(collected_Y_Rows),
// all rows on "collected_Y_Rows" mas have the same size;
resultsSheet.getRange(1, 1, collected_Y_Rows.length, collected_Y_Rows[0].length).setValues(collected_Y_Rows);
}

Alfresco check for adding files

There is a review and approval workflow
On the start forms are attached files and selected executors(Package Items and People selection).
Then create a task is assigned to the previously selected executors.
Each executor sees the task assigned to it, and file attachments.
I need to check for adding files. While the executor has not added a file it can not approve the task.
I created the counter at the time of task creation taskListener event="create".
He counts the files sent to the executor.
Then I created another counter at the time of completion of the task taskListener event="complete", It also counts files.
Then I compare these two counters and if they are equivalent
It means that the executor does not attach files and he sees the error.
But this method works only for the first executor who approved the task.
The rest of the executors can already approve the task without adding files.
I do not know what the problem is.
Here's the code where I implemented it:
<userTask id="userTask5" name="Revies" activiti:assignee="${zvernennya_reviewnachassignee.properties.userName}" activiti:formKey="zvernennya:reviewnach">
<documentation>Review task</documentation>
<extensionElements>
<activiti:taskListener event="create" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
<activiti:field name="script">
<activiti:string><![CDATA[
if (typeof bpm_workflowDueDate != 'undefined') task.dueDate = bpm_workflowDueDate;
if (typeof bpm_workflowPriority != 'undefined') task.priority = bpm_workflowPriority;;
var count=0;
for (var i = 0; i < bpm_package.children.length; i++)
{
count++;
}
execution.setVariable ('count', count);
]]></activiti:string>
</activiti:field>
</activiti:taskListener>
<activiti:taskListener event="complete" class="org.alfresco.repo.workflow.activiti.tasklistener.ScriptTaskListener">
<activiti:field name="script">
<activiti:string><![CDATA[
if(task.getVariableLocal('zvernennya_reviewnachtransitions') == 'Approve') {
execution.setVariable('zvernennya_reviewnachapprovalcount', zvernennya_reviewnachapprovalcount + 1);
}
var count_new=0;
for (var i = 0; i < bpm_package.children.length; i++)
{
count_new++;
}
if (count==count_new) {
var message = "\n\nAttach files!!\n";
throw new Error(message + "\n");
}
]]></activiti:string>
</activiti:field>
</activiti:taskListener>
</extensionElements>
<multiInstanceLoopCharacteristics isSequential="false" activiti:collection="zvernennya_executers" activiti:elementVariable="zvernennya_reviewnachassignee">
<completionCondition>${zvernennya_reviewnachapprovalcount >= zvernennya_reviewnachrequiredapprovalcount}</completionCondition>
</multiInstanceLoopCharacteristics>
</userTask>
I think you need to re-initialize the variable "count" in the 2nd tasklistener ("complete"). like so:
var count = execution.getVariable ('count');
var count_new= bpm_package.children.length;
if (count==count_new) {
var message = "\n\nAttach files!!\n";
throw new Error(message + "\n");
}

ReferenceError: Error #1069 Actionscript 3

So i have been stuck on this for about 2 weeks and i have no idea how to progress.
I have an array of movie clips called "_main.speederArray" and i'm trying to make it so that if they collide with each other then they are both destroyed. Here is my code in the "Speeder class" to detect collision.
private function detectionHandler():void{
//trace("array length", _main.speederArray.length);
detectionID = _main.gameCounter;
for ( var i:int = _main.speederArray.length -1; i >= 0; i--){
var speeder:Speeder = _main.speederArray[i];
if(speeder.destroyMe) continue;
if(speeder.detectionID == this.detectionID) continue;
if (boxIntersect(this, speeder)){
trace("collision");
destroyMe = true;
speeder.destroyMe = true;
}
}
}
Here is the boxIntersect function this code refers to. It's in the same class
private function boxIntersect ( speeder1:Speeder, speeder2:Speeder):Boolean{
if(speeder1.x + speeder1.distRight < speeder2.x + speeder2.distLeft) return false; //checking for overlap on X axis
if(speeder1.x + speeder1.distLeft > speeder2.x + speeder2.distRight) return false;
if(speeder1.y + speeder1.distBot < speeder2.y + speeder2.distTop) return false; // checking for overlap on Y axis
if(speeder1.y + speeder1.distTop > speeder2.y + speeder2.distBot) return false;
return true;
}
And then here is where i think the problem is. I have a class called "spawner" and this is where i was going to handle the objects being created and destroyed. Here is the code where i am trying to splice objects from the array depending on whether the destroyMe bool is set to true. At this stage i have confused the shit out of myself so any help would be greatly appreciated!
private function updateArray(e:Event):void{
for(var i:int = _main.speederArray.length - 1; i>=0; i--){
var speeder:Speeder = _main.speederArray[i];
if(speeder.destroyMe){
//trace("hello");
removeChild(speeder[i]); // take it off the stage
_main.speederArray[i] = null;
_main.speederArray.splice(i, 1); //remove it from the array
}
}
}
Now, the game runs however as soon as the 2 objects within the same array collide, i get the collision trace in the output window but straight after i get this :
ReferenceError: Error #1069: Property 1 not found on com.game.Speeder and there is no default value.
at com.game::Spawner/updateArray()
No idea what it means :(
Any help appreciated thanks guys!
The problem comes from the line
removeChild(speeder[i]); inside your update function.
Speeder has no properties that are called 1 and the 1 comes obviously from your for loop.
So, to solve this problem, you should simply call
removeChild(speeder);
speeder already is the object at the position i of your array. Putting [] behind an object is the same like accessing a property from it. essentially you were doing this:
removeChild(speeder.1);

AngularJS "10 $digest() iterations reached" in Internet Explorer dealing with a custom filter

Our project is using a custom filter to provide sorting and filtering of items in a list. It takes two arguments, the list, and a filter type parameter that determines the sort/filter scheme to apply. The filter appears to be responsible for a "10 $digest() iterations reached" error in Internet Explorer (only). The business end of the filter is below:
return function(players, filterType) {
switch (filterType) {
case 'Money':
return players.sort(function (a, b) {
if (a.IsSelf) return -1;
if (a.WinnerPrizeMoney == b.WinnerPrizeMoney) return 0;
if (b.IsSelf || a.WinnerPrizeMoney < b.WinnerPrizeMoney) return -1;
if (a.IsSelf || a.WinnerPrizeMoney > b.WinnerPrizeMoney) return 1;
return 0;
});
case 'Tracked Players':
var trackedPlayers = [];
for (var i = 0; i < players.length; i++) {
if (players[i].IsTracked || players[i].IsSelf) {
trackedPlayers.push(players[i]);
}
}
return trackedPlayers;
case 'Connections':
var connectedPlayers = [];
for (var j = 0; j < players.length; j++) {
if (players[j].IsConnected || players[j].IsSelf) {
connectedPlayers.push(players[j]);
}
}
return connectedPlayers;
case 'Rank':
return players.sort(function (a, b) {
if (a.IsSelf) return -1;
if (a.WinnerPosition == b.WinnerPosition) return 0;
if (b.IsSelf || a.WinnerPosition < b.WinnerPosition) return -1;
if (a.IsSelf || a.WinnerPosition > b.WinnerPosition) return 1;
return 0;
});
default:
}
};
Two of the filter types sort the items, the other two filter the items. The problem presents almost as soon as the page loads and gets items to filter, and initially the filterType is set to 'Rank'.
I have read that array.sort modifies the array in place, (i.e. it does not return a new array). Is my understanding on that count correct? .sort would not cause this problem as it is returning the same array it came in with, the items are just changed in position. That applies to filterTypes of 'Money' and 'Rank'.
For 'Tracked Players' and 'Connections' is there a better way to handle those than by creating a new array and pushing specific items into it according to the filter? While this does not appear to be the culprit in this instance, it seems to fit the mold that others have suggested as possible causes in other SO articles regarding this error.
I feel like I am spinning my wheels on this, I spent about 6 hours yesterday ("after work") fiddling with this trying to diagnose and fix it. I have narrowed it down to the filtering mechanism above, but other than that, I am having no luck.
Update
This seems to have specifically to do with Internet Explorer. I tested the filter in Chrome and Firefox and it was only hit once per filterType change (e.g. user changes the value of the Filter dropdown which in turn changes the filterType and fires off the filter.
Internet Explorer however repeatedly hits the filter. And only when filterType = 'Rank'. I don't get that though. Rank and Money have almost the exact same sorting scheme, just on different properties.
Just to be sure that this did not have something to do with the fact that I set filterType = 'Rank' in the initialization of the controller, I changed it to all three of the other values in turn. No problems. This now seems specifically to do with possibly the comparison of the values WinnerPosition (numeric) or with some value somehow changing on the item being sorted.
Stepping Through Execution Update
OK, so I may need someone to enlighten me. The $watchCollectionWatch function (angular.js:12307 in my case) iterates through the items in each collection on the scope and checks the oldValue (i.e. what was passed into the filter in this case) with the newValue (what came back) if the two are different it increments changeDetected signaling that a collection has changed. When a collection changes that has a filter on it, it re-runs the filter. In my case I am changing the ordering of the collection and thus every time the filter gets run, it reads it as having changed. How to get around this?
I ended up changing this around so that instead of having the filter above registered as such with the app, I put it on the controller called by ng-change on the drop down that the user specifies the filter with.
I changed the code a little. I store Players in both $scope.Players and $scope.StoragePlayers. StoragePlayers holds the empirical set of Players. $scope.Players is what the list of players on the page is bound to. I modify $scope.Players and only read from $scope.StoragePlayers.
New Version
$scope.NewFilter = function () {
switch ($scope.SelectedFilter) {
case 'Money':
$scope.Players = $scope.StoragePlayers.sort(function (a, b) {
if (a.IsSelf) return -1;
if (a.WinnerPrizeMoney == b.WinnerPrizeMoney) return 0;
if (b.IsSelf || a.WinnerPrizeMoney < b.WinnerPrizeMoney) return -1;
if (a.IsSelf || a.WinnerPrizeMoney > b.WinnerPrizeMoney) return 1;
return 0;
});
break;
case 'Tracked Players':
var trackedPlayers = [];
for (var i = 0; i < $scope.StoragePlayers.length; i++) {
if ($scope.StoragePlayers[i].IsTracked || $scope.StoragePlayers[i].IsSelf) {
trackedPlayers.push($scope.StoragePlayers[i]);
}
}
$scope.Players = trackedPlayers;
break;
case 'Connections':
var connectedPlayers = [];
for (var j = 0; j < $scope.StoragePlayers.length; j++) {
if ($scope.StoragePlayers[j].IsConnected || $scope.StoragePlayers[j].IsSelf) {
connectedPlayers.push($scope.StoragePlayers[j]);
}
}
$scope.Players = connectedPlayers;
break;
case 'Rank':
$scope.Players = $scope.StoragePlayers.sort(function (a, b) {
if (a.IsSelf) return -1;
if (a.WinnerPosition == b.WinnerPosition) return 0;
if (b.IsSelf || a.WinnerPosition < b.WinnerPosition) return -1;
if (a.IsSelf || a.WinnerPosition > b.WinnerPosition) return 1;
return 0;
});
break;
default:
}

Is it possible to reload or reset an array in as3?

I'm wondering if it is possible to reset / reload / reconstruct an array order?
I'm making this "Space Invaders" game and the enemy's need to restart to it's position when the game is being restarted. When I shoot down the enemy's and reset my game, the enemy's I've killed keep being gone.
So here's some of the code responsible:
var spiderArray:Array = new Array(enemyField.enemy1,enemyField.enemy2,
enemyField.enemy3,enemyField.enemy4,
enemyField.enemy5,enemyField.enemy6,
enemyField.enemy7,enemyField.enemy8,
enemyField.enemy9,enemyField.enemy10,
enemyField.enemy11,enemyField.enemy12,
enemyField.enemy13,enemyField.enemy14,
enemyField.enemy15,enemyField.enemy16,
enemyField.enemy17,enemyField.enemy18,
enemyField.enemy19,enemyField.enemy20,
enemyField.enemy21,enemyField.enemy22,
enemyField.enemy23,enemyField.enemy24,
enemyField.enemy25,enemyField.enemy26,
enemyField.enemy27,enemyField.enemy28,
enemyField.enemy29,enemyField.enemy30,
enemyField.enemy31,enemyField.enemy32,
enemyField.enemy33,enemyField.enemy34,
enemyField.enemy35,enemyField.enemy36,
enemyField.enemy37,enemyField.enemy38,
enemyField.enemy39,enemyField.enemy40,
enemyField.enemy41,enemyField.enemy42,
enemyField.enemy43,enemyField.enemy44,
enemyField.enemy45,enemyField.enemy46,
enemyField.enemy47,enemyField.enemy48,
enemyField.enemy49,enemyField.enemy50,
enemyField.enemy51,enemyField.enemy52,
enemyField.enemy53,enemyField.enemy54,
enemyField.enemy55,enemyField.enemy56,
enemyField.enemy57,enemyField.enemy58,
enemyField.enemy59,enemyField.enemy60,
enemyField.enemy61,enemyField.enemy62,
enemyField.enemy63,enemyField.enemy64,
enemyField.enemy65,enemyField.enemy66);
Now the place where the enemy's are being killed:
function enemyHitTest():void {
//for each of the three spiders
for(var i:int = 0; i < spiderArray.length; i++) {
//the each of the six bullets
for(var j:int = 0; j < 6; j++) {
//don't consider bullets that aren't in play:
if(bulletArray[j].y > SpelerMC.y) continue;
if(spiderArray[i].hitTestObject(bulletArray[j])) {
score += 10;
scoreTxt.text = score.toString();
trace("Invader " + i + " neergeschoten!");
spiderArray[i].parent.removeChild(spiderArray[i]);
bulletArray[j].x = j * 70 + 100;
bulletArray[j].y = 595;
}
}
}
Now I think I need to put some sort of theArray.pop(); or something, but don't know how to use it, but I need to place it in this function:
function startGame() {
trace("Start het spel opnieuw...");
gameTimer.addEventListener(TimerEvent.TIMER, onTick);
gameTimer.start();
enemyField.x = 400;
enemyField.y = 160;
SpelerMC.x = 83;
SpelerMC.y = 531;
}
Please help me! Have been searching for 5 hours already. Thanks in advance!
to remove element number i use array.splice(i, 1); ( http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/Array.html#splice().com/en_US/FlashPlatform/reference/actionscript/3/Array.html#splice%28%29) but keep in mind that array.length will decrease
to reset the array just invoke spidersArray = new Array(enemyField.enemy1, etc) again
UPDATE
in in the enemyHitTest function i changed the removing condition to if(enemyArray[i].visible && enemyArray[i].hitTestObject(laserArray[j])) and enemyArray[i].parent.removeChild(enemyArray[i]); to enemyArray[i].visible = false;
and added
function respawnEnemies():void{
for(var i:int = 0; i < enemyArray.length; i++) {
enemyArray[i].visible = true;
}
}
to call it from startGame
full code here
upd 2
so the problem was not in resetting the array but in the fact that your enemyField and its' enemies were added to stage manually and removed programmatically so there was no code to call to bring them back
if all your instances should be preserved - e.g. you generate all actors at the beginning and later all of them are reused (at the new game) you can set an array of them and on each start game make a copy and remove "dead" enemies from the copied array
also better option is to use a vector e.g.
var enemies:Vector.<Enemy> = Vector.<Enemy>([]);//in brackets references to the instances of Enemy class
var inGame:Vector.<Enemy> = enemies.concat();
also 5hrs of research? please be patient and try harder,
best regards

Resources