How to script editor to clear cells but keep formula in certain cells - google-apps-script-editor

Is there a way to keep formulas in certain cells when I have a clear cell script. At the moment it clears everything and removes my formula.
Cells with formulas are - 'H2' & 'K2'
function reset() {
var sheet = SpreadsheetApp.getActive();
sheet.getRange("F3:K8").clearContent();
}

Clearing your content will always clear the formula in a cell. A cell has a text/number literal or a formula in it. There's not a function that will clear one and not the other.
But, you can check to see if a cell contains a formula, and if so, don't clear the content for it. That will functionally do what you want.
function reset() {
var sheet = SpreadsheetApp.getActive();
var range = sheet.getRange('F3:K8');
var numRows = range.getNumRows();
var numCols = range.getNumColumns();
for (var i = 1; i <= numRows; i++) {
for (var j = 1; j <= numCols; j++) {
if (range.getCell(i,j).getFormula());
{
range.getCell(i,j).clearContent();
}
}
}
}

Related

Flex how to use callLater?

In my flex mobile application, I have a loop running for over 100 iterations. In each iteration I'm updating some properties of specific Label(s). Since the loop is time consuming, I need to update the screen and display intermediate results at each iteration. How can I break the loop and refresh the display list?
function theFunction():void{
for var i:int = 0; i < n; i++{
doBusyStuff();
label_1.text = "iteration"+" i";
}
}
In that situation, I prefer to use flash.utils.setTimeout()
import flash.utils.setTimeout;
function theFunction(limit:int, current:int = 0):void
{
if (current >= limit)
return;
doBusyStuff();
label_1.text = "iteration "+ current.toString();
setTimeout(theFunction, 0, limit, current+1);
}
However, both setTimeout() and callLater() depend on the tick or the frame rate, meaning that they won't do as fast as they can. So if you also want it to run faster, you should have it run a few loops per each call.
Another solution, similar to Chaniks' answer, uses DateTime to check how long the loop has been running on each iteration. Once it detects that it's been running for too long, it ends the loop and picks up again on the next Frame.
var i:int;
function callingFunction():void {
i = 0;
stage.addEventListener(Event.ENTER_FRAME, theFunction);
}
function theFunction(e:Event):void {
var time:DateTime = new DateTime();
var allowableTime:int = 30; //Allow 30ms per frame
while ((new DateTime().time - time.time < allowableTime) && i < n) {
doBusyStuff();
i++;
}
if (i >= n) {
stage.removeEventListener(Event.ENTER_FRAME, theFunction);
}
label_1.text = "iteration"+" i";
}
There are several methods to force redraw of components:
invalidateDisplayList();
invalidateProperties();
invalidateSize();
Just use whatever you need for your components inside a function and call it after your script using callLater(yourRedrawFunction);
EDIT: For example, in your case:
function theFunction():void{
for var i:int = 0; i < n; i++{
doBusyStuff();
label_1.text = "iteration"+" i";
}
callLater(yourRedrawFunction);
}

How to tell when element is finally shown on screen?

I have a "Loading" dialog that displays while I'm adding a lot of custom elements to a container. I've set the dialog to disappear when the last added element's creationCompleteHandler is called, but the dialog disappears before all the elements display on screen (which results in a very large lag).
Here's an example of what I'm doing:
for (var i:int = 0; i < 100; i++) {
var elem:MyElement = new MyElement();
elem.name = "elem" + i;
container.addElement(elem);
if (i == 99) {
elem.creationComplete = function():void {
PopUpManager.removePopUp(loadingDialog);
};
}
}
So as I've said, the dialog disappears before all the elements appear on screen. Is there a way to tell when all the custom elements have been added AND are currently showing on screen?
Update: To clarify, elem.creationComplete is just a custom property function that gets called when the element's creationCompleteHandler is called.
The elements, even though they have been added in the right order, they are not created in that order:
private function doStuff():void {
PopUpManager.addPopUp(myPopup, this);
for (var i:int = 0; i < 10; i++) {
var elem:MyElement = new MyElement();
elem.name = "elem" + i;
container.addElement(elem);
elem.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:FlexEvent):void {
trace("i'm done " + e.target.name);
});
if (i == 9) {
elem.addEventListener(FlexEvent.CREATION_COMPLETE, function():void {
trace("i'll remove the popup " + elem.name);
PopUpManager.removePopUp(myPopup);
});
}
}
}
Gives:
i'm done elem5
i'm done elem7
i'm done elem0
i'm done elem8
i'm done elem6
i'm done elem3
i'm done elem9
i'll remove the popup elem9
i'm done elem1
i'm done elem4
i'm done elem2
You need to add a global variable to check that all the elements have actually been created:
public var created:int = 0;
private function doStuff():void {
PopUpManager.addPopUp(myPopup, this);
for (var i:int = 0; i < 10; i++) {
var elem:MyElement = new MyElement();
elem.name = "elem" + i;
container.addElement(elem);
created++; // <--- increment with each new element
elem.addEventListener(FlexEvent.CREATION_COMPLETE, function(e:FlexEvent):void {
created--; // <--- decrement when element is created
trace("i'm done ", e.target.name);
if (created == 0) {
trace("i'll remove it ", e.target.name);
PopUpManager.removePopUp(myPopup);
}
});
}
}
And the result is:
i'm done elem5
i'm done elem7
i'm done elem0
i'm done elem8
i'm done elem6
i'm done elem3
i'm done elem9
i'm done elem1
i'm done elem4
i'm done elem2
i'll remove it elem2
To solve this, I followed jidma's answer, except I listened for the PropertyChanged event and decremented when the contentHeight property changed on the container. This decremented only when the container's height was affected by the added element, which seemed to work.

AdvancedDataGrid Flex - Row not getting added under correct column

I'm dynamically adding rows and they don't seem to go under the proper column. I have all of my headers in 'headerArray' and the data i need to add is in the string 'item'.
//create an item to work with
var chartItem:Object = new Object();
for( var j:int = 0; j < columnResult.length ; j++ )
{
var item:String = removeformat(removetd(columnResult[j]));
//grab the header (this is which column the value will be added
var head:String = headerArray[j];
//set the value to header (pair)
chartItem[head] = item;
}
//add the chartItem (row) to the main collection
arr.addItem(chartItem);
tableCollection = arr;
It's getting all the headers properly and setting the chartItem (from inspection with debugger). When it gets to a row (building from html) where there is an item that only has values for some of the columns, it doesn't add the information under the right column, it just goes from left to right and adds it in the next one.
The behaviour is kind of strange because the chartItem clearly has the right header value and corresponding item value in it, but like I said they don't end up under the right column.
tableCollection gets set as the dataprovider for the grid later (not modified since)
var chartItem:Object = new Object();
var span:int = 0;
for( var j:int = 0; j < columnResult.length ; j++ )
{
var colSpan:int = this.getColSpan(columnResult[j]);
var item:String = removeformat(removetd(columnResult[j]));
//grab the header (this is which column the value will be added
var head:String;
if (colSpan >1){
head = headerArray[j];
span = colSpan;
} else {
if (span == 0){
head = headerArray[j];
} else {
head = headerArray[j+span-1]
}
}
//set the value to header (pair)
chartItem[head] = item;
}
//add the chartItem (row) to the main collection
arr.addItem(chartItem);
If i read the span attribute for the row, i set the NEXT row to be at column+previous colspan. then all the rows line up properly.

getCharIndexAtPoint() equivalent in Spark RichEditableText

I want to find a way to get the character index in a Spark based RichEditableText based on mouse x, y position.
The mx.controls.TextArea has a protected getCharIndexAtPoint() method but I can't find an equivalent of this in the Spark RichEditableText which is disappointing.
Any ideas or recommendations?
I can see why. seems RichEditableText uses FTE, while TextArea uses TextField, so you can just use TextField::getCharIndexAtPoint. you may just as well have no char at a point.
It's a long time since I've had a a look at FTE, but I think TextLine::getAtomIndexAtPoint would be a good start. Also, you should have a look at TLFTextField::getCharIndexAtPoint.
I was looking for a similar solution after the heads up from back2dos i came up with the following solution, probably needs a bit of work but it functions
http://www.justinpante.net/?p=201
Here's what I used:
private function getCharAtPoint(ta:RichEditableText, x:Number, y:Number) : int
{
var globalPoint:Point = ta.localToGlobal(new Point(x, y));
var flowComposer:IFlowComposer = ta.textFlow.flowComposer;
for (var i:int = 0; i < flowComposer.numLines; i++){
var textFlowLine:TextFlowLine = flowComposer.getLineAt(i);
if (y >= textFlowLine.y && y < textFlowLine.height + textFlowLine.y)
{
return textFlowLine.absoluteStart
+ textFlowLine.getTextLine(true)
.getAtomIndexAtPoint(globalPoint.x, globalPoint.y);
}
}
return -1;
}
I had the same problem. The answer Even Mien gave did not work for me, initially.
With the below changes I got it working.
var globalPoint:Point = new Point(stage.mouseX, stage.mouseY);
var flowComposer:IFlowComposer = this.textFlow.flowComposer;
for (var i:int = 0; i < flowComposer.numLines; i++)
{
var textFlowLine:TextFlowLine = flowComposer.getLineAt(i);
var textLine:TextLine = textFlowLine.getTextLine(true);
var textRect:Rectangle = textLine.getRect(stage);
if (globalPoint.y >= textRect.top && globalPoint.y < textRect.bottom)
{
return textFlowLine.absoluteStart + textLine.getAtomIndexAtPoint(globalPoint.x, globalPoint.y);
}
}
return 0;

save state of a dataGrid: visible columns, columns width and order

I want to save remotely (on a database) the state (visible columns, columns width and order) of a Flex3 DataGrid.
For width and visibility I can simply save them by accessing each column attribute.. ugly but possible..
But for the order? Do I have to create the dataGrid dynamically??
Any idea is appreciated
thanks
In my case I have saved the order by header name (I'm making an assumption that your DataGrid always has the same columns and header names).
for (var n:Number = 0; n< datagrid.columns.length; n++)
{
var thiscol:DataGridColumn = DataGridColumn(datagrid.columns[n]);
colArray.addItem(thiscol.headerText);
}
Then I can restore the column order by retrieving the ordered list of column headers, and swapping the position of columns in the datagrid as required.
for (var n:Number = 0; n < colArray.length; n++)
{
moveColumnTo(String(colArray.getItemAt(n)), n);
}
I have defined a function moveColumnTo() to perform the switch.
private function moveColumnTo(columnName:String, columnIndex:Number):void
{
// Find current column position
var i:Number = -1;
for (var n:Number = 0; n < datagrid.columns.length; n++)
{
if (DataGridColumn(datagrid.columns[n]).headerText == columnName)
{
i = n;
break;
}
}
if (i == -1 || i == columnIndex) return; // Don't shift column
this.mx_internal::shiftColumns(i, columnIndex); // Shift column to required position
}
Why can't you just save the order as you're looping through each column?
for(var i:int = 0; i < dataGrid.columns.size; i++)
{
var column:DataGridColumn = dataGrid.columns[i];
arr.push({column.visible, column.width, i});
}

Resources