How do I get the current region surrounding the ActiveCell using the Excel JS API?
In VBA this is
Set rng=ActiveCell.CurrentRegion
The current region property in the JavaScript API has now been implemented. The property is called getSurroundingRegion()
There is no direct equivalent, but we do have a range.getUsedRange() that will take an existing range and give you a smaller range that represents the non-empty portions. Note that this method will throw a not-found error if there is nothing in the entire range (since effectively it's an empty range, which Excel can't express).
If you really need the CurrentRegion scenario (and I'd be curious to learn more), you could first get the used range (to ensure you're not loading too much data), then load the values property, and then do range.getExpandedRange(indexOfLastRow, indexOfLastColumn).
BTW, unlike VBA's usedRange, the JS "getUsedRange()" always creates an accurate snapshot of the current used range (the VBA one could get stale), and we're exposing it not just on the worksheet but also on a given range.
Update
What I mean is that there are a couple of scenario, one simpler, the other harder.
The simpler one: you know roughly what range you need, but you just need to trim it. For example, you know you have a table-like entity in columns A:C, but you don't know the row count. That's where
worksheet.getRange("A:C").getUsedRange()
would get you what you need.
The harder one: you use getUsedRange() to trim down what you can, but you then load range.values and manually do a search for rows and columns where each cell is empty (""). Once you have that (suppose you found that the relative row index you care about is 5, and column index 2), you could do
originalRange.getCell(0, 0).getExpandedRange(rowIndex, columnIndex)
Concrete example for the above: You have data in A2:C7, though the getUsedRange() of the worksheet is much larger (and hence my suggestion could try to trim it down further by doing a range.getUsedRange()). But for this case, let's imagine that getUsedRange on a worksheet returned a range corresponding to A1:Z100. worksheet.getRange(0, 0) would get you the first cell, which you can then expand by 5 rows and 2 columns (which you find through simple albeit tedious array iteration) to get the range you care about. Makes sense?
Related
I have an equation that references a dynamic dataset… When referencing these dynamic columns I initially just used the range row 3 to row 2000 (as this range is a lot longer than my actual dataset). Unfortunately when I refresh the data it changes this range and messes up the whole equation… So I attempted to make it dynamic.
The initial equation I wrote (ie referencing row 3 to row 2000) as follows.
=IF(MAXIFS($EA$3:$EA$2000,Book1!$C$3:$C$2000,Book1[#[project_id]])=Book2!EA3,MAXIFS($EA$3:$EA$2000,Book1!$C$3:$C$2000,Book1[#[project_id]]),0)
This is my attempt at making it dynamic (so I don’t need to keep on fiddling around with the equation):
=IF(MAXIFS($EA$3:INDEX($EA$3:$EA$2000,COUNTA($EA$3:$EA$2000)),Book1!$C$3:INDEX($C$3:$C$2000,COUNTA($C$3:$C$2000)),Book1[#[project_id]])=Book2!EA3,MAXIFS($EA$3:INDEX($EA$3:$EA$2000,COUNTA($EA$3:$EA$2000)),Book1!$C$3:INDEX($C$3:$C$2000,COUNTA($C$3:$C$2000)),Book1[#[project_id]]),0)
But I get a #VALUE error and unsure how to resolve this.
The ranges passed to MAXIFS must be of an equal size, which means that COUNTA($C$3:$C$2000) and COUNTA($EA$3:$EA$2000) must be equal, which I suspect they are not (you can easily verify).
You are correct to attempt to restrict your ranges, as this in general is good practice: some functions, however, including MAXIFS, employ implicit detection of the last-used cells within the ranges passed, effectively meaning that you can get away with referencing entire columns with no detriment to calculation performance. As such, that would be my recommendation to you, i.e. use $EA:$EA in place of $EA$3:$EA$2000, etc.
I'm a beginner with Visual Basic, and mainly use it to edit MS Excel files.
When copying/pasting (Cell) content or other values, in some cases .value is added.
When should this be added?
When not?
Is it necessary?
Could it harm my code if I use it in places where it isn't needed?
In Excel VBA a Range object is a fairly rich thing which corresponds to either a cell or a range of cells. As such it has all sorts of properties (it is in a given row, accessible via the .Row property, it has interior color, possible borderlines, formulas, etc. -- all accessible via the right properties after the dot.) Value is one of these properties. It refers to the value in the cell -- typically a number or a text. It wouldn't be used when using Copy and Paste since those methods are used on whole Range object -- as can been seen by the fact that they are able to copy formatting and not just raw values.
You can assign the value in one cell to another. Even though this looks like copy/pasting it really is quite different and is in some sense a low-tech solution when all you want to do is transfer the values. It can be done using either e.g. Range("A1").Value = Range("B1").Value or Range("A1") = Range("B1"). The reason the later works is that Value is the default property of a Range object -- hence .Value is implicit in any context in which you aren't treating the Range as an actual object.
Personally, I always explicitly use Value when I want to either read or set the value in a cell (or range of cells) even though I could rely on the fact that Value is the default property. Most Excel VBA code makes heavy use of both Range objects and the values in the Range objects. For reasons of readability it is a good idea for your code to be explicit about when it is using the range vs. when it is using the value. If you follow the excel-vba tag on SO you will see that it is relatively rare for programmers to rely on Range's default property.
So background first, question second.
I recently discovered an interesting property of named ranges that I'm experimenting with and not finding much help. The property is this: If I name a range (a column in this example), I can use the named range as a reference in formulas and it will usually resolve as though it were a reference to the same relative position as the current cell within the named range. So if I call A:A "Alphabet" and it contains letters a through z, each in their own row, I can simply type =Alphabet in cell b26 and it will evaluate to "z" (i.e. A26 instead of a:A). Seems simple, but it is shaping up to be quite powerful, because there is essentially an index function built-in. Very useful for making tidy formulas.
Onto the issue: when I use this same technique with a range that accepts an array argument (i.e. MAX, EOMONTH, etc.), the reference is resolving in the standard way (Max(A:A)). If I wrap the reference in VALUE(), then it resolves to just the single reference within the larger range (a26). The question is simply can anyone think of any way to avoid needing to do this, or at least to make the wrapper as unobstrusive as possible?
Real world example: I have a list of employees and I want to determine which date from three named ranges is larger. So I have something like
='DateSameRow1' > Max('DateSameRow2','DateSameRow3','DateSameColumn', and it is resolving as =a10 > Max(b:b,c:c,2:2). Note the issue: The named range outside of MAX resolved one way, and inside MAX resolved another. Sure, I could just write = a10 > Max(b10,c10,d2) or whatever, but this is so much more readable in what will end up being a huge formula. Right now I'm having to write MAX(VALUE('DateSameRow2')) or whatever to get the result I want and it is defeating the purpose.
Thanks
You can use --NAMED_RANGE in front of the "offending" named range and it will force a negative VALUE and then undo the negative.
Per my comment, I would recommend you not build a spreadsheet on this functionality. The -- is even further removed from VALUE in indicating that a named range is being used in this way.
i have a named range that refers to range D3:I23 and this range is well-defined for some automation purposes.
Recently i had an update that required me to redefine this range as F3:I23 and exclude, initially, columns D & E. But further in the various logic coding, i need to include E for evaluation (turning dynamic data to static data).
Was thinking of using Resize but didnt seem right. Also thought Offset but that moves the whole range forward or backwards. I basically need to resize the range back 1 column while retaining the original defined range
In essence i need the named range to be defined as F3:I23 but during this one code segment i need the range to be evaluated to E3:I23.
Any thoughts, or combination of Range properties to use in VBA? At the point that i am passing the reference, it is being stored in a Range object, so any chained set of properties is fair game.
Please try to apply the KISS policy when answering. Doesnt need to be an overly complex formula, as i am not guaranteed to be the one supporting the end result.
As Rachel indicated... this should do the trick assumes your named range is defined as namedRange:
Set neededRange = namedRange.Resize(namedRange.Rows.Count, _
namedRange.Columns.Count + 1).Offset(0, -1)
Resize to increase the columns included by 1, then offset the entire range by -1 column to get your neededRange.
I have a Named Range setup in an Excel worksheet which I'm using to supply values for a Data Validation drop-down. My source formula is, basically, this:
=INDIRECT( "OnePartOfTheRangeName" & "AnotherPart" )
The range changes based on another value in the row, so that's why I have to combine strings, etc.
I want to add an extra value to the Data Validation list but am not having any luck with that. I thought that if there was some sort of "Union" function I could combine the INDIRECT list with the single value, but I haven't been able to find such a function.
Does anyone know another way to solve my issue?
Excel is quite specific in its error message (indeed, rather a nice change!):
so I doubt worth too much effort in attempting a direct approach. And I am bearing in mind that over three years without a solution to a fully understandable question probably means "it is not possible".
However an indirect approach might serve, though for that some details may be missing - for example how your named range is being constructed at present. For the purposes of illustration, assume that is named Part1 and refers to R1:R12, with blanks at the end (to allow room for expansion) and blanks in the middle (to show versatility). Assume 'another part' is named Part2 and refers to S1:S10, also with blanks in the middle and at the end (and also at the start).
The Data Validation might then be a List whose Source: =whole is the range T1:T22 named whole.
T1 would then be populated with:
=IFERROR(INDEX(Part1,SMALL(IF(ISBLANK(Part1),"",ROW(Part1)-MIN(ROW(Part1))+1),ROW(A1))),IFERROR(INDEX(Part2,SMALL(IF(ISBLANK(Part2),"",ROW(Part2)-MIN(ROW(Part2))+1),ROW(A1)-SUMPRODUCT(--NOT((ISBLANK(Part1)))))),""))
(courtesy of Get Digital Help) entered with Ctrl+Shift+Enter and copied down to T22.
This is dynamic in that adding an entry in ColumnR for example adds that into ColumnT which in turn adds into the validation drop-down.
Disadvantages include that the dropdown is not sorted in order if S and T entries are not sorted and the 'room for expansion' remains evident in the drop-down.