jQuery 验证 R/Shiny 应用程序中的表单
jQuery validation of form in R/Shiny application
是否可以使用 jQuery validation plugin 来验证 R/Shiny 应用程序中的表单?
我想在我的应用程序中利用这个很棒的软件包
我无法在下面找到一个最小的示例来工作,而且我无法确定问题所在。
library(shiny)
library(shinydashboard)
ui <-
dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
fluidPage(
includeScript('jquery.validate.min.js'),
tags$form(id='myform',
textInput('field1','label'),
textInput('field2','label2'),
submitButton('submit')
),
tags$script('
$(document).ready(function () {
$(\'#myform\').validate({ // initialize the plugin
rules: {
field1: {
required: true,
email: true
},
field2: {
required: true,
minlength: 5
}
}
});
});
')
)
)
)
server <- function(input, output) {
# Once form is validated, do something
}
# Run the application
shinyApp(ui = ui, server = server)
我不确定它是否有效,但使用 Dean Attali 的 shinyJS 包可能会更好,特别是 extendshinyjs()。
见https://deanattali.com/shinyjs/ and https://deanattali.com/shinyjs/extend
查看 Dean 网站上的这个模板,看看您可以使用 $(document).ready()
验证部分进行的明显交换:
jscode <- "
shinyjs.init = function() {
$(document).keypress(function(e) { alert('Key pressed: ' + e.which); });
}"
shinyApp(
ui = fluidPage(
useShinyjs(),
extendShinyjs(text = jscode),
"Press any key"
),
server = function(input, output) {}
)
如果有效,请post返回此处。
这是可能的,但在 Shiny 中做起来非常痛苦。根据 jQuery 验证插件文档:
Mandated: A 'name' attribute is required for all input elements needing validation, and the plugin will not work without this. A 'name' attribute must also be unique to the form, as this is how the plugin keeps track of all input elements.
https://jqueryvalidation.org/reference/
Shiny textInput
s 没有 'name' 属性,也没有提供添加属性的简单方法。你有点不得不绕过它——要么构建你自己的 textInput,要么修改现有的。
第二种痛苦:Shiny 捕获并专门处理表单提交以使 submitButton
工作。这意味着我们不能依赖 jQuery.Validate 的内置行为来防止提交无效表单。相反,我们必须解决它,使用类似 showErrors
回调的东西来简单地在表单无效时引发一个标志。很难防止将无效表单发送到服务器,但至少您可以在对输入进行任何操作之前检查输入是否有效。
此示例展示了两种添加规则的方法:纯标记和自定义规则对象(如您的示例中所示)。我推荐标记只是为了便于使用。有关示例,请参阅 https://jqueryvalidation.org/documentation/。
library(shiny)
library(shinydashboard)
# Use a CDN for the example, but can also be sourced locally
jQueryValidateLib <- htmltools::htmlDependency(
"jquery.validate", "1.17.0",
src = c(href = "https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0"),
script = "jquery.validate.min.js"
)
# Form validity status is accessible at input$formId_valid
validatedForm <- function(formId, ..., rules = NULL, options = list()) {
options$rules <- rules
tagList(
jQueryValidateLib,
tags$form(id = formId, ...),
tags$script(HTML(sprintf("
$(function () {
var formId = '%s';
var options = %s;
options.showErrors = function(e) {
var isValid = this.numberOfInvalids() === 0;
Shiny.onInputChange(formId + '_valid', isValid);
this.defaultShowErrors();
};
$('#' + formId).validate(options);
});
", formId, toJSON(options))
))
)
}
# Like textInput but allows adding attributes to the input element through ...
validatedTextInput <- function(inputId, label, value = "", width = NULL,
placeholder = NULL, ...) {
inputContainer <- textInput(inputId, label, value = value,
width = width, placeholder = placeholder)
inputElement <- inputContainer$children[[2]]
attribs <- c(inputElement$attribs, list(name = inputId, ...))
attribs[duplicated(names(attribs), fromLast = TRUE)] <- NULL
inputElement$attribs <- attribs
inputContainer$children[[2]] <- inputElement
inputContainer
}
toJSON <- function(x, auto_unbox = TRUE, ...) {
jsonlite::toJSON(x, auto_unbox = auto_unbox)
}
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
validatedForm(
"myform",
validatedTextInput("field1", "field1", required = TRUE, type = "email"),
validatedTextInput("field2", "field2"),
submitButton("Submit"),
rules = list(field2 = list(required = TRUE, minlength = 5))
),
verbatimTextOutput("fields")
)
)
server <- function(input, output) {
output$fields <- renderPrint({
cat(
paste("field1:", input$field1),
paste("field2:", input$field2),
paste("myform_valid:", input$myform_valid),
sep = "\n"
)
})
}
shinyApp(ui = ui, server = server)
这是生成的 HTML 的样子:
<form id="myform">
<div class="form-group shiny-input-container">
<label for="field1">field1</label>
<input id="field1" class="form-control" value="" name="field1" required="TRUE" type="email"/>
</div>
<div class="form-group shiny-input-container">
<label for="field2">field2</label>
<input id="field2" type="text" class="form-control" value="" name="field2"/>
</div>
<div>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
<script>
$(function () {
var formId = 'myform';
var options = {"rules":{"field2":{"required":true,"minlength":5}}};
options.showErrors = function(e) {
var isValid = this.numberOfInvalids() === 0;
Shiny.onInputChange(formId + '_valid', isValid);
this.defaultShowErrors();
};
$('#' + formId).validate(options);
});
</script>
是否可以使用 jQuery validation plugin 来验证 R/Shiny 应用程序中的表单?
我想在我的应用程序中利用这个很棒的软件包
我无法在下面找到一个最小的示例来工作,而且我无法确定问题所在。
library(shiny)
library(shinydashboard)
ui <-
dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
fluidPage(
includeScript('jquery.validate.min.js'),
tags$form(id='myform',
textInput('field1','label'),
textInput('field2','label2'),
submitButton('submit')
),
tags$script('
$(document).ready(function () {
$(\'#myform\').validate({ // initialize the plugin
rules: {
field1: {
required: true,
email: true
},
field2: {
required: true,
minlength: 5
}
}
});
});
')
)
)
)
server <- function(input, output) {
# Once form is validated, do something
}
# Run the application
shinyApp(ui = ui, server = server)
我不确定它是否有效,但使用 Dean Attali 的 shinyJS 包可能会更好,特别是 extendshinyjs()。
见https://deanattali.com/shinyjs/ and https://deanattali.com/shinyjs/extend
查看 Dean 网站上的这个模板,看看您可以使用 $(document).ready()
验证部分进行的明显交换:
jscode <- "
shinyjs.init = function() {
$(document).keypress(function(e) { alert('Key pressed: ' + e.which); });
}"
shinyApp(
ui = fluidPage(
useShinyjs(),
extendShinyjs(text = jscode),
"Press any key"
),
server = function(input, output) {}
)
如果有效,请post返回此处。
这是可能的,但在 Shiny 中做起来非常痛苦。根据 jQuery 验证插件文档:
Mandated: A 'name' attribute is required for all input elements needing validation, and the plugin will not work without this. A 'name' attribute must also be unique to the form, as this is how the plugin keeps track of all input elements.
https://jqueryvalidation.org/reference/
Shiny textInput
s 没有 'name' 属性,也没有提供添加属性的简单方法。你有点不得不绕过它——要么构建你自己的 textInput,要么修改现有的。
第二种痛苦:Shiny 捕获并专门处理表单提交以使 submitButton
工作。这意味着我们不能依赖 jQuery.Validate 的内置行为来防止提交无效表单。相反,我们必须解决它,使用类似 showErrors
回调的东西来简单地在表单无效时引发一个标志。很难防止将无效表单发送到服务器,但至少您可以在对输入进行任何操作之前检查输入是否有效。
此示例展示了两种添加规则的方法:纯标记和自定义规则对象(如您的示例中所示)。我推荐标记只是为了便于使用。有关示例,请参阅 https://jqueryvalidation.org/documentation/。
library(shiny)
library(shinydashboard)
# Use a CDN for the example, but can also be sourced locally
jQueryValidateLib <- htmltools::htmlDependency(
"jquery.validate", "1.17.0",
src = c(href = "https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0"),
script = "jquery.validate.min.js"
)
# Form validity status is accessible at input$formId_valid
validatedForm <- function(formId, ..., rules = NULL, options = list()) {
options$rules <- rules
tagList(
jQueryValidateLib,
tags$form(id = formId, ...),
tags$script(HTML(sprintf("
$(function () {
var formId = '%s';
var options = %s;
options.showErrors = function(e) {
var isValid = this.numberOfInvalids() === 0;
Shiny.onInputChange(formId + '_valid', isValid);
this.defaultShowErrors();
};
$('#' + formId).validate(options);
});
", formId, toJSON(options))
))
)
}
# Like textInput but allows adding attributes to the input element through ...
validatedTextInput <- function(inputId, label, value = "", width = NULL,
placeholder = NULL, ...) {
inputContainer <- textInput(inputId, label, value = value,
width = width, placeholder = placeholder)
inputElement <- inputContainer$children[[2]]
attribs <- c(inputElement$attribs, list(name = inputId, ...))
attribs[duplicated(names(attribs), fromLast = TRUE)] <- NULL
inputElement$attribs <- attribs
inputContainer$children[[2]] <- inputElement
inputContainer
}
toJSON <- function(x, auto_unbox = TRUE, ...) {
jsonlite::toJSON(x, auto_unbox = auto_unbox)
}
ui <- dashboardPage(
dashboardHeader(),
dashboardSidebar(),
dashboardBody(
validatedForm(
"myform",
validatedTextInput("field1", "field1", required = TRUE, type = "email"),
validatedTextInput("field2", "field2"),
submitButton("Submit"),
rules = list(field2 = list(required = TRUE, minlength = 5))
),
verbatimTextOutput("fields")
)
)
server <- function(input, output) {
output$fields <- renderPrint({
cat(
paste("field1:", input$field1),
paste("field2:", input$field2),
paste("myform_valid:", input$myform_valid),
sep = "\n"
)
})
}
shinyApp(ui = ui, server = server)
这是生成的 HTML 的样子:
<form id="myform">
<div class="form-group shiny-input-container">
<label for="field1">field1</label>
<input id="field1" class="form-control" value="" name="field1" required="TRUE" type="email"/>
</div>
<div class="form-group shiny-input-container">
<label for="field2">field2</label>
<input id="field2" type="text" class="form-control" value="" name="field2"/>
</div>
<div>
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
<script>
$(function () {
var formId = 'myform';
var options = {"rules":{"field2":{"required":true,"minlength":5}}};
options.showErrors = function(e) {
var isValid = this.numberOfInvalids() === 0;
Shiny.onInputChange(formId + '_valid', isValid);
this.defaultShowErrors();
};
$('#' + formId).validate(options);
});
</script>