Flash AS2 show text one by one from array - for-loop

I want to dynamically display some text from an array one after another in a dynamic textfield.
var wordList:Array = new Array('one','two','three');
for (var i = 0; i < wordList.length; i++) {
this.text_mc.txt.text = wordlist[i];
// Pause for 3 seconds and then move next
}
its the "Pause for 3 seconds and then move next" part I cant figure out.
Thanks.

track what index of the array you are currently showing, and use the setInterval function to call your 'showNext' function every 3000 milliseconds
ie)
var wordList:Array = new Array('one','two','three');
var curIndex = 0;
renderText(curIndex);
setInterval( showNextText, 3000 );
function showNextText()
{
curIndex++;
renderText(curIndex);
}
function renderText( index:Number )
{
this.text_mc.txt.text = wordlist[index];
}

Related

How to get a loop to load movieclips with eventlisteners

I wanted the scene load 5 different movie clips (named B1-B5). Each movie clip is placed on a specific x and y. Each movie clip grows/shrinks on roll over/roll out....
I got the code working by typing everything out and duplicating each section per time but it's messy and I'd like to clean up the code by getting a loop to do it (if it's possible?).
This is the code that works but I'd have to duplicate it per movie clip (changing the obvious bits)...
var scene1:MovieClip = new B1();
addChild(scene1);
scene1.x = 170.30;
scene1.y = 231.15;
scene1.addEventListener(MouseEvent.MOUSE_OVER, onRollOverEvent1);
scene1.addEventListener(MouseEvent.MOUSE_OUT, onRollOutEvent1);
function onRollOverEvent1(e:MouseEvent) {
scene1.width=25.9;
scene1.height=25;
}
function onRollOutEvent1(e:MouseEvent) {
scene1.width = 20.9;
scene1.height = 20;
}
Below is what I've tried out but have been stuck for a good while...
for (var i:int=1; i<5; i++){
var scene[i]:MovieClip = new "B"+i();
addChild("scene"+i);
//var scene[i]:MovieClip = new B[i]();
scene[i].addEventListener(MouseEvent.MOUSE_OVER, onRollOverEvent);
scene[i].addEventListener(MouseEvent.MOUSE_OUT, onRollOutEvent)
function onRollOverEvent(e:MouseEvent) {
scene[i].width=25.9;
scene[i].height=25;
}
function onRollOutEvent(e:MouseEvent) {
scene[i].width = 20.9;
scene[i].height = 20;
}
}
scene1.x = 170.30;
scene1.y = 231.15;
scene2.x = 284.30;
scene2.y = 250.75;
scene3.x = 377.30;
scene3.y = 280.15;
scene4.x = 444.30;
scene4.y = 321.15;
scene5.x = 196.30;
scene5.y = 172.15;
First, lets go through your mistakes.
new "B"+i();
At the very best that translates to calling a number i as function and adding the result to "B" as a String. But even new "B1"() is not the same as new B1(). There is, in fact, a method getDefinitionByName(..) that allows to address a class via its name, but I don't recommend to use it because it is advanced topic.
var scene[i]:MovieClip
You just cannot define variables scene1, scene2, etc this way. The closest thing you can actually devise is the square bracket notation: this["scene" + i] = ....
addChild("scene"+i);
The argument must be a DisplayObject instance, not a String.
for (...)
{
...
function onRollOverEvent(e:MouseEvent)
...
}
Do not define functions inside other functions or loops.
scene[i].width = 20.9;
scene[i].height = 20;
By the end of your loop i will be equal to 5, so, what do you think such a record will address?
Then, the solution.
When you come to scaling your working solution to multiple instances, you are to go algorithmic. Loops and Arrays are your friends.
// Lets devise a list of classes and (x,y) coordinates.
var Designs:Array = [
null, // the 0-th element
{id:B1, x:170, y:230},
{id:B2, x:285, y:250},
];
for (var i:int = 1; i < Design.length; i++)
{
// Retrieve a record for the future object.
var aDesign:Object = Designs[i];
// Get a reference to the object's class.
var aClass:Class = aDesign.id;
// Create the object. Yes, you CAN omit () with
// the "new" operator if there are no mandatory arguments.
var aThing:Movieclip = new aClass;
// Set coordinates from the design record.
aThing.x = aDesign.x;
aThing.y = aDesign.y;
// Add to the display list.
addChild(aThing);
// Subscribe the event handlers.
aThing.addEventListener(MouseEvent.MOUSE_OVER, onOver);
aThing.addEventListener(MouseEvent.MOUSE_OUT, onOut);
// Save the object's reference for the later use.
// If you'd need to address, say, 3rd object,
// you do it as following:
// Designs[3].instance
aDesign.instance = aThing;
}
function onOver(e:MouseEvent):void
{
// You subscribed all of the objects to this one event handler.
// This is the correct way to learn, which one of the objects
// is under the mouse and is dispatching the said event.
var aThing:MovieClip = e.currentTarget as MovieClip;
// Change the object's size.
aThing.width = 26;
aThing.height = 25;
}
function onOut(e:MouseEvent):void
{
// Get the source of the dispatched event.
var aThing:MovieClip = e.currentTarget as MovieClip;
// Change the object's size.
aThing.width = 21;
aThing.height = 20;
}

My google script is slowing down my spreadsheet very badly

I'm a total beginner when it comes to writing scripts but somehow managed to copy-paste/write this script that protocols the date when a specific cell has been updated. Somehow the script slows down my spreadsheet so badly that I have to wait a few seconds for every change I make. I used the s.getRange() function instead of s.getActiveCell() because in some cases I want to change up to 30 cells at once and it should then protocol all the changes. Could this maybe slowdown my sheet? Or does anyone have other ideas how I can speed up my sheet?
Why I entered the following functions:
(r.getRow() !1 & r.getRow() !=2) so that the 2 title rows can be change without being protocoled
var name1versandstatus = s.getRange("datum1versandspalte") so that I can insert new columns without affecting the scripts function
function onEdit() {
var s = SpreadsheetApp.getActiveSheet();
if( s.getName() == "Strukturierung" ) {
var r = s.getActiveRange(); //
if ( r.getRow() !=1 & r.getRow() !=2) {
var name1versandstatus = s.getRange("datum1versandspalte")
if( r.getColumn() == name1versandstatus.getColumn()) {
if(r.getValue() == "Versendet"){
var nextCell = r.offset(0, 1);
nextCell.setValue(new Date());
}
}
}
}
}

How to use setTimeout within a for ( ) { } loop?

Good day ! I'm learning javascript and have a problem with the timers. I just wanted to check if the onload event is triggered once the whole page is written including the text modified via javascipt. For that purpose I wanted to slow down the writing of the text by inducing a 200 ms delay between characters.
The test I use is the following:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>Onload test</title>
<script>
function load() {
alert("The page is considered loaded !");
}
function writeSlowly(text, timer) {
var L= text.length;
var st = "";
function write (seq) {
document.getElementById("st").innerHTML = seq;
};
for (var i = 0; i < L; i += 1) {
st += text[i];
setTimeout(write(st), timer);
};
};
</script>
</head>
<body>
<p id="st"></p>
<script>
writeSlowly("This pages takes a while to load", 200);
window.onload = load;
</script>
</body>
</html>
The page loads as if there were no delay at all. Actually I expected the text (32 characters long) to take about 32 x 200 ms =~ 7 seconds. When debugging (with Firebug - I use Firefox 30) the program steps through the lines but the timer has no effect. The page displays almost instantaneously.
You are creating separate timers for each letter, all start at time 0 and all are executing at time 200ms.
Further, the function for setTimeout needs to be a callback (the function will be called back into when the timer expires). You are passing it a null. write() does not return anything much less a function.
So you are actually writing each letter every time you hit the loop, resulting in no delay
To achieve what you are trying I would do something along the lines of...
var str;
var index = 0;
function writeSlowly(text, timer) {
str = text;
setInterval(writeNext, timer);
};
function writeNext()
{
if(index < str.length - 1)
document.getElementById("st").innerHTML = str.substring(0, ++index);
else
document.getElementById("st").innerHTML = str;
}
I made a few modifications and made it work, you can try it out at this link.
One issue is that you were calling the write function, not setting it as a callback. Another issue is that the string you wanted to write was getting filled up completely before you wrote it. Finally, the timer was being set at 200ms from the current time for all writes, instead of introducing a delay of 200ms for each character written.
The updated Javascript is below.
function writeSlowly(text, timer) {
var L= text.length;
var st = "";
var delay = 0;
for (var i = 0; i < L; i += 1) {
st += text[i];
delay += timer
setTimeout(writer(st), delay);
};
}
function writer(toWrite) {
return function() {
document.getElementById("st").innerHTML = toWrite;
}
}
Edit:
I updated the JSFiddle.
When the text is done scrolling, it it will trigger the done() function and run whatever code you'd like to run at that point.
Following the answers given, their analysis (see comments below the original question) my preferred answer is the following - which like the one by Adam - takes almost exactly 5760 msec for a 2880 characters string with a 2 msec delay per character. The central part is below and the full answer on JS Fiddle.
function writeSlowly(text, timer) {
var L= text.length;
var delay = 0;
for (var i = 0; i < L; i += 1) {
setTimeout(writer, delay += timer);
};
function writer() {
if (!writer.seq) writer.seq = 0; // Create a function property that increments on each call.
document.getElementById("slowpara").innerHTML = text.substring(0, ++writer.seq);
}
}
I thank StackOverflow, the community, in particular Cheruvian and Adam for their generous help.

how to create multiple slickgrids with a single function

I have a problem which I cannot seem to solve. I need to create a function which loops over an array of datasets and creates an independent slickgrids for each dataset. The catch is that the functions need to be bound to each grid independently. For example:
// this part works fine
for(var i=0; i<domain.length; i++){
dataView = new Slick.Data.DataView();
grid = new Slick.Grid('#' + domain[i].name, dataView, domain[i].columns, domain[i].options);
var data = domain[i].data;
// this works well and I am able to create several slickgrid tables
... etc ...
The problem is that every grid is now called "grid". Therefore, when I bind a function like this:
// controls the higlighting of the active row
grid.highlightActiveRow = function () {
var currentCell;
currentCell = this.getActiveCell();
I get a result which affects all grids (or in some cases only one grid).
How do I create multiple, independent grids with associated functions??? The problems seems to be that I have created one object "grid" and then assign all functions using the syntax grid.xxx - but I dont know how to create a unique object on each itteration.
Any help would be most appreciated.
PS: slickgrid is just amazing!!
Thanks
//****** UPDATE *********
#Jokob, #user700284
Thank you both for your help. Here is where I have manged to get to:
var dataView;
function buildTable() {
for(i = 0; i<domains.length; i++){
dataView = new Slick.Data.DataView();
var d = domains[i];
grid = new Slick.Grid('#' + d.name, dataView, d.columns, grids.options);
var data = d.data;
grid.init();
dataView.beginUpdate();
dataView.setItems(data);
// dataView.setFilter(filter); -- will be reinstated once i have this working
dataView.endUpdate();
arrOfGrids.push(grid);
};
};
Jakob - for now i am sticking to "for(i)" until I can wrap my head around your comment - which seems very sensible.
But, using the above, the grid data are not populating. I am not getting any js errors and the column headers are populating but not the data. The reference to d.data is definitely correct as I can see the data using the Chrome js debugger.
Any ideas? Many thanks for your help so far
Instead of assign all new grids to grid (in which case you overwrite the old one everytime you create a new one), push them to an array:
var arrayOfGrids = [];
for(var i=0; i<domain.length; i++) {
dataView = new Slick.Data.DataView();
arrayOfGrids.push(new Slick.Grid('#' + domain[i].name, dataView, domain[i].columns, domain[i].options));
// ....
Then, when you want to something with your grids, like adding the highlight-function, you loop over the array and do it for each element:
for ( var i=0; i<arrayOfGrids.length; i++ ) {
arrayOfGrids[i].highlightActiveRow = function () {
var currentCell;
currentCell = this.getActiveCell();
// ... etc...
BONUS
While we're at it, I would recommend that you use the forEach method that's available on the array-object when iterating over the arrays, rather than the for-loop. The unlike the loop, forEach creates a proper scope for your variables and it gets rid of the useless i-iteration variable:
var arrayOfGrids = [];
domain.forEach(function(d) {
dataView = new Slick.Data.DataView();
arrayOfGrids.push(new Slick.Grid('#' + d.name, dataView, d.columns, d.options));
// ....
And then the same for the other loop of course :)
You could try adding each of the grid instances to an array.You will be able to handle each of the grids differently if you want, by means of <arrray>[<array-index>]
var gridArr = [];
// this part works fine
for(var i=0; i<domain.length; i++){
dataView = new Slick.Data.DataView();
var grid = new Slick.Grid('#' + domain[i].name, dataView, domain[i].columns, domain[i].options);
var data = domain[i].data;
// this works well and I am able to create several slickgrid tables
... etc ...
gridArr.push(grid)
Then if you say gridArr[0] you can access the 1st grid,gridArr[1] second grid and so on.
Just in case anybody else is following this question - here is the working solution:
Many many thanks to #Jokob and #user700284
// default filter function
function filter(item) {
return true; // this is just a placeholder for now
}
var dataView;
function buildTables() {
for(i = 0; i<domains.length; i++){
dataView = new Slick.Data.DataView();
var d = domains[i];
grid = new Slick.Grid('#' + d.name, dataView, d.columns, options);
var data = d.data;
grid.init();
dataView.beginUpdate();
dataView.setItems(data);
dataView.setFilter(filter);
dataView.endUpdate();
grid.invalidate();
grid.render();
arrOfGrids.push(grid);
};
};

Store & retrieve the identifiers of a multipliable widget's instances

The aim is to remove only the last row at any time and only by the last remove button.
There is a user interface which building up as a multiplication of the same row. The number of rows are controlled by 'Add' & 'Remove' buttons which are also elements of the row. The problem is that the hidden widgets - that are applied for each row to distinguish the instances by storing their row numbers - are storing the very same number which is the last one. Except the first (0) hidden widget which stores the proper number (0). Where am I missing the point? How should this be resolved?
As per the remove buttons have two different purposes (not detailed here), we use a cacheService to distinguish the last row from all the others. Only the last row should be removed at any time.
var cache = CacheService.getPrivateCache();
we clear the cache and create the first instance
function doGet() {
var app = UiApp.createApplication();
app.add(app.createVerticalPanel().setId('mainContainer'));
cache.removeAll([]);
ui(0);
cache.put('numberOfInstances',0);
return app; }
each instance is held by a horizontal panel which contains the mentioned hidden widget, a label which informs about the instance number, and the Add & Remove buttons.
function ui(instance) {
var app = UiApp.getActiveApplication();
var eventContainer = app.createHorizontalPanel()
.setId('eventContainer' + instance);
var instanceContainer = app.createHidden('instanceContainer',instance);
var showInstance = app.createLabel(instance)
.setId('showInstance' + instance);
var addButton = app.createButton('Add')
.setId('add' + instance)
.addClickHandler(app.createClientHandler()
.forEventSource().setEnabled(false)) //avoiding multiple click during server response
.addClickHandler(app.createServerHandler('add')
.addCallbackElement(instanceContainer));
var removeButton = app.createButton('X')
.addClickHandler(app.createServerHandler('remove')
.addCallbackElement(instanceContainer));
app.getElementById('mainContainer')
.add(eventContainer
.add(instanceContainer)
.add(showInstance)
.add(addButton)
.add(removeButton));
return app; }
and the event handling...
function add(inst) {
var app = UiApp.getActiveApplication();
var instance = Number(inst.parameter.instanceContainer);
ui(instance+1);
cache.put('numberOfInstances',instance+1);
return app; }
function remove(inst) {
var app = UiApp.getActiveApplication();
var instance = Number(inst.parameter.instanceContainer);
var numberOfInstances = cache.get('numberOfInstances')
if( (instance != 0) && (instance = numberOfInstances) ) {
app.getElementById('mainContainer').remove(app.getElementById('eventContainer' + instance));
cache.put('numberOfInstances',instance-1);
app.getElementById('add' + (instance-1)).setEnabled(true); } //avoiding multiple click during server response
return app; }
The aim is to remove only the last row at any time and only by the last remove button.
Many Thanks.
Why don't you simply use a clientHandler just as you did on the 'add' button? You could target the preceding 'remove' button and disable it each time you create a new one and change /update each time you remove one row.
EDIT : I can suggest you something, feel free to have a look, I changed a bit the approach but it is working and I hope you'll find it at least interesting ;-)
Link to the online test
function doGet() {
var app = UiApp.createApplication();
var counter = app.createHidden().setName('counter').setId('counter').setValue('1');
var mainContainer = app.createVerticalPanel().setId('mainContainer')
app.add(mainContainer.add(counter));
var event1Container = app.createHorizontalPanel()
var showInstance = app.createLabel('1')
var addButton = app.createButton('Add')
.setId('add1')
.addClickHandler(app.createClientHandler()
.forEventSource().setEnabled(false)) //avoiding multiple click during server response
.addClickHandler(app.createServerHandler('add')
.addCallbackElement(mainContainer));
var removeButton = app.createButton('X')
.setId('remove1')
.addClickHandler(app.createServerHandler('remove')
.addCallbackElement(mainContainer));
mainContainer.add(event1Container
.add(showInstance)
.add(addButton)
.add(removeButton));
return app; }
function add(inst) {
var app = UiApp.getActiveApplication();
var hiddenVal =inst.parameter.counter;
var counterVal = Number(hiddenVal);
var mainContainer = app.getElementById('mainContainer')
var counter = app.getElementById('counter')
++ counterVal
counter.setValue(counterVal.toString())
var eventContainer = app.createHorizontalPanel().setId('eventContainer'+counterVal)
var showInstance = app.createLabel(counterVal.toString())
var addButton = app.createButton('Add')
.setId('add'+counterVal)
.addClickHandler(app.createClientHandler()
.forEventSource().setEnabled(false)) //avoiding multiple click during server response
.addClickHandler(app.createServerHandler('add')
.addCallbackElement(mainContainer));
var removeButton = app.createButton('X')
.setId('remove'+counterVal)
.addClickHandler(app.createServerHandler('remove')
.addCallbackElement(mainContainer));
app.add(eventContainer
.add(showInstance)
.add(addButton)
.add(removeButton));
if(counterVal>1){app.getElementById('remove'+(counterVal-1)).setEnabled(false)}
return app; }
function remove(inst) {
var app = UiApp.getActiveApplication();
var counterVal = Number(inst.parameter.counter);
var counter = app.getElementById('counter')
if(counterVal ==1) {return app}
var maincontainer = app.getElementById('mainContainer')
app.getElementById('eventContainer' + counterVal).setVisible(false)
--counterVal
counter.setValue(counterVal.toString())
app.getElementById('add'+counterVal).setEnabled(true)
app.getElementById('remove'+counterVal).setEnabled(true)
return app;
}
NOTE : I didn't make use of .remove(widget) since this is a fairly new method and I don't know exactly how it works... I'll test it later. Until then I used setVisible(false) instead, sorry about that :-)
Note 2 : I didn't use the cache since the hidden widget is sufficient to keep track of what is going on... if you needed it for something else then you could always add it back .

Resources