Fill in blanks in excel with vba - vba

Im working with a large dataset in excel whose boundaries may change with updates.
I need an automated method to fill in all blank cells with a place holder such as 'n/a'.
Is there a quick way to do that?
Thanks

You will need to loop through cells in your range and wherever you encounter a blank, you'll need the following code
' e.g. you need to make cell A2 read #N/A, i.e. the error value
ActiveSheet.Range("A2").Value = CVErr(xlErrNA)
If you simply need to put the string "N/A" and not the equivalent of the error function =NA() do have a look at the code provided by Gary's Student.

How about:
Sub NoBlanka()
For Each r In Selection
If r.Text = "" Then
r.Value = "n/a"
End If
Next r
End Sub
Select your group of cells and run the macro.

Not 100% clear on requirements, but maybe give this a try. Should be entered into your worksheet code module, and the worksheet name where commented should be changed to whatever name you are using for your sheet.
Private Sub Worksheet_Change(ByVal Target As Range)
Static r As Range
With Worksheets("mySheet")
If .UsedRange Is Nothing Then Exit Sub
If r Is Nothing Then
Set r = .UsedRange
On Error Resume Next
r.SpecialCells(xlBlanks).Value = CVErr(xlErrNA)
On Error GoTo 0
Exit Sub
End If
On Error GoTo ERREUR
If r.Address <> .UsedRange.Address Then
On Error goto 0
Set r = .UsedRange
On Error Resume Next
r.SpecialCells(xlBlanks).Value = CVErr(xlErrNA)
On Error GoTo 0
End If
End With
ERREUR:
Set r = Nothing
End Sub

Not sure if this is what you need. I used a Macro-recorder in Excel.
Sub Macro1()
Cells.Select
Selection.SpecialCells(xlCellTypeBlanks).Select
Selection.FormulaR1C1 = "na"
End Sub

You don't even need vba to do this. You can use the special cells.
In the Home tab of the ribbon, click Find and Select (in the Editing section at the right of the ribbon) and choose Go To Special
Select Blank Cells. Then ok. This will select all your blank cells.
Now type = and your place holder. So for n/a you would simply type ='n/a

Related

Excel VBA code to select all cells with data sometimes working

I once built a VBA button to automatically lock all cells with data in them. And it was working perfectly. Now I wanted to copy that button to another worksheet. So I created another button, copy and pasted the whole VBA over, then edited the worksheet names and range. And, it's only working like 5% of the time, the rest of the time, I'm getting an "Run-Time error '1004': No cells were found." I've tried a few fixed, changing Sheets to Worksheets, or adding a ", 23" to the specialcells argument. However, nothing is working right now. When I try stepping in, it sometimes say both rng and lckrng as empty, and sometimes only show lockrng as empty and not show rng at all. Problem is this used to be a working code, and now, it still works around 5% of time. Any idea why? Thank you very much!
Private Sub CommandButton1_Click()
Dim rng As Range
Dim lockrng As Range
Sheets("Uploading Checklist (M)").Unprotect Password:="signature"
Set rng = Range("A1:M14")
'Selecting hardcoded data and formulas
Set lockrng = Union(rng.SpecialCells(xlCellTypeConstants), rng.SpecialCells(xlCellTypeFormulas))
lockrng.Locked = True
Sheets("Uploading Checklist (M)").Protect Password:="signature"
End Sub
Maybe this is too simplistic, but it seems to do what you want. The animated .gif shows it working to "lock all cells with data in them". (I made the second button just for convenience). If nothing else it might be good to start from something like this that works and modify to suit your needs.
Dim cell As Range, sh As Worksheet
Sub Button4_Click()
Set sh = Worksheets("Sheet1")
sh.Unprotect Password:="s"
For Each cell In sh.UsedRange
If cell <> "" Then cell.Locked = True Else cell.Locked = False
Next
sh.Protect Password:="s"
End Sub
Sub Button5_Click()
Set sh = Worksheets("Sheet1")
sh.Unprotect Password:="s"
End Sub
The Union you are attempting will not work if either of the parameters is Nothing (i.e. you either have no constants in the range, or you have no formulas in the range).
Prior to doing the Union, you should check the parameters aren't Nothing but, once you start changing your code to do that, it would be just as simple to do the locking in two parts - so I recommend you rewrite the code as follows:
Private Sub CommandButton1_Click()
With Sheets("Uploading Checklist (M)")
.Unprotect Password:="signature"
With .Range("A1:M14")
'Lock any constants
If Not .SpecialCells(xlCellTypeConstants) Is Nothing Then
.SpecialCells(xlCellTypeConstants).Locked = True
End If
'Lock any formulas
If Not .SpecialCells(xlCellTypeFormulas) Is Nothing Then
.SpecialCells(xlCellTypeFormulas).Locked = True
End If
End With
.Protect Password:="signature"
End With
End Sub

Nested loop does not run properly

I have a nested loop which first changes all ref cells to white font using a for loop and in a sub for loop the ref cells are deleted. The code runs but has still one or two cells with reference errors. Would need help to sort out the code so that it can remove all reference errors instead of most of it! Thank you .
Sub Delete_ref_basedontextcondition()
Dim R As Range
Dim w As Long, ref As Range
Dim refi As Range
On Error Resume Next
'Set rng = Nothing
On Error Resume Next
Set R = Application.InputBox("Select cells To be deleted", Type:=8)
Dim rng As Range
If TypeName(R) <> "Range" Then
Exit Sub
Else
R.Delete
End If
For w = 1 To Worksheets.Count
With Worksheets(w)
For Each ref In .Cells.SpecialCells(xlCellTypeFormulas, xlErrors)
If ref.Text = "#REF!" Then
ref.Font.ColorIndex = 2
For Each refi In .Cells.SpecialCells(xlCellTypeFormulas, xlErrors)
If refi.Text = "#REF!" Then
refi.Delete
End If
Next refi
End If
Next ref
End With
Next w
End Sub
I'm believe that the rogue #REF! is actually created by refi.Delete so it is missed by the loop that was defined prior to its creation. Use refi.Clear instead. You just want to remove the bad formula; you do not want to delete the cell and shift other cells around it (thereby creating new #REF! errors).
Think of it as a Pez dispenser full of #REF! errors. Every time you pop one out, another comes in to take its place. Close the lid with .Clear instead of spiralling through popping them out with .Delete.

Hiding Reference Errors using Font colour in VBA

Hi there i have this code which changes cells with reference errors to white fonts. However i could only do so for a single sheet. range. How do i change the for each loop to loop for all the worksheets in the workbook? I used this code below but it does not seem to work!
Sub Delete_ref_basedontextcondition()
Dim R As Range
'Set rng = Nothing
On Error Resume Next
Set R = Application.InputBox("Select cells To be deleted", Type:=8)
Dim rng As Range
If TypeName(R) <> "Range" Then
Exit Sub
Else
R.Delete
End If
For k = 1 To ThisWorkbook.Worksheets.Count 'runs through all worksheets
Set wks = ThisWorkbook.Worksheets(k)
For Each cell In wks
If cell.Text = "#REF!" Then
cell.Font.Color = RGB(255, 255, 255)
End If
Next
Next
End Sub
While I disagree with your method of hiding #REF! errors rather than dealing with them so that they are not #REF! errors (or deleting the formulas that are creating them, here is some standard 'loop-through-the-worksheets' code that you should be able to adapt for your purposes.
Sub bad_ref()
Dim w As Long, ref As Range
On Error Resume Next
For w = 1 To Worksheets.Count
With Worksheets(w)
For Each ref In .Cells.SpecialCells(xlCellTypeFormulas, xlErrors)
If ref.Text = "#REF!" Then
ref.Font.ColorIndex = 2
'ref.clear '<~~this clears formatting, formulas. etc from the rogue cell.
End If
Next ref
End With
Next w
End Sub
It should run through quickly enough. Rather than examine every cell on each worksheet, I've narrowed down the cells to be critiqued with the Range.SpecialCells method, looking only through the formulas that produce errors. Something like a #N/A error will be left alone.
I've left an option to actually do something with the errors as a commented line.

excel vba on cell change error

Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Range = Range("A1") Then
If Range("A1").Value <> Range("A2").Value Then
Range("C1").Value = Range("C1").Value + 1
Range("A2").Value = Range("A1").Value
End If
End If
End Sub
that's the code however when i copy paste a set off cell, let's say 2 columns and 3 rows
it produce runtime error 13 type mismatch on line
If Target.Range = Range("A1") Then
why?
i simply wants the vba to do something everytime cell A1 changes
the value of A1 itself is an excel sum formula
You get type-missmatch error, becase you're trying to compare range (containing many cells) with single cell. If you want to do something every time cell A1 changed, use this one instead:
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
On Error GoTo ErrHandler
If Not Intersect(Target, Range("A1")) Is Nothing Then
If Range("A1").Value <> Range("A2").Value Then
Range("C1").Value = Range("C1").Value + 1
Range("A2").Value = Range("A1").Value
End If
End If
ExitHere:
Application.EnableEvents = True
Exit Sub
ErrHandler:
Resume ExitHere
End Sub
also note that I'm using Application.EnableEvents = False - it's a good habbit for Worksheet_Change event to use it. It prevents code from infinity firing itself each time you change any cell in event handler code.
UPD:
Btw, the value of A1 itself is an excel sum formula - you can't track changes of formula using above approach. I covered in details how you can do it in this question: Using Worksheet_Calculate event for tracking changes of formula
Simoco's answer should work for you. Another way (the one I usually use, though only out of habit) is to compare the addresses:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address = Range("A1").Address Then
If Range("A1").Value <> Range("A2").Value Then
Range("C1").Value = Range("C1").Value + 1
Range("A2").Value = Range("A1").Value
End If
End If
End Sub
You are getting an error because Target.Range is not defined. You should either just refer to Target (a Range Object) or Target.Address (the address of the Range Object). Secondly, depending on the context, Range("A1") refers to either the cell A1 itself (a Range Object) or the value in cell A1 (a literal value). You need to carefully think what you want to compare to what.
If, as you said, you want the comparison done whenever the value in Range("A1") changes then you should follow Simoco's suggestion.

How to delete all blank rows

This code makes Excel non-responsive. Anyone know why that might be?
Sub delblank()
On Error Resume Next
ActiveSheet.UsedRange.Range("A:A").SpecialCells(xlCellTypeBlanks).EntireRow.Delete
If Err Then
MsgBox "No blank cells"
End If
End Sub
The problem is that UsedRange won't accept Range("A:A") as a property because the used range in your sheet does not contain an entire column from top to bottom of the Excel sheet, i.e. from row 1 to row 1048756.
What you want instead is to refer to the first column of UsedRange: replace Range("A:A") by Columns(1) like this:
ActiveSheet.UsedRange.Columns(1).SpecialCells(xlCellTypeBlanks).EntireRow.Delete
Now it works.
When you have a long chain of methods and properties giving you trouble like that, it's easier to break it down into its constituents in order to find the source of the error. That's what I did:
Dim r1 As Range
Dim r2 As Range
Dim r3 As Range
Dim sh As Worksheet
Set sh = ActiveSheet
Set r1 = sh.UsedRange
Set r2 = r1.Range("A:A") ' Aha, error occurs here! Wow, that was easy to find.
Set r3 = r1.SpecialCells(xlCellTypeBlanks)
r3.EntireRow.Delete
When the error is gone, it's fine to put the chain back together again to get rid of the clutter.
Also don't use On Error Resume Next unless you're absolutely certain that this is what you want, because it will just swallow errors and not tell you where they came from.
Try something like this:
Public Sub Tester()
On Error Resume Next
Columns(1).SpecialCells(xlBlanks).EntireRow.Delete
On Error GoTo 0
End Sub
Try below code
Sub delblank()
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Dim rng As Range
On Error Resume Next
Set rng = ActiveSheet.UsedRange.Range("A:A").SpecialCells(xlCellTypeBlanks)
On Error GoTo 0
If rng Is Nothing Then
MsgBox "No cells found"
Else
rng.EntireRow.Delete
End If
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
End Sub