Assignment to constant not allowed - vba

I am getting this error in one of my macros, the code is
Dim rdel1 As Range
Dim rdel2 As Range
Set rdel1 = Sheets("Sheet1").Range(A1:B100)
For Each rdel2 In rdel1.Cells
If rdel2.Value = "No item selected" Then
rdel2.Offset(1, 0).EntireRow.Delete
rdel2.EntireRow.Delete
rdel2.Address = rdel2.Offset(-1, 0) "Error in this line"
End If
Next rdel2
I want to change the address of redel2 by offset(-1,0). I know it dosen't look the right way to write it but I am unable to get the right syntax to change it. Can someone help! Please!

After you execute
rdel2.EntireRow.Delete
rdel2 will be `Nothing' so any attempt to manipulate it will fail.
If it were not Nothing, and referenceing a cell in a row > 1, then
Set rdel2 = rdel2.Offset(-1, 0)
would work.
It's not clear exactly what you want to achieve, but this may get you started
Sub Demo()
Dim rdel1 As Range
Dim rdel2 As Range
Set rdel1 = Sheets("Sheet1").Range("A1:A100")
Dim rw As Long
For rw = rdel1.Rows.Count To 1 Step -1
Set rdel2 = rdel1.Cells(rw, 1)
If rdel2.Value = "No item selected" Then
rdel2.Offset(1, 0).EntireRow.Delete
End If
Next
End Sub

rdel2 is a range and .Offset(-1,0) returns a range, just do rdel2 = rdel2.Offset(-1, 0) if you want to change rdel2.
Although, in your case, the For Each loop will update rdel2 so this line will be useless (unless you are not showing all your code and there is actually more between the problematic line and the Next rdel2 statement)

Related

How do I find out why I get an error when writing to an Excel cell with VBA?

I'm still fairly new to VBA and struggling with its limitations (and mine!). Here's my code:
Sub updateCache(CacheKey As String, CacheValue As Variant)
Dim DataCacheWorksheet As Worksheet, CacheRange As Range, Found As Variant, RowNum As Integer
Set DataCacheWorksheet = ThisWorkbook.Worksheets("DataCache")
Set CacheRange = DataCacheWorksheet.Range("A1:B999")
Set Found = CacheRange.Find(What:=CacheKey)
If Found Is Nothing Then
RowNum = CacheRange.Cells(Rows.Count, 2).End(xlUp).Row
DataCache.Add CacheKey, CacheValue
On Error Resume Next
DataCacheWorksheet.Cells(1, 1).Value = CacheKey
DataCacheWorksheet.Cells(1, 2).Value = CacheValue
Else
'Do other things
End If
End Sub
When I step through the code, Excel simply exits the sub at the line DataCacheWorksheet.Cells(1, 1).Value = CacheKey, with no error. So, two questions:
What's the bug that's preventing the value from being updated?
Why does Excel ignore my On Error command?
Edit: If I run the line in the IDE's "Immediate" box, I get the error "Run-time error '1004' Application-defined or object-defined error. I get the same error regardless of the value of CacheKey (I tried Empty, 1234 and "Hello").
Edit 2: If I modify the sub so that CacheKey and CacheValue are hardcoded and the reference to DataCache is removed, and then I run the sub standalone it works. So why doesn't it work when called from another function? Is it possible that Excel is locking cells while doing calculations?
Not sure if this applies, but you mentioned you were calling this macro from another function. If you are calling it from a function, depending on how you are calling it, that would explain your problem. For example, a worksheet function entered into a cell cannot modify another cell on the worksheet. And the attempt to do so will result in the macro merely exiting at that point, without throwing a VBA error.
How to work around this depends on specifics you have yet to share. Sometimes, worksheet event code can be useful.
Ok, wasn't about to write an answer, but there are 3 things you should modify in your code:
Found As Range and not As Variant
RowNum As Long in case it's a row after ~32K
To trap errors usually On Error Resume Next won't help you, it will just jump one line of code. You need to handle the error situation.
Modified Code
Sub updateCache(CacheKey As String, CacheValue As Variant)
Dim DataCacheWorksheet As Worksheet, CacheRange As Range, Found As Range, RowNum As Long ' < use Long instead of Integer
Set DataCacheWorksheet = ThisWorkbook.Worksheets("DataCache")
Set CacheRange = DataCacheWorksheet.Range("A1:B999")
Set Found = CacheRange.Find(What:=CacheKey)
If Found Is Nothing Then ' check if not found in cache (*Edit 1)
RowNum = CacheRange.Cells(Rows.Count, 2).End(xlUp).Row
DataCache.Add CacheKey, CacheValue ' I assume you have a `Dictionary somewhere
' On Error Resume Next <-- Remove this, not recommended to use
DataCacheWorksheet.Cells(1, 1).Value = CacheKey
DataCacheWorksheet.Cells(1, 2).Value = CacheValue
Else
'Do other things
End If
End Sub

VBA code to select sells on the basis of values in them

I am trying to write a small piece of code that selects all cells containing "D" in the range A1:J10. Sorry if the code below is sub-optimal for the purpose, but I am trying to use this as a means of learning the language. There seems to be no obvious error in the code (to me), but it says 'Invalid procedure call or argument' when I try to run it.
Option Explicit
Dim t As Range
Dim finalrange As Range
Sub selectallbattleships()
For Each t In Range("A1:J10")
If t.Value = "D" Then Set finalrange = Application.Union(finalrange, t)
Next t
finalrange.Select
End Sub
You have to give finalrange an initial Range, otherwise it starts off as Nothing. The code is failing at Application.Union(finalrange, t) because it's trying to Union Nothing.
There are a couple of issues here.
First your Dim statements should be inside the sub. Next, you cannot union nothing, so you need to check if finalrange has been assigned to anything yet, then decide how to treat it - in this case if it hasn't then just assign it to t, otherwise union. Lastly, you do not need 'Application.' before union.
Sub selectallbattleships()
Dim t As Range
Dim finalrange As Range
For Each t In Range("A1:J10")
If t.Value = "D" Then
If finalrange Is Nothing Then
Set finalrange = t
Else
Set finalrange = Union(finalrange, t)
End If
End If
Next t
finalrange.Select
End Sub

Error 1004: Unable to Get CountIf Property

I'm trying to search a range of named cells to see if there are any cells that contain a number greater than zero. Here is the code I currently have:
Dim YTDclauses As Boolean
Dim ytdrng As Range
Set ytdrng = Worksheets("Sheet1").Range("z1AY:z1BB,z1BG:z1BJ")
'Employer 1
If Sheet1.[z1AG] = "No" And WorksheetFunction.CountIf(ytdrng, ">0") = 0 Then
MsgBox "Works!"
Else
MsgBox "Does Not Work"
End If
I'm getting an error back as "Run-time error '1004': Unable to get the CountIfs property of the WorksheetFunction class". By looking at other questions, I think it might be a syntax error with how I'm setting ytdrng, but I've tried many ways of naming it differently to no avail. Any help is appreciated, thank you!
Note: Sheet1 is named "Main Checklist" - I also tried using that in the setting of ytdrng, but got the same error.
As #ScottCraner has stated, you cannot do a countif on a split range. You can modify the routine slightly to implement a countif by looping over each cell in the range:
Dim YTDclauses As Boolean
Dim ytdrng As Range
Dim SRCountif As Long
Dim cel As Object
Set ytdrng = Worksheets("Sheet1").Range("z1AY:z1BB,z1BG:z1BJ")
SRCountif = 0
For Each cel In ytdrng.Cells
If cel.Value > 0 Then SRCountif = SRCountif + 1
Next
'Employer 1
If Sheet1.[z1AG] = "No" And SRCountif = 0 Then
MsgBox "Works!"
Else
MsgBox "Does Not Work"
End If
(The variable SRCountif is meant to mean SplitRangeCountif)
Note that as it is comparing the value to numeric 0, Exec takes any text as greater than 0, so you may want to adjust the test if there is a chance of any text in your range.

VBA Return message if cell(s) in range are blank

i am trying to return a message if any cells in a given range are blank. If i declare the range i.e.
Set OrderRng = [C1: C41]
it works fine, but if i declare it as such;
Set OrderRng = Range("c1:" & ActiveSheet.Range("c65536"). End(xlUp).Address).Select`
It does not work.
I know the second argument range is declared correctly as it always highlights the correct cells.
My entire code looks like this;
> Sub BlankCell() Dim OrderRng As Range On Error Resume Next
>
> Set OrderRng = Range("c1:" & ActiveSheet.Range("c65536").End(xlUp).Address).Select
>
> ' Set OrderRng = [C1: C41] ' Rm'd for testing
>
> Set OrderRng = OrderRng.SpecialCells(xlCellTypeBlanks)
>
> If Err = 0 Then MsgBox "An Order ID is missing on one of your entries,
> please amend then try again" End If End Sub
What am i doing wrong, i know it will be obvious, but not to me.
Many thanks
To fix, just remove the .select from the end of your range variable set line:
Set OrderRng = Range("c1:" & ActiveSheet.Range("c65536").End(xlUp).Address)
The .select method returns a TRUE or FALSE value, so you end up with a type mismatch trying to Set OrderRng to TRUE, which is a boolean, not a range.
Also there's 100% no reason to select here and your code should continue on fine.

List Box shows dates that aren't in the range

I'm having trouble with my Listbox. When I run the following code for the first time, it always runs showing only 1 date which is 30/12/1899. The range that I've specified only contains 6 dates which are 8/1/2014, 9/1/2014, 14/1/2014, 24/1/2014, 24/1/2014 and 02/02/2014.
Once I stop the form and run it again, all the required dates show up.
I've just started learning VBA on Excel so I'm still struggling to understand the concepts.
Is there something that I'm missing? The reason for no duplicates is that I can't show the 2 dates (24/01/2014).
Private Sub UserForm_Activate()
Dim AllCells As Range, Cell As Range
Dim NoDupes As New Collection
Dim i As Integer, j As Integer
Dim Swap1, Swap2, Item
Dim wksJobDetail As Worksheet
'The items are in A2:A7
Set AllCells = Range("A2:A7")
'Point the variable to JobSchedule worksheet
Set wksJobDetail = Application.Workbooks("xxxxx.xlsm").Worksheets("JobSchedule")
wksJobDetail.Activate
'Statement ignores any errors regarding duplicates and duplicate dates aren't added
On Error Resume Next
For Each Cell In AllCells
NoDupes.Add Format(CDate(Cell.Value), "dd/mm/yyyy"), _
CStr(Format(CDate(Cell.Value), "dd/mm/yyyy"))
Next Cell
'Add non-duplicated items into lstDate
For Each Item In NoDupes
JobDetail.lstDate.AddItem Item
Next Item
End Sub
Set AllCells = Range("A2:A7") will reference the active worksheet which may or may not be wksJobDetail.
The second time you run it wksJobDetail has been activated.
Try putting the Set AllCells = Range("A2:A7") statement after:
Set wksJobDetail = Application.Workbooks("xxxxx.xlsm").Worksheets("JobSchedule")
wksJobDetail.Activate
I think it has something to do with how you format your data in Excel and the proper way of referencing source range.
Try this:
First, check if the dates are correctly entered as dates in Excel like below.
Then make this line explicit:
Set AllCells = Range("A2:A7")
and change to this:
Set AllCells = Sheets("JobSchedule").Range("A2:A7")
Now, run your code which I've rewritten below adding On Error Goto 0.
Dim AllCells As Range, Cell As Range, Item
Dim NoDupes As New Collection
Set AllCells = Sheets("JobSchedule").Range("A2:A7")
On Error Resume Next '~~> Ignore Error starting here
For Each Cell In AllCells
NoDupes.Add Format(CDate(Cell.Value), "dd/mm/yyyy"), _
CStr(Format(CDate(Cell.Value), "dd/mm/yyyy"))
Next Cell
On Error GoTo 0 '~~> Stops ignoring error
For Each Item In NoDupes
JobDetail.lstDate.AddItem Item
Next Item
And that should give you the result you want. Also, I suggest to use Initialize Event instead of Activate.
Everytime you use OERN, do not forget to use OEG0 to reset the error handling.
Otherwise, you will not be able to trap other errors not related to the adding existing item in Collection.
Bonus:
Another way to do this is to use a Dictionary instead. You need to add reference to Microsoft Scripting Runtime. I rewrote part of your code which will have the same effect. The advantage of a Dictionary is that it offers other helpful properties that you can use.
Private Sub UserForm_Initialize()
Dim AllCells As Range, Cell As Range
Dim d As Dictionary
Set AllCells = Sheets("Sheet1").Range("A2:A7")
Set d = New Dictionary
For Each Cell In AllCells
d.Item(Format(CDate(Cell.Value), "dd/mm/yyyy")) = _
CStr(Format(CDate(Cell.Value), "dd/mm/yyyy"))
Next Cell
JobDetail.lstDate.List = d.Keys
End Sub
As you can see, we removed one Loop by using Keys property which is an array of all unique keys. I hope this somehow helps.