0

I want to create an entirely new workbook from my existing file with a robust list.

I've managed to create a new workbook with its sheets, but I really want to generate the custom workbook name based on the other cell in the row, where my cell was selected.

enter image description here

Like you see above. In the AD column, every row has the cell with GENERATE value, which runs the macro. When I click for instance on cell AD5 I want my workbook to be saved under the name fetched from cell D5. Unfortunately, the code below:

 Private Sub Worksheet_SelectionChange(ByVal Target As Range)
 Dim answer As Integer
 Dim lrou As Long
 Dim i As Long
 Dim c As Range
 lrou = ActiveSheet.UsedRange.Rows(ActiveSheet.UsedRange.Rows.Count).Row
 If Selection.Count = 1 Then
    If Not Intersect(Target, Range("AD3:AD" & lrou)) Is Nothing Then
      For Each c In Range("AD3:AD" & lrou)
       If LCase(c.Value) <> "Complete" Then
        answer = MsgBox("Do you want to create the Pre-Survey form?", vbQuestion + vbYesNo + vbDefaultButton2, "CST Tracker")
        If answer = vbYes Then
            Call Pre_Surveyform
     Else
         Exit Sub
        End If
        End If
    Next c
    End If
    End If
 End Sub

MACRO IN MODULE 1

Sub Pre_Surveyform()

Dim wkb As Workbook
Dim rng As Range
Dim Lr As Long
Dim n As Long

Lr = Cells(Rows.Count, "B").End(xlUp).Row

Dim fwsk As Worksheet, cnws As Worksheet, orwsk As Worksheet, hosws As Worksheet

For n = 1 To Lr
Set rng = Cells(n, "D")
Next n


 Set wkb = Workbooks.Add

 With wkb

'.SaveAs "NewXcel", FileFormat:=xlOpenXMLWorkbookMacroEnabled
.SaveAs Filename:=rng, FileFormat:=xlOpenXMLWorkbookMacroEnabled
.Sheets("Sheet1").Name = "Frontsheet"
Set fwsk = .Sheets("Frontsheet")
Set cnws = .Sheets.Add(After:=.Sheets(.Sheets.Count))
With cnws
    .Name = "Client Network Plan"
End With
Set orwsk = .Sheets.Add(After:=.Sheets(.Sheets.Count))
With orwsk
    .Name = "OR Portal Image"
End With
Set hosws = .Sheets.Add(After:=.Sheets(.Sheets.Count))
With hosws
    hosws.Name = "Hospital & Welfare"
End With

End With

End Sub

I receive just the value from the last column. In other cases, I get the 1004 error.

Is there any chance to make my selection synchronized with the row, where the cell is clicked?

I found some solutions here:

https://www.exceldemy.com/select-range-based-on-cell-value-vba/

from where the following code comes.

UPDATE:

I found some nice hints here: How to use the Target parameter in a standard module?

And adjusted my macro as per both this hint and the answer below:

Dim wkb As Workbook

Dim Lr As Long
Dim n As Long

Dim Saverng As Range

Lr = Cells(Rows.Count, "B").End(xlUp).Row

Dim cstws As Worksheet, cpws As Worksheet
Dim fwsk As Worksheet, cnws As Worksheet, orwsk As Worksheet, hosws As 
Worksheet
Dim shp As Shape
Dim Target As Range

Dim SelectedRow As Integer

Set Target = ActiveCell

SelectedRow = Target.Row

Set cstws = ThisWorkbook.Sheets("CST Tracker")
Set cpws = ThisWorkbook.Sheets("Control Page")
Set shp = ThisWorkbook.Sheets("Control Page").Shapes("Se")


Saverng = cstws.Range("K" & SelectedRow).Value

 MsgBox Target.Address & vbNewLine & Target.Row & vbNewLine & Target.Column & vbNewLine & Saverng

At the following line: Saverng = cstws.Range("K" & SelectedRow).Value

I keep getting Object variable or With block variable not set

Where is the problem now?

Geographos
  • 827
  • 2
  • 23
  • 57
  • 1
    `Private Sub Worksheet_SelectionChange(ByVal Target As Range) If Target.Column = 56 Then 'column BD ThisWorkbook.SaveCopyAs Range("D" & Target.Row) End If End Sub ` – k1dr0ck Feb 25 '23 at 05:06
  • @k1dr0ck Helpful comment; should guide MKR into the right direction; took the liberty to integrate a hint into my answer here. – T.M. Mar 02 '23 at 19:50
  • You wrote : _When I click for instance on cell BD5 I want my excel workbook to be saved under the name fetched from cell D5_. Isn't @k1dr0ck comment the answer to what you want ? Also I'm curious at your code `If Not Intersect(Target, Range("AD3:AD" & lrou)) Is Nothing` why the intersect range is column AD not column BD ? – karma Mar 03 '23 at 15:23
  • I've changed my columns from BD to AD. – Geographos Mar 03 '23 at 15:51

4 Answers4

1

Based on what you wrote, I think this is what you are looking for: It will trigger only if a single Cell is selected between H3 and H12, you can change this on line 5 in the code. It will create the new workbook and the new worksheets and save them based on the value of column "G", can edit this as well in the code. Important to Edit fileDir to an existing directory or it will give you an error.

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    Dim wb As Workbook
    Dim ws As Worksheet
    Set wb = ThisWorkbook
    Set ws = Target.Parent
    If Intersect(Target, Range("H3:H12")) Is Nothing Then
        Exit Sub
    Else
        On Error GoTo errorExit
        If Target.CountLarge = 1 Then
            'Get Row Number
            Dim rowNumber As Long
            rowNumber = Target.Row
            'Get if not complete
            If ws.Range("B" & rowNumber).Value <> "Complete" Then
                Dim asnwer As Integer
                answer = MsgBox("Do you want to create the Pre-Survey Form?", vbQuestion + vbYesNo + vbDefaultButton2, "CST Tracker")
                If answer = vbYes Then
                    'Set Save Directory IMPORTANT TO EDIT THIS
                    Dim fileDir As String
                    fileDir = "C:\Testing"
                    'Get Desired File Name
                    Dim fileName As String
                    fileName = ws.Range("G" & rowNumber).Value
                    'Make New Workbook, Add worksheets
                    Dim newWb As Workbook
                    Set newWb = Workbooks.Add
                    'Save File with File Name from column G
                    Application.DisplayAlerts = False
                    newWb.SaveAs fileDir & Application.PathSeparator & fileName, xlOpenXMLWorkbookMacroEnabled
                    Application.DisplayAlerts = True
                    'Add Worksheets
                    Set fwsk = newWb.Sheets("Sheet1")
                    fwsk.Name = "Frontsheet"
                    Set cnws = newWb.Sheets.Add(After:=newWb.Sheets(newWb.Sheets.Count))
                    cnws.Name = "Client Network Plan"
                    Set orwsk = newWb.Sheets.Add(After:=newWb.Sheets(newWb.Sheets.Count))
                    orwsk.Name = "OR Portal Image"
                    Set hosws = newWb.Sheets.Add(After:=newWb.Sheets(newWb.Sheets.Count))
                    hosws.Name = "Hospital & Welfare"
                    'Should probably save here instead and remove the previous save
                    Application.DisplayAlerts = False
                    newWb.SaveAs fileDir & Application.PathSeparator & fileName, xlOpenXMLWorkbookMacroEnabled
                    Application.DisplayAlerts = True
                    MsgBox "Saved"
                End If
            End If
            Exit Sub
errorExit:
            Application.DisplayAlerts = True
            MsgBox "There was an error saving the file, bad directory, or the file exists and it is open"
            Err.Clear
        Else
            'Do nothing, more than 1 cell was selected
        End If
    End If
End Sub
Ricardo A
  • 1,752
  • 1
  • 10
  • 16
  • I see no reaction at all. – Geographos Mar 07 '23 at 09:18
  • This does not go on a Module, goes on the Sheet that has the table where you click the cell. – Ricardo A Mar 07 '23 at 19:52
  • Ok, so there is no possibility to call the macro from the module in this case? Shall I build everything inside of this Worksheet_SelectionChange? – Geographos Mar 08 '23 at 14:55
  • filename = ws.Range("G" & selectedRow).Value Object variable or with variable not set - this is the error I am currently receiving – Geographos Mar 08 '23 at 15:04
  • That error can only show up if `Dim ws as Worksheet` and `Set ws = Target.Parent` is not being used or improperly set/used. Did you move the code to the module? Edit: Perhaps `SelectedRow` in your code is not being updated properly, that variable is not on my code. – Ricardo A Mar 08 '23 at 20:00
  • Right, I think your answer was the most helpful. In fact, I found another solution for it, but I used bits from your code, which helped me to understand it. Thank you my friend! – Geographos Mar 09 '23 at 10:51
  • I'm glad I was able to assist. – Ricardo A Mar 09 '23 at 18:07
0

A couple of basic hints ...

When I click for instance on cell BD5 I want my excel workbook to be saved under the name fetched from cell D5.

A way to react to click events would be to use a SelectionChange event (Worksheet_SelectionChange(ByVal Target As Range) in code behind the worksheet to be clicked - c.f. comment by @k1dr0ck which might be used as base to success.

Btw Make it a habit to fully qualify all range references with their exact workbook and worksheet identification (otherwise VBA assumes the active sheet which need not be the targeted one); so don't refer only to Lr = Cells(Rows.Count, "B").End(xlUp).Row - there are numerous examples here at SO :-;

In any case I'd rethink if it's the best solution to offer an endless sequence of coloured cells to be clicked, especially if this will be users other than yourself.

I receive just the value from the last column.

Aside from the fact that the loop here isn't appropriate for determining the current table row, reconsider the logic behind your loop:

Assigning consecutive range references to the same variable in a loop in column D means that eventually your range variable rng is set only to the last cell in column D whereas all prior settings will be overwritten by the next one. - Btw I assume you mean the last cell or last row in column D, not the last column.

Good luck in finishing the code; with a reputation score of nearly 1,000 i'm sure you will succeed following my few hints.

T.M.
  • 9,436
  • 3
  • 33
  • 57
  • Maybe I wasn't precise enough. You are telling me what I already have. Honestly, the problem is to make the macro work on the same basis as the selection is made in selectionChange. Can this selectionChange be applied to the code in the module? I've updated my code already showing exactly what am I after. – Geographos Mar 03 '23 at 12:53
  • @MKR a) Would appreciate feed back to the penultimate paragraph concerning the fact that your macro overwrites each prior `rng` variable. b) Following your edit: why don't you pass the wanted workbook name directly from the event code as macro argument instead of looping? c) What do you mean by *Is there any chance to make my selection synchronized with the row, where the cell is clicked* ? – T.M. Mar 03 '23 at 21:00
  • You posted: *"When I click for instance on cell AD5 I want my workbook to be saved under the name fetched from cell D5. "* - following your event code only it seems, however that you want to save all unprocessed names in column `D`, not only a single name like e.g. D5. So I'd ask you to clarify your intention before trying to expand my answer. @MKR – T.M. Mar 04 '23 at 19:08
  • You wrote : _"Can this selectionChange be applied to the code in the module?"_ . AFAIK, you can't trigger a macro resides in regular module on the worksheet event. A way that I can think of, make a multiple condition in the worksheet selection change event sub ... for example : if the selection is within C2:C10 then call macro1 which resides in the regular module - if the selection is within K2:K10 then call macro2 which resides in the regular module. Maybe something like that. – karma Mar 05 '23 at 07:26
  • @karma Support your comment to MKR. - In the absence of current feedback, it seems unclear whether MKR is unsure in which modules both macros should reside, or is just expressing himself *"not precise enough"*. – T.M. Mar 05 '23 at 09:40
  • 1
    @T.M, I agree that is hard to fully understand on what did MKR mean. He wrote `For Each c In Range("AD3:AD" & lrou)` to check if the looped cell (as c variable) `<> "Complete"`. But in the image, it is column B which rows has "complete" value. Anyway, assume it's typo ... so actually it should be `For Each c In Range("B3:B" & lrou)` ... so, if c value <>"Complete" and the user's answer is yes create the Pre-Survey form, then it jump to `Sub Pre_Surveyform()` which resides in regular module. (continue) – karma Mar 05 '23 at 15:12
  • 1
    If I'm correct that his situation like that, the way I can think of is to put `application.enableevents=false` then add `c.activate` after `If answer = vbYes then`. So assume that there are two rows which value <>"Complete" in column B (the looped cell as c variable) and the user answer Yes two times, the wkb in Pre_Surveyform sub can be saved with name from `activecell.offset(0,2).value`. Still not sure though. Need more explanation from the OP. Thanks. – karma Mar 05 '23 at 15:28
0

I'm not sure I get the gist of this, but this may help:
(Maybe "BeforeDoubleClick" would be better):

Sub Sub1() ' setup
  Range("a1:c1") = Array("Status", "Requested By", "Generate")
  Range("a2:c2") = Array("In Progress", "Donald", "Generate")
  Columns.AutoFit
End Sub

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
  Dim lastRow&, answer&, zCell As Range
  If Selection.Count > 1 Then Exit Sub
  lastRow = ActiveSheet.UsedRange.Rows.Count
  If Intersect(Target, Range("C2:C" & lastRow)) Is Nothing Then Exit Sub
  For Each zCell In Range("A2:A" & lastRow)
    If LCase(zCell.Value) <> "complete" Then
      answer = MsgBox("Do you want to create the Pre-Survey form?", vbQuestion + vbYesNo + vbDefaultButton2, "CST Tracker")
      If answer = vbYes Then
        MsgBox "Workbook " & Cells(zCell.Row, 2) & " created"
      Else
        Exit Sub
      End If
    End If
  Next zCell
End Sub
dcromley
  • 1,373
  • 1
  • 8
  • 23
0

Here is my table, that I used, same is the second sheetused table

Here is the structure of my workbook.

enter image description here

Here is the code for class

Public WithEvents App As Application

Private Sub App_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)

    Call OnSelect(Sh, Target)

End Sub

Here is the code for module SurveyForm

Option Explicit
Dim selection As New OnClick
Dim used As Range
Dim lastRow As Integer
Dim selectedRow As Integer
Dim answer As VbMsgBoxResult


Sub init()
 Set selection.App = Application
End Sub


Sub OnSelect(ByVal Sh As Object, ByVal Target As Range)

    Set used = ActiveSheet.UsedRange
    lastRow = used.Row + used.Rows.Count - 1
    selectedRow = Target.Row
    
    If Target.Count = 1 Then
        If Not Intersect(Target, Range("D2:D" & lastRow)) Is Nothing Then
            If LCase(Range("A" & selectedRow).Value) = "completed" Then
                answer = MsgBox("Do you want to create the Pre-Survey form?", vbQuestion + vbYesNo + vbDefaultButton2, "CST Tracker")
                If answer = vbYes Then
                    'answer = vbYes = 6
                    Call Pre_Surveyform
                End If
            End If
        End If
    End If
        
    
End Sub


Sub Pre_Surveyform()

    'All the necessary arguments
    'if you have ths function in other module,
    'send the arguments like this Pre_Surveyform(lastRow,selectedRow,answer)
    'You need to modify the function arguments Sub Pre_Surveyform(lastRow,selectedRow,answer)

    MsgBox lastRow
    MsgBox selectedRow
    MsgBox answer

    'Here some code you need

End Sub

You can put the Pre_SurveyForm() anywhere, same goes for the OnSelect() sub method.

jan benes
  • 33
  • 7
  • I want to have this Pre_Surveyform workable with the cell selection. I have this macro in a separate module instead of the worksheet. – Geographos Mar 08 '23 at 12:07
  • Ahh, now I got you. Sadly, you need to have the Worksheet_SelectionChange in the worksheet that you are clinking in, but the Pre_Surveform can be really anywhere. You need to use Application events, if you want to achieve what you are describing – jan benes Mar 09 '23 at 07:25
  • Check the edit, this should be what you are looking for. – jan benes Mar 09 '23 at 13:23