diff --git a/R/WorkbookClass.R b/R/WorkbookClass.R
index a920b5c3..253438bc 100644
--- a/R/WorkbookClass.R
+++ b/R/WorkbookClass.R
@@ -2856,6 +2856,24 @@ Workbook$methods(
values[1],
values[2]
)
+ } else if (type == "containsBlanks") {
+ cfRule <-
+ sprintf(
+ '
+ LEN(TRIM(%s))=0
+ ',
+ dxfId,
+ unlist(strsplit(sqref, split = ":"))[[1]]
+ )
+ } else if (type == "notContainsBlanks") {
+ cfRule <-
+ sprintf(
+ '
+ LEN(TRIM(%s))>0
+ ',
+ dxfId,
+ unlist(strsplit(sqref, split = ":"))[[1]]
+ )
}
worksheets[[sheet]]$conditionalFormatting <<-
diff --git a/R/conditional_formatting.R b/R/conditional_formatting.R
index e2e51a3d..2876fef6 100644
--- a/R/conditional_formatting.R
+++ b/R/conditional_formatting.R
@@ -15,7 +15,7 @@
#' @param rule The condition under which to apply the formatting. See examples.
#' @param style A style to apply to those cells that satisfy the rule. Default is createStyle(fontColour = "#9C0006", bgFill = "#FFC7CE")
#' @param type Either 'expression', 'colourScale', 'databar', 'duplicates', 'beginsWith',
-#' 'endsWith', 'topN', 'bottomN', 'contains' or 'notContains' (case insensitive).
+#' 'endsWith', 'topN', 'bottomN', 'blanks', 'notBlanks', 'contains' or 'notContains' (case insensitive).
#' @param ... See below
#' @details See Examples.
#'
@@ -61,6 +61,18 @@
#' \item{style is a Style object. See [createStyle()]}
#' \item{rule is a numeric vector of length 2 specifying lower and upper bound (Inclusive)}
#' }
+#' If type == "blanks"
+#' \itemize{
+#' \item{style is a Style object. See [createStyle()]}
+#' \item{rule is ignored.}
+#' }
+#'
+#' If type == "notBlanks"
+#' \itemize{
+#' \item{style is a Style object. See [createStyle()]}
+#' \item{rule is ignored.}
+#' }
+
#'
#' If type == "topN"
#' \itemize{
@@ -104,6 +116,8 @@
#' addWorksheet(wb, "between")
#' addWorksheet(wb, "topN")
#' addWorksheet(wb, "bottomN")
+#' addWorksheet(wb, "containsBlanks")
+#' addWorksheet(wb, "notContainsBlanks")
#' addWorksheet(wb, "logical operators")
#'
#' negStyle <- createStyle(fontColour = "#9C0006", bgFill = "#FFC7CE")
@@ -238,6 +252,18 @@
#' # Highlight bottom 20 percentage in column y
#' conditionalFormatting(wb, "bottomN", cols = 2, rows = 2:11,
#' style = negStyle, type = "topN", rank = 20, percent = TRUE)
+#'
+#' ## cells containing blanks
+#' sample_data <- sample(c("X", NA_character_), 10, replace = TRUE)
+#' writeData(wb, "containsBlanks", sample_data)
+#' conditionalFormatting(wb, "containsBlanks", cols = 1, rows = 1:10,
+#' type = "blanks", style = negStyle)
+#'
+#' ## cells not containing blanks
+#' sample_data <- sample(c("X", NA_character_), 10, replace = TRUE)
+#' writeData(wb, "notContainsBlanks", sample_data)
+#' conditionalFormatting(wb, "notContainsBlanks", cols = 1, rows = 1:10,
+#' type = "notBlanks", style = posStyle)
#'
#' ## Logical Operators
#' # You can use Excels logical Operators
@@ -320,9 +346,13 @@ conditionalFormatting <-
type <- "topN"
} else if (type == "bottomn") {
type <- "bottomN"
- } else if (type != "expression") {
+ } else if (type == "blanks") {
+ type <- "containsBlanks"
+ } else if (type == "notblanks") {
+ type <- "notContainsBlanks"
+ }else if (type != "expression") {
stop(
- "Invalid type argument. Type must be one of 'expression', 'colourScale', 'databar', 'duplicates', 'beginsWith', 'endsWith', 'contains' or 'notContains'"
+ "Invalid type argument. Type must be one of 'expression', 'colourScale', 'databar', 'duplicates', 'beginsWith', 'endsWith', 'blanks', 'notBlanks', 'contains' or 'notContains'"
)
}
@@ -629,6 +659,32 @@ conditionalFormatting <-
invisible(dxfId <- wb$addDXFS(style))
values <- params
rule <- style
+ } else if (type == "containsBlanks") {
+ # rule is ignored
+
+ if (is.null(style)) {
+ style <-
+ createStyle(fontColour = "#9C0006", bgFill = "#FFC7CE")
+ }
+
+ if (!"Style" %in% class(style)) {
+ stop("If type == 'blanks', style must be a Style object.")
+ }
+
+ invisible(dxfId <- wb$addDXFS(style))
+ } else if (type == "notContainsBlanks") {
+ # rule is ignored
+
+ if (is.null(style)) {
+ style <-
+ createStyle(fontColour = "#9C0006", bgFill = "#FFC7CE")
+ }
+
+ if (!"Style" %in% class(style)) {
+ stop("If type == 'notBlanks', style must be a Style object.")
+ }
+
+ invisible(dxfId <- wb$addDXFS(style))
}
diff --git a/man/conditionalFormatting.Rd b/man/conditionalFormatting.Rd
index 19316d05..38907a63 100644
--- a/man/conditionalFormatting.Rd
+++ b/man/conditionalFormatting.Rd
@@ -30,7 +30,7 @@ conditionalFormatting(
\item{style}{A style to apply to those cells that satisfy the rule. Default is createStyle(fontColour = "#9C0006", bgFill = "#FFC7CE")}
\item{type}{Either 'expression', 'colourScale', 'databar', 'duplicates', 'beginsWith',
-'endsWith', 'topN', 'bottomN', 'contains' or 'notContains' (case insensitive).}
+'endsWith', 'topN', 'bottomN', 'blanks', 'notBlanks', 'contains' or 'notContains' (case insensitive).}
\item{...}{See below}
}
@@ -82,6 +82,17 @@ If type == "between"
\item{style is a Style object. See \code{\link[=createStyle]{createStyle()}}}
\item{rule is a numeric vector of length 2 specifying lower and upper bound (Inclusive)}
}
+If type == "blanks"
+\itemize{
+\item{style is a Style object. See \code{\link[=createStyle]{createStyle()}}}
+\item{rule is ignored.}
+}
+
+If type == "notBlanks"
+\itemize{
+\item{style is a Style object. See \code{\link[=createStyle]{createStyle()}}}
+\item{rule is ignored.}
+}
If type == "topN"
\itemize{
@@ -123,6 +134,8 @@ addWorksheet(wb, "databar")
addWorksheet(wb, "between")
addWorksheet(wb, "topN")
addWorksheet(wb, "bottomN")
+addWorksheet(wb, "containsBlanks")
+addWorksheet(wb, "notContainsBlanks")
addWorksheet(wb, "logical operators")
negStyle <- createStyle(fontColour = "#9C0006", bgFill = "#FFC7CE")
@@ -257,6 +270,18 @@ conditionalFormatting(wb, "bottomN", cols = 1, rows = 2:11,
# Highlight bottom 20 percentage in column y
conditionalFormatting(wb, "bottomN", cols = 2, rows = 2:11,
style = negStyle, type = "topN", rank = 20, percent = TRUE)
+
+## cells containing blanks
+sample_data <- sample(c("X", NA_character_), 10, replace = TRUE)
+writeData(wb, "containsBlanks", sample_data)
+conditionalFormatting(wb, "containsBlanks", cols = 1, rows = 1:10,
+type = "blanks", style = negStyle)
+
+## cells not containing blanks
+sample_data <- sample(c("X", NA_character_), 10, replace = TRUE)
+writeData(wb, "notContainsBlanks", sample_data)
+conditionalFormatting(wb, "notContainsBlanks", cols = 1, rows = 1:10,
+type = "notBlanks", style = posStyle)
## Logical Operators
# You can use Excels logical Operators
diff --git a/tests/testthat/test-conditionalFormatting.R b/tests/testthat/test-conditionalFormatting.R
index 4efe169b..0150600b 100644
--- a/tests/testthat/test-conditionalFormatting.R
+++ b/tests/testthat/test-conditionalFormatting.R
@@ -57,3 +57,30 @@ test_that("topN/bottomN conditions correspond to 'top10' type", {
expect_true(object = grepl(paste('type="top10"'), wb$worksheets[[1]]$conditionalFormatting[5]))
expect_true(object = grepl(paste('type="top10"'), wb$worksheets[[1]]$conditionalFormatting[6]))
})
+
+
+context("Testing 'blanks' and 'notBlanks' conditions in conditionalFormatting")
+BNB_test_data <- data.frame(col1 = sample(c("X", NA_character_), 10, replace = TRUE),
+ col2 = sample(c("Y", NA_character_), 10, replace = TRUE))
+
+bg_blue <- createStyle(bgFill = "skyblue")
+bg_red <- createStyle(bgFill = "red")
+
+wb <- createWorkbook()
+sht <- "Blanks_NonBlanks_TEST"
+addWorksheet(wb, sht)
+writeData(wb, sht, BNB_test_data)
+conditionalFormatting(wb, sht, cols = 1, rows = 2:11, type = "blanks", style = bg_red)
+conditionalFormatting(wb, sht, cols = 2, rows = 2:11, type = "notBlanks", style = bg_blue)
+
+test_that("Number of conditionalFormatting rules added equal to 2", {
+ expect_equal(object = length(wb$worksheets[[1]]$conditionalFormatting), expected = 2)
+})
+
+test_that("type='blanks' calls type='containsBlanks'", {
+ expect_true(object = grepl(paste('containsBlanks'), wb$worksheets[[1]]$conditionalFormatting[1]))
+})
+
+test_that("type='notBlanks' calls type='notContainsBlanks'", {
+ expect_true(object = grepl(paste('notContainsBlanks'), wb$worksheets[[1]]$conditionalFormatting[2]))
+})