I have created a multiselect dropdown for Cities in my sheet 1 and the postcodes associated with the dropdown is in sheet 2.
This is how my sheet 2 looks.
1.) User is allowed to select multiple cities from the dropdown. As soon as user selects the city, I want to show in one cell the selected city and the associated postcodes. For e.g. If user selects Sion and Dadar from the dropdown then just below the dropdown user should be able to see something like this.
With the help of Vlookup i am able to retrieve either one of the value and also not able to show in a single cell with equals to sign.
2.) Also I have used VBA code from the internet to have multiple select and remove. The code works fine but I want to make some changes in it. Like when user selects two cities the value gets populated in the dropdown cell separated by "comma". I want everytime the second value to go on next line but to remain in the same cell and also dynamically adjust the row height with leaving some margin from top and bottom. I am new to VBA and don't know how exactly to get it on next line.
This is how it currently looks.
But instead of above, I want it look like this
Here is the VBA code which i have used.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim xRng As Range
Dim xValue1 As String
Dim xValue2 As String
If Target.Count > 1 Then Exit Sub
On Error Resume Next
Set xRng = Me.Range("J2, K2,L2,M2,N2")
If xRng Is Nothing Then Exit Sub
Application.EnableEvents = False
If Not Application.Intersect(Target, xRng) Is Nothing Then
xValue2 = Target.Value
Application.Undo
xValue1 = Target.Value
Target.Value = xValue2
If xValue1 <> "" Then
If xValue2 <> "" Then
If InStr(1, xValue1, xValue2 & ",") > 0 Then
xValue1 = Replace(xValue1, xValue2 & ", ", "") ' If it's in the middle with comma
Target.Value = xValue1
GoTo jumpOut
End If
If InStr(1, xValue1, ", " & xValue2) > 0 Then
xValue1 = Replace(xValue1, ", " & xValue2, "") ' If it's at the end with a comma in front of it
Target.Value = xValue1
GoTo jumpOut
End If
If xValue1 = xValue2 Then ' If it is the only item in string
xValue1 = ""
Target.Value = xValue1
GoTo jumpOut
End If
Target.Value = xValue1 & ", " & xValue2
End If
jumpOut:
End If
End If
Application.EnableEvents = True
End Sub
Select Formulas » Defined Names » Name Manager
Replace the Refers to: formula with the following formula:
=OFFSET(Lookups!$A$2,0,0,COUNTA(Lookups!$A:$A)-1)
You can now go nuts with adding and removing values from the Priority list and the dropdowns will have updated values with no additional effort!
To break down the OFFSET formula usage (using List_Priority as the example):
Lookups!$A$2: start at cell $A$2 on sheet named "Lookups" which is
the first value in the list
0: stay in that same row (so still at
$A$2)
0: stay in that same column (so, again, still at $A$2)
COUNTA(Lookups$A:$A)-1: count the number of cells in column A that
have values and then subtract 1 (the heading cell: “Priority”); grab
an area that is that tall, starting with the cell currently
“selected” ($A$2)
Add the Dependent Drop Down
On the DataEntry sheet, select cell E6.
On the Ribbon, click the Data tab, then click Data Validation..
From the Allow drop-down list, choose List.
In the Source box, type an equal sign and INDIRECT function,
referring to the first data cell in the Produce Type column: ...
Click OK.
Put code on Sheet Lookup
Private Sub Worksheet_Change(ByVal Target As Range)
On Error Resume Next
If Not Intersect(Target, Range("E6")) Is Nothing And Target.Cells.Count = 1 Then
Application.EnableEvents = False
If Len(Target.Offset(1, 0)) = 0 Then ' (1,0) down direction (0,1) right
Target.Offset(1, 0) = Target ' (1,0) down direction (0,1) right
Else
Target.End(xlDown).Offset(1, 0) = Target ' (1,0) down direction (0,1) right
End If
Target.ClearContents
Application.EnableEvents = True
End If
End Sub
For
Sion = 400022
You can use Vlookup formula
=VLOOKUP(Table1[Segments];Table1[Segments];1;FALSE)&" = "&VLOOKUP(Table1[Segments];Sheet2!A2:B4;2;FALSE)
I am not getting how to do it for multiselect. This works only when user select single option from the dropdown
Another solution. Change Sheet name and ranges and try:
Option Explicit
Sub test()
Dim strCitys As String
Dim rng As Range
Dim arr As Variant, strResults As Variant, City As Variant
With ThisWorkbook.Worksheets("Sheet1")
strCitys = .Range("A1").Value
Set rng = .Range("D1:E3")
strResults = ""
If strCitys <> "" Then
If InStr(1, strCitys, ",") = 0 Then
strResults = Application.VLookup(strCitys, rng, 2, False)
If Not IsError(strResults) Then
.Range("B1").Value = strCitys & "=" & strResults
Else
.Range("B1").Value = strCitys & "=" & "Missing Code"
End If
Else
For Each City In Split(strCitys, ",")
strResults = Application.VLookup(Trim(City), rng, 2, False)
If Not IsError(strResults) Then
If .Range("B1").Value = "" Then
.Range("B1").Value = Trim(City) & "=" & strResults
Else
.Range("B1").Value = .Range("B1").Value & vbNewLine & Trim(City) & "=" & strResults
End If
Else
If .Range("B1").Value = "" Then
.Range("B1").Value = Trim(City) & "=" & "Missing Code"
Else
.Range("B1").Value = .Range("B1").Value & vbNewLine & Trim(City) & "=" & "Missing Code"
End If
End If
Next City
End If
Else
.Range("B1").Clear
MsgBox "Please select city/ies."
End If
End With
End Sub
Results:
Related
I have a document where you can move or copy a row, there is a "move" and "copy" button, both are toggle buttons
'VARIABLES
Const sSTARTROW As String = "A"
Const sENDROW As String = "O"
Const sMOVEBUTTON As String = "Move line"
Const sCOPYBUTTON As String = "Copy line"
Dim sClipboard() As String
Dim iRowNumberBackup As Integer
Private Sub MoveButton_Click()
Dim sRange As String
Dim rDataRange As Range
Select Case MoveButton.Value
'pushed
Case True
GetData ActiveCell.Row, False
'released
Case False
DropData ActiveCell.Row
End Select
End Sub
Private Sub CopyButton_Click()
Select Case CopyButton.Value
'pushed
Case True
GetData ActiveCell.Row, True
'released
Case False
DropData ActiveCell.Row
End Select
End Sub
And these are the functions.
Function GetData(iRowNumber As Integer, bCopy As Boolean)
Dim cell As Range
'set the row number were data was taken from to set back in case of emergency
iRowNumberBackup = iRowNumber
'create the range that needs to be moved
sRange = sSTARTROW & iRowNumber & ":" & sENDROW & iRowNumber
'copy value into dynamic range
Set rDataRange = Range(sRange)
'if the line is empty stop everything
If rDataRange(1, 1) = 0 Then
MsgBox ("empty line")
Exit Function
End If
'define array size depending the size of range
ReDim sClipboard(rDataRange.Columns.Count)
'put the value of range into the array
Dim i As Integer: i = 0
For Each cell In rDataRange.Cells
sClipboard(i) = cell.Value
i = i + 1
Next cell
'check if it's copy or move
Select Case bCopy
Case True
'change button description
CopyButton.Caption = sClipboard(0) & " - " & sClipboard(1) & " (" & sClipboard(2) & ")"
Case False
'remove data that was placed in the array
Range(sRange).ClearContents
'change button description
MoveButton.Caption = sClipboard(0) & " - " & sClipboard(1) & " (" & sClipboard(2) & ")"
End Select
End Function
.
Function DropData(iRowNumber As Integer)
Dim cell As Range
'create the range that needs to be moved
sRange = sSTARTROW & iRowNumber & ":" & sENDROW & iRowNumber
'set the new range
Set rDataRange = Range(sRange)
'if the line is already with data set back in previous row where it was copied & stop everything
If rDataRange(1, 1) <> 0 Then
MsgBox ("Data already in this line")
DropData (iRowNumberBackup)
Exit Function
End If
'copy value from the array into the selected range
Dim i As Integer: i = 0
For Each cell In rDataRange.Cells
cell.Value = sClipboard(i)
i = i + 1
Next cell
'empty array
Erase sClipboard
'change button description
MoveButton.Caption = sMOVEBUTTON
CopyButton.Caption = sCOPYBUTTON
End Function
I would like to avoid copying / moving empty lines, as well as not overwriting a line with data yet (or at least give a warning). See msgbox in the code.
What property can I use to change it so after the first click, the button goes back into the "released" state ? When I do just "value = false" the click event is triggered again.
If a "simple" button instead of a Active X toggle button is a solution, this solution would also be great. It's just for usability it took this toggle button.
Thanks for your input.
PS: also I would prefer to pass the button itself to the formula instead of a boolean where I have to do a check.
Meanwhile I found a (temporary?) solution, to call again the click event of the button, this way the button is back in "released" mode. Here's (for one button) the code:
Sub MoveButton_Click()
'check for avoiding endless loop
If Not bEmptyline Then
Dim sRange As String
Dim rDataRange As Range
DisableOtherButton (False)
Select Case MoveButton.Value
'clicked
Case True
GetData ActiveCell.Row, False
'released
Case False
DropData ActiveCell.Row
End Select
End If
End Sub
.
Function GetData(iRowNumber As Integer, bCopy As Boolean)
Dim cell As Range
'set the row number were data was taken from to set back in case of emergency
iRowNumberBackup = iRowNumber
'create the range that needs to be moved
sRange = sSTARTROW & iRowNumber & ":" & sENDROW & iRowNumber
'copy value into dynamic range
Set rDataRange = Range(sRange)
'if the line is empty stop everything
If rDataRange(1, 1) = 0 Then
EmptyLine (bCopy)
Exit Function
End If
'define array size depending the size of range
ReDim sClipboard(rDataRange.Columns.Count)
'put the value of range into the array
Dim i As Integer: i = 0
For Each cell In rDataRange.Cells
sClipboard(i) = cell.Value
i = i + 1
Next cell
'check if it's copy or move
Select Case bCopy
Case True
'change button description
CopyButton.Caption = sClipboard(0) & " - " & sClipboard(1) & " (" & sClipboard(2) & ")"
Case False
'remove data that was placed in the array
Range(sRange).ClearContents
'change button description
MoveButton.Caption = sClipboard(0) & " - " & sClipboard(1) & " (" & sClipboard(2) & ")"
End Select
End Function
.
Function EmptyLine(bCopy As Boolean)
whatever = MsgBox("Empty row selected.", vbInformation)
'change empty line to avoid endless loop (for every time click event)
bEmptyline = True
'recall click to set button back to standard state (not clicked but released), BETTER SOLUTION ???
Select Case bCopy
'coming from the copy button
Case True
CopyButton.Value = Not CopyButton.Value
Sheet1.CopyButton_Click
'coming from the move button
Case False
MoveButton.Value = Not MoveButton.Value
Sheet1.MoveButton_Click
End Select
'set back to false for next time
bEmptyline = False
End Function
I'd like a certain cell to show different values depending on the value of other cells. For example, in my worksheet, A1 is "Title of the film", A2 is "Duration" and A3 is "Genre". A4 should show the message "You should introduce..." and the cell that is empty. For example, if I have only completed A2, A4 should show "You should introduce Title of the film and Genre".
I have previously programmed the macro with a Worksheet_Change so that the sheet changes depending on other values.
I have developed this code so far:
Sub Macro1()
If Range("A1") = "Introduce text" And _
Range("A2") <> "Introduce text" And _
Range("A3") <> "Introduce text" Then
Range("A4") = "You should introduce Title of the film"
Else
If Range("A1") <> "Introduce text" And _
Range("A2") = "Introduce text" And _
Range("A3") <> "Introduce text" Then
Range("A4") = "You should introduce Duration"
Else
If Range("A1") = "Introduce text" And _
Range("A2") <> "Introduce text" And _
Range("A3") ="Introduce text" Then
Range("A4") = "You should introduce Title of the film and Genre"
End if
End if
End if
End Sub
However, with the Ifs, I have to make a condition with every possible combination, and this can take such a long time if I introduce more cells to fill.
Is there any other way to develop the code?
You don't need VBA here since you have a set number of cells (3). You can simply use one or more formulae. However, if you really want VBA (perhaps you want to be able to add more cells in the future) then the following code should work
Sub Macro1()
Dim vTitles As Variant
Dim i As Integer
Dim iRows As Integer
Dim sTempSeparator As String
Dim sToIntroduce As String
Dim bEventsEnabled As Boolean
vTitles = Array("Title of the film", "Duration", "Genre")
iRows = UBound(vTitles) + 1
sTempSeparator = ";" ' anything that is not part of the final text
For i = 1 To iRows
If Cells(i, 1) = "" Then
sToIntroduce = Replace(sToIntroduce, sTempSeparator, ",") & sTempSeparator & " " & vTitles(i - 1)
End If
Next i
bEventsEnabled = Application.EnableEvents
If bEventsEnabled Then Application.EnableEvents = False
With Cells(iRows + 1, 1)
If Len(sToIntroduce) <> 0 Then
sToIntroduce = Right$(sToIntroduce, Len(sToIntroduce) - 2)
sToIntroduce = Replace(sToIntroduce, sTempSeparator, " and")
sToIntroduce = "You should introduce " & sToIntroduce
If .Value <> sToIntroduce Then .Value = sToIntroduce
Else
If Len(.Value) <> 0 Then .ClearContents
End If
End With
If bEventsEnabled Then Application.EnableEvents = True
End Sub
I have encountered a few issues with some code in VBA. I am trying to have the changes made to a cells on an excel sheet show up in comments on the cell the change was made to and I wish for these changes to be stored in a list so I can view them all later. I have tried lots of different pieces of code I have found to try and implement it into the code but none have worked.
Any ideas on how to get this to work?
Worksheet
The below code is what I am currently using
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Adding As Boolean, Finding As Boolean, Subtracting As Boolean
Dim f As Range, v
Select Case Target.Address(True, True)
Case "$A$4": Adding = True
Case "$C$4": Subtracting = True
Case "$E$4": Finding = True
Case Else: Exit Sub
End Select
v = Trim(Target.Value)
If Len(v) = 0 Then Exit Sub
Set f = Me.Range("C8").Resize(1000, 1).Find(v, lookat:=xlWhole)
If Adding Then
If f Is Nothing Then
'not found: add as new row
Set f = Me.Cells(Rows.Count, 3).End(xlUp).Offset(1, 0)
f.Value = v
End If
f.Offset(0, 1).Value = f.Offset(0, 1).Value + 1
doDate f.Offset(0, 2)
Target.Value = ""
ElseIf Subtracting Then
If f Is Nothing Then
MsgBox v & " not found for subtraction!"
Else
f.Offset(0, 1).Value = f.Offset(0, 1).Value - 1
doDate f.Offset(0, 3)
Target.Value = ""
End If
Else 'finding
If Not f Is Nothing Then
f.EntireRow.Select
Target.Value = ""
Else
MsgBox v & " not found."
End If
End If
If Adding Or Subtracting Then Target.Select
End Sub
Sub doDate(c As Range)
With c
.NumberFormat = "m/d/yyyy h:mm AM/PM"
.Value = Now
End With
End Sub
I have implemented a few formulas on the worksheet but don't see any reason why it would matter in this situation since they only track quantity of items with the same unique identifier.
I also tried some code that added comments to the cells as they were changed that worked but always returned the previous cell value as blank. It is not actually added into the current code though.
Option Explicit
Public preValue As Variant
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Count > 1 Then Exit Sub
Target.ClearComments
Target.AddComment.Text Text:="Previous Value was " & preValue & Chr(10) & "Revised " & Format(Date, "mm-dd-yyyy") & Chr(10) & "By " & Environ("UserName")
End Sub
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Target.Count > 1 Then Exit Sub
If Target = "" Then
preValue = "a blank"
Else: preValue = Target.Value
End If
End Sub
By and large, the code below should do what you want. I marveled at your use of A4 and C4 to express addition and subtraction. As it is, whatever you change in those two cells, apart from clearing them, will result in a quantity of 1 being added or subtracted. I would have expected that a quantity must be entered there which is processed. If the quantity is fixed at 1 the system appears too elaborate.
Anyway, here's the code. I guess you'll be able to modify it to better suit your needs.
Private Sub Worksheet_Change(ByVal Target As Range)
' 038
Dim LookUp As Variant ' subject
Dim Action As Variant ' add = 1, subtract = -1, find = 2
Dim Fnd As Range ' Result of Find method
Dim Txt As String ' comment text
With Target
If (.Row <> 4) Or (.CountLarge > 1) Then Exit Sub
LookUp = Cells(4, "E").Value
On Error Resume Next
Action = Array(0, 1, 0, -1, 0, 2)(.Column)
End With
If Action And (LookUp <> "") Then
' C8 to end of column C
With Range(Cells(8, "C"), Cells(Rows.Count, "C").End(xlUp))
Set Fnd = .Find(LookUp, .Cells(.Cells.Count), xlValues, xlWhole, xlByRows)
End With
End If
If Fnd Is Nothing Then
Select Case Action
Case -1
MsgBox """" & LookUp & """ not found.", vbInformation, "Can't subtract"
Action = -2
Case 2
MsgBox """" & LookUp & """ not found.", vbInformation, "No record"
Action = -2
Case Else
Set Fnd = Cells(Rows.Count, "C").End(xlUp).Offset(1)
Fnd.Value = LookUp
End Select
End If
With Fnd
If Abs(Action) <> 2 Then
With .Offset(0, 1)
If .Comment Is Nothing Then
.AddComment
Else
Txt = Chr(10)
End If
Txt = "Previous Qty = " & .Value & Chr(10) & _
"Revised " & Format(Date, "mm-dd-yyyy") & Chr(10) & _
"by " & Environ("UserName") & Txt
.Comment.Text Txt, 1, False
.Value = Val(.Value) + Action
With .Offset(0, 2)
.NumberFormat = "m/d/yyyy h:mm AM/PM"
.Value = Now
End With
End With
ElseIf Action = 2 Then
.EntireRow.Select
End If
End With
If Action <> 2 Then Target.Select
End Sub
I am trying to make calculation from my dropdown menu.
This is how my dropdown looks.
Category
AAA
BBB
CCC
DDD
These are the values associated with my dropdown.
Category Category value
AAA 1
BBB 2
CCC 3
DDD 4
I added VBA code for multiple selection and also added simple Vlookup formula to retrieve the value of category.
=VLOOKUP(E2;Sheet2!I2:J5;2;)
With the VBA code, i am able to select all three category and also remove the selected category later. But I am failing to retrieve the sum of selected category. For e.g. I want if customer chooses category AAA & CCC, he/she should be able to see sum as 4. Also if customer first chooses all three category and then removes one of the category then also the sum should get updated. I am not getting how do i update my Vlookup formula to get the sum.
Here is my VBA code for multiple selection.
Private Sub Worksheet_Change(ByVal Target As Range)
'Updated: 2016/4/12
Dim xRng As Range
Dim xValue1 As String
Dim xValue2 As String
If Target.Count > 1 Then Exit Sub
On Error Resume Next
Set xRng = Cells.SpecialCells(xlCellTypeAllValidation)
If xRng Is Nothing Then Exit Sub
Application.EnableEvents = False
If Not Application.Intersect(Target, xRng) Is Nothing Then
xValue2 = Target.Value
Application.Undo
xValue1 = Target.Value
Target.Value = xValue2
If xValue1 <> "" Then
If xValue2 <> "" Then
' If xValue1 = xValue2 Or _
' InStr(1, xValue1, ", " & xValue2) Or _
InStr(1, xValue1, xValue2 & ",") Then
If InStr(1, xValue1, xValue2 & ",") > 0 Then
xValue1 = Replace(xValue1, xValue2 & ", ", "") ' If it's in the middle with comma
Target.Value = xValue1
GoTo jumpOut
End If
If InStr(1, xValue1, ", " & xValue2) > 0 Then
xValue1 = Replace(xValue1, ", " & xValue2, "") ' If it's at the end with a comma in front of it
Target.Value = xValue1
GoTo jumpOut
End If
If xValue1 = xValue2 Then ' If it is the only item in string
xValue1 = ""
Target.Value = xValue1
GoTo jumpOut
End If
Target.Value = xValue1 & ", " & xValue2
End If
jumpOut:
End If
End If
Application.EnableEvents = True
End Sub
Instead of coding in VBA, you can simply use this function and it will work.
=SUMPRODUCT(ISNUMBER(SEARCH(Sheet2!A1:I4;Sheet1!A2))*Sheet2!B1:B4)
I would do something like so for the summation part. I have my reference table A1:B4. I called using Get_Sum("A,C,D")
Function Get_Sum(strInput As String) As Double
Dim a() As String
Dim v As Variant
Dim r As Excel.Range
Dim l As Long
a = Split(strInput, ",")
Set r = Range("a1:b4")
Get_Sum = 0
For Each v In a
l = Application.WorksheetFunction.Match(v, r.Columns(1), 0)
Get_Sum = Get_Sum + r.Cells(l, 2)
Next v
Set r = Nothing
Erase a
End Function
Calling like so
Private Sub Worksheet_Change(ByVal Target As Range)
' Where A5 is the validated cell and B5 is the sum result
If Target = Range("a5") Then
Range("b5").value = Get_Sum (Target.Value)
End If
End Sub
I want to create a vba code to prevent duplicate entry that also tell me the location where it is already present. E.g. in my sheet it I type 'Jimmy' in cell D13 or anywhere in column D then a MsgBox will warn me showing "The entered Name is already exists at serial number 4."
I am trying this formula but doesn't work.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 2 And Len(Target.Value) > 0 Then
If Evaluate("Countif(D:D," & Target.Address & ")") > 1 Then
MsgBox Target.Value & " is a duplicate entry. It will be removed.", vbExclamation, "Data Entry Editor" & "(INDEX(C7:C23,MATCH(target.Value,D7:D23,0))"
Range(Target.Address).ClearContents
End If
End If
End Sub
While the answer provided by #ShaiRado is certainly correct it is missing a small piece and does not point out in which line the (dupe) name exists already. So, here is another solution which includes:
the desired feature of indicating the duplicate row and
also allows for duplicates in the middle of the list. So, if you were to change in your list the name for S. No. 2 from Mukesh to
Jimmy.
Finally, the sub has been changed to allow for editing multiple cells at once (selecting several rows and pressing del or inserting several names / rows at once).
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Dim arrList As Variant, cell As Range
Dim rowLast As Long, searchRow As Long
For Each cell In Target
If cell.Column = 4 And Trim(cell.Value2) <> vbNullString Then
rowLast = cell.Parent.Cells(cell.Parent.Rows.Count, 4).End(xlUp).Row
arrList = cell.Parent.Range("D1:D" & rowLast).Value2
For searchRow = LBound(arrList) To UBound(arrList)
If searchRow <> cell.Row Then
If arrList(UBound(arrList), 1) = arrList(searchRow, 1) Then
cell.Parent.Activate
Union(cell, cell.Parent.Range("C" & searchRow & ":F" & searchRow)).Select
MsgBox "This name exists already in row " & searchRow & _
Chr(10) & " with the S. No. " & searchRow - 6 & _
Chr(10) & Chr(10) & "This name will be now removed..."
Application.EnableEvents = False
cell.ClearContents
Application.EnableEvents = True
End If
End If
Next searchRow
End If
Next cell
End Sub
In your code you want to check for values in Column D, but in your code you are checking for If Target.Column = 2 And.. , it needs to be If Target.Column = 4.
Also, you can use the WorksheetFunction.CountIf to see if there will be duplicates in column D.
Code
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Column = 4 And Len(Target.Value) > 0 Then
Application.EnableEvents = False
If WorksheetFunction.CountIf(Range("D:D"), Target.Value) > 1 Then
MsgBox Target.Value & " is a duplicate entry. It will be removed.", vbExclamation, "Data Entry Editor" & "(INDEX(C7:C23,MATCH(Target.Value,D7:D23,0))"
Target.ClearContents
End If
Application.EnableEvents = False
End If
End Sub
excel has this functionality built into the ribbon...
use conditional formatting - to flag the duplicates
& data validation for pop-up notification
http://www.excel-easy.com/examples/prevent-duplicate-entries.html