CopyPastor

Detecting plagiarism made easy.

Score: 1; Reported for: Exact paragraph match Open both answers

Possible Plagiarism

Reposted on 2023-09-19
by FaneDuru

Original Post

Original - Posted on 2023-09-02
by FaneDuru



            
Present in both answers; Present only in the new answer; Present only in the old answer;

You did not answer my clarification question...
The next adapted code/solution assumes that you will not have spaces between the categories (the ones starting and ending in *). The following code creates dynamic ranges name, able to automatically update when you delete a row, or write a new string at the end, or in an inserted row.
1. Copy the next declarations on top of a standard module (in the declarations area). Now, you will not define the whole source range, only the starting cell: ``` Option Explicit
Public Const DropDownsSourceRangeName As String = "Angle" Public Const DropDownsRangeName As String = "DropDownsRange" Public Const DropDownsSourceSheetName As String = "Angles for estimation" Public Const DropDownsSheetName As String = "Fundfakt-kateg-vinkl" Public Const DropDownsSourceRangeAddress As String = "$A$8" ' Not "$A$8:$A$1008" Public Const DropDownsRangeAddress As String = "$AC$4:$AI$18"
'declarations for the new part: Public Const DropDownsSourceSheetName2 As String = "Categories for estimation" Public Const DropDownsSourceSheetName3 As String = "Fundamentals for estimation"
Public Const DropDownsRangeName2 As String = "DropDownsRange1" Public Const DropDownsRangeName3 As String = "DropDownsRange2"
Public Const DropDownsSourceRangeName2 As String = "Angle1" Public Const DropDownsSourceRangeName3 As String = "Angle2"
Public Const DropDownsSourceRange2Address As String = "$A$8" ' Not "$A$8:$A$1008" Public Const DropDownsSourceRange3Address As String = "$A$8" ' Not "$A$8:$A$22"
Public Const DropDownsRange2Address As String = "$Q$4:$W$18" Public Const DropDownsRange3Address As String = "$A$4:$G$18"
'arrays to keep the necessary above variables in a way to allow iteration, to make the code more compact/elegant Private arrDrD(), arrSource(), arrAngle(), arrSourceSh(), arrSourceAddr(), arrDropDAddr(), arrDrDRangeAddr() ``` 2. Copy the next code inside the standard module where you placed the above declarations: ``` Sub LoadArrays() 'it loads the necessary above declared arrays, to be used in the next procedures Dim i As Long arrSourceSh = Array(DropDownsSourceSheetName, DropDownsSourceSheetName2, DropDownsSourceSheetName3) arrDrD = Array(DropDownsRangeName, DropDownsRangeName2, DropDownsRangeName3) arrAngle = Array(DropDownsSourceRangeName, DropDownsSourceRangeName2, DropDownsSourceRangeName3) arrSourceAddr = Array(DropDownsSourceRangeAddress, DropDownsSourceRange2Address, DropDownsSourceRange3Address) arrDrDRangeAddr = Array(DropDownsRangeAddress, DropDownsRange2Address, DropDownsRange3Address) End Sub
Sub AddNamedRangeAndSetDropDown(Optional boolNoSource As Boolean = False) LoadArrays 'if boolNoSource = True source names are not deleted, anymore - No need for that, they are DYNAMIC! DeleteNamedRanges boolNoSource Dim i As Long For i = 0 To UBound(arrDrD) If Not boolNoSource Then ThisWorkbook.Names.Add Name:=arrAngle(i), RefersTo:="=Offset('" & arrSourceSh(i) & _ "'!" & arrSourceAddr(i) & ",0,0,COUNTA('" & arrSourceSh(i) & "'!$A:$A)-1,1)" 'Name in source sheets End If ThisWorkbook.Names.Add Name:=arrDrD(i), RefersTo:="='" & DropDownsSheetName & "'!" & arrDrDRangeAddr(i) 'where to place the DropDown based on above source Next i SetDropDownList End Sub
Sub DeleteNamedRanges(Optional boolNoSource As Boolean = False) 'if boolNoSource = True source names are not deleted, anymore On Error GoTo ErrorHandler Dim i As Long For i = ThisWorkbook.Names.Count To 1 Step -1 Select Case ThisWorkbook.Names(i).Name Case IIf(boolNoSource, "", DropDownsSourceRangeName), DropDownsRangeName, _ IIf(boolNoSource, "", DropDownsSourceRangeName2), DropDownsRangeName2, _ IIf(boolNoSource, "", DropDownsSourceRangeName3), DropDownsRangeName3 ThisWorkbook.Names(i).Delete Case Else If InStr(ThisWorkbook.Names(i).Name, IIf(boolNoSource, "|#@$|", DropDownsSourceRangeName)) Or _ InStr(ThisWorkbook.Names(i).Name, DropDownsRangeName) Then _ If InStr(ThisWorkbook.Names(i).Name, IIf(boolNoSource, "|#@$|", DropDownsSourceRangeName2)) Or _ InStr(ThisWorkbook.Names(i).Name, DropDownsRangeName2) Then _ If InStr(ThisWorkbook.Names(i).Name, IIf(boolNoSource, "|#@$|", DropDownsSourceRangeName3)) Or _ InStr(ThisWorkbook.Names(i).Name, DropDownsRangeName3) Then _ ThisWorkbook.Names(i).Delete End Select Next i Exit Sub ErrorHandler: MsgBox "An error occurred " & Err.Description End Sub
Sub SetDropDownList() 'No need of any iteration. Validation can be add from all the range, at once! Dim rngDropDown As Range, i As Long LoadArrays For i = 0 To UBound(arrDrDRangeAddr) Set rngDropDown = Sheets(DropDownsSheetName).Range(arrDrDRangeAddr(i)) With rngDropDown.Validation .Delete 'clear existed Validation rules, if any .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _ Operator:=xlBetween, _ Formula1:="=" & arrAngle(i) 'use the named range directly .IgnoreBlank = True .InCellDropdown = True .InputTitle = vbNullString '"Select a value" .ErrorTitle = "Invalid value" .InputMessage = arrSourceSh(i) .ErrorMessage = "Select a valid value in the list." .ShowInput = True .ShowError = True End With Next i clearNotInListValues 'it clears selected values which are not in the source list, anymore End Sub

Sub clearNotInListValues() Dim ws As Worksheet, rng As Range, cel As Range, list Dim arrIntersect, A As Range, i As Long, dict As New Scripting.dictionary Const strError As String = "ErrV"
Set ws = ThisWorkbook.Sheets(DropDownsSheetName) Set rng = Union(ws.Range(DropDownsRangeAddress), _ ws.Range(DropDownsRange2Address), ws.Range(DropDownsRange3Address)) For Each A In rng.Areas 'iterate between the range areas:
list = Application.Transpose(Evaluate(A.Cells(1).Validation.Formula1).Value) 'extract the array from validation list For Each cel In A.Cells If cel.Value <> "" Then dict(cel.Value) = vbNullString 'collect all the unique strings from the Area 'except the empty strings Next cel
If dict.Count > 0 Then 'if at least a value has been found (except the empty string): 'match the dict.keys with validation list to determine the common ones (the rest are Errors) arrIntersect = Application.IfError(Application.Match(dict.Keys, list, 0), "Err") For i = 1 To UBound(arrIntersect) 'iterate between the matching array elements If arrIntersect(i) = "Err" Then 'the elements not being found in the validation list: 'Debug.Print dict.Keys(i - 1): Stop 'uncomment to visually see what will be deleted... A.Replace dict.Keys()(i - 1), "" 'delete the value from the respective Area range End If Next i dict.RemoveAll 'prepare it for the next range Area End If Next A End Sub ``` 3. Copy the next (easily) adapted code in the "Fundfakt-kateg-vinkl" code module: ``` Option Explicit
Private Sub Worksheet_Activate() AddNamedRangeAndSetDropDown True 'it recreates the validations according the the last changes in source sheets 'and clear the selection where not in the validation list, anymore End Sub
Sub Worksheet_Change(ByVal Target As Range) 'limit the event to trigger ONLY THE NECESSARY DROPDOWN RANGES: If Not Intersect(Target, Union(Me.Range(DropDownsRangeAddress), _ Me.Range(DropDownsRange2Address), Me.Range(DropDownsRange3Address))) Is Nothing Then If Target.Cells.Count > 1 Then Exit Sub If Target.Value = "" Then Exit Sub
If Left(Target.Value, 1) = "*" And Right(Target.Value, 1) = "*" Then MsgBox "You can't select a heading: '" & Target.Value + "'" & vbCr & vbCr & vbTab & "Try again. ", vbCritical Application.EnableEvents = False Application.Undo 'place back the value existing before change! Application.EnableEvents = True End If End If End Sub ``` It calls now the main function, but without recreating the Source ranges Names, because it is not necessary, anymore. They are of dynamic type and adapts by themself (using a formula).
4. Copy the next code in `ThisWorkbook` code module. It recreates **all named ranges** and validation ranges **when the workbook is opened**.
If something not clear, please do not hesitate to ask for clarifications.
Please, use the next solution:
1. Copy the code in a **standard module**: ``` Option Explicit
Public Const DropDownsSourceRangeName As String = "Angle" Public Const DropDownsRangeName As String = "DropDownsRange" Public Const DropDownsSourceSheetName As String = "Angles for estimation" Public Const DropDownsSheetName As String = "Fundfakt-kateg-vinkl" Public Const DropDownsSourceRangeAddress As String = "$A$8:$A$1008" Public Const DropDownsRangeAddress As String = "$AC$4:$AI$18"
'declarations for the new part: Public Const DropDownsSourceSheetName2 As String = "Categories for estimation" Public Const DropDownsSourceSheetName3 As String = "Fundamentals for estimation"
Public Const DropDownsRangeName2 As String = "DropDownsRange1" Public Const DropDownsRangeName3 As String = "DropDownsRange2"
Public Const DropDownsSourceRangeName2 As String = "Angle1" Public Const DropDownsSourceRangeName3 As String = "Angle2"
Public Const DropDownsSourceRange2Address As String = "$A$8:$A$1008" Public Const DropDownsSourceRange3Address As String = "$A$8:$A$22" 'source for Fundamentals...
Public Const DropDownsRange2Address As String = "$Q$4:$W$18" Public Const DropDownsRange3Address As String = "$A$4:$G$18"
Sub AddNamedRangeAndSetDropDown() DeleteNamedRanges ThisWorkbook.Names.Add Name:=DropDownsSourceRangeName, RefersTo:="='" & DropDownsSourceSheetName & "'!" & DropDownsSourceRangeAddress 'Angle for estimation ThisWorkbook.Names.Add Name:=DropDownsRangeName, RefersTo:="='" & DropDownsSheetName & "'!" & DropDownsRangeAddress 'where to place the DropDown based on above source ThisWorkbook.Names.Add Name:=DropDownsSourceRangeName2, RefersTo:="='" & DropDownsSourceSheetName2 & "'!" & DropDownsSourceRange2Address 'Categories for estimation ThisWorkbook.Names.Add Name:=DropDownsRangeName2, RefersTo:="='" & DropDownsSheetName & "'!" & DropDownsRange2Address 'where to place the DropDown based on above source ThisWorkbook.Names.Add Name:=DropDownsSourceRangeName3, RefersTo:="='" & DropDownsSourceSheetName3 & "'!" & DropDownsSourceRange3Address 'Fundamentals for estimation ThisWorkbook.Names.Add Name:=DropDownsRangeName3, RefersTo:="='" & DropDownsSheetName & "'!" & DropDownsRange3Address 'where to place the DropDown based on above source
SetDropDownList End Sub
Sub DeleteNamedRanges() On Error GoTo ErrorHandler Dim i As Long For i = ThisWorkbook.Names.Count To 1 Step -1 Select Case ThisWorkbook.Names(i).Name Case DropDownsSourceRangeName, DropDownsRangeName, DropDownsSourceRangeName2, DropDownsRangeName2, DropDownsSourceRangeName3, DropDownsRangeName3 ThisWorkbook.Names(i).Delete Case Else If InStr(ThisWorkbook.Names(i).Name, DropDownsSourceRangeName) Or _ InStr(ThisWorkbook.Names(i).Name, DropDownsRangeName) Then _ If InStr(ThisWorkbook.Names(i).Name, DropDownsSourceRangeName2) Or _ InStr(ThisWorkbook.Names(i).Name, DropDownsRangeName2) Then _ If InStr(ThisWorkbook.Names(i).Name, DropDownsSourceRangeName3) Or _ InStr(ThisWorkbook.Names(i).Name, DropDownsRangeName3) Then _ ThisWorkbook.Names(i).Delete End Select Next i Exit Sub ErrorHandler: MsgBox "An error occurred " & Err.Description End Sub
Sub SetDropDownList() 'No need of any iteration. Validation can be add from all the range, at once! Dim rngDropDown As Range, arrDrD(), arrSource(), arrAngle(), i As Long arrDrD = Array(DropDownsRangeName, DropDownsRangeName2, DropDownsRangeName3) arrSource = Array(DropDownsSourceRangeName, DropDownsSourceRangeName2, DropDownsSourceRangeName3) arrAngle = Array("Angle", "Angle1", "Angle2") For i = 0 To UBound(arrDrD) Set rngDropDown = Sheets(DropDownsSheetName).Range(arrDrD(i)) With rngDropDown.Validation .Delete 'clear existd Validation rules, if any .Add Type:=xlValidateList, AlertStyle:=xlValidAlertStop, _ Operator:=xlBetween, _ Formula1:=getFormula1(CStr(arrSource(i))) .IgnoreBlank = True .InCellDropdown = True .InputTitle = vbNullString '"Select a value" .ErrorTitle = "Invalid value" .InputMessage = arrAngle(i) .ErrorMessage = "Select a valid value in the list." .ShowInput = True .ShowError = True End With Next i End Sub
Function getFormula1(drDownSourceName As String) As String Const strStrange As String = "|#$%^" Dim rng As Range, arr, arr1 Set rng = Range(drDownSourceName) 'set the range where from to extract the list (without blanck cells) arr1 = rng.Value 'place the range in an array to finally drop its content back rng.Replace "", strStrange, xlWhole 'replace the empty cells with strStrange arr = Application.WorksheetFunction.Transpose(rng) 'place the range in a 1D array arr = Filter(arr, strStrange, False) 'replace the former empty cells (strStrange array elements) getFormula1 = Join(arr, ",") rng.Value = arr1 'place back the original range content End Function ``` a. It validates **without iteration between each ranges cell**, not being necessary. b. `getFormula1` takes a parameter and it also **do not use iteration**.
2. Please, copy the next code event in sheet "Fundfakt-kateg-vinkl" code module: ``` Option Explicit
Private Sub Worksheet_Activate() AddNamedRangeAndSetDropDown 'it recreates the validations according the the last changes in source sheets (when this sheet is activated) End Sub
Sub Worksheet_Change(ByVal Target As Range) 'limit the event to trigger ONLY THE NECESSARY DROPDOWN RANGES: If Not Intersect(Target, Union(Me.Range(DropDownsRangeAddress), _ Me.Range(DropDownsRange2Address), Me.Range(DropDownsRange3Address))) Is Nothing Then If Target.Cells.Count > 1 Then Exit Sub If Target.Value = "" Then Exit Sub
If Left(Target.Value, 1) = "*" And Right(Target.Value, 1) = "*" Then MsgBox "You can't select a heading: '" & Target.Value + "'" & vbCr & vbCr & vbTab & "Try again. ", vbCritical Application.EnableEvents = False 'Target.Value = "" Application.Undo 'place back the value existing before change! Application.EnableEvents = True End If End If End Sub ``` The code is not triggered by changing a cell **not intersecting with the three ranges which the above code processes**.
It also does need `BeforeCellChange` function. It searches inside the validation list, not in the range where it came from. It is enough to have the headers with "*" character as first and last character.
Please, send some feedback after testing it. I will send back the test working workbook, in a comment.




        
Present in both answers; Present only in the new answer; Present only in the old answer;