واجهة مستخدم ديناميكية باستخدام renderUI وinsertUI
ولّد عناصر واجهة المستخدم ديناميكيًا استنادًا إلى إدخال المستخدم وحالة الخادم
واجهة مستخدم ديناميكية باستخدام renderUI وinsertUI درس مجاني في R Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في R Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة R Academy 4 دروس في المجموع.
واجهة المستخدم الديناميكية — لماذا ومتى
أحيانًا لا يمكن تحديد واجهة المستخدم المطلوبة بالكامل عند بدء تشغيل التطبيق؛ إذ قد تعتمد على اختيارات المستخدم أو البيانات المحمّلة أو ظروف وقت التشغيل. يوفر Shiny آليتين: renderUI() لاستبدال المحتوى الكامل لموضع مؤقت، وinsertUI()/removeUI() لإضافة العناصر أو إزالتها دون استبدال كل شيء.
library(shiny)
# Static UI: columns always shown
# ui <- fluidPage(selectInput('x', ...), selectInput('y', ...))
# Dynamic UI: columns depend on which dataset was loaded
# ui <- fluidPage(fileInput('upload', ...), uiOutput('var_selectors'))renderUI() وuiOutput()
تنشئ renderUI({...}) الموجودة في الخادم عنصرًا من واجهة المستخدم وتُرجعه بطريقة تفاعلية. وتنشئ uiOutput('id') الموجودة في واجهة المستخدم موضعًا مؤقتًا يعرض ما تنتجه renderUI. ويُستبدل المحتوى الكامل للموضع المؤقت في كل مرة يُعاد فيها تشغيل العملية التفاعلية.
ui <- fluidPage(
selectInput('dataset', 'Dataset:', choices = c('iris', 'mtcars')),
uiOutput('column_selector') # placeholder
)
server <- function(input, output, session) {
output$column_selector <- renderUI({
df <- get(input$dataset) # reactive dependency on dataset
selectInput('col', 'Choose Column:',
choices = names(df))
})
}
shinyApp(ui, server)renderUI() مع عناصر تحكم متعددة
أرجِع tagList() من renderUI() لعرض عدة عناصر من واجهة المستخدم دفعة واحدة. وهذا هو النمط القياسي عندما يعتمد عدد عناصر التحكم على البيانات، مثل إنشاء مرشّح واحد لكل عمود في مجموعة بيانات.
server <- function(input, output, session) {
output$filters <- renderUI({
df <- get(input$dataset)
nums <- names(df)[sapply(df, is.numeric)]
# One slider per numeric column
sliders <- lapply(nums, function(col) {
rng <- range(df[[col]], na.rm = TRUE)
sliderInput(
inputId = paste0('filter_', col),
label = col,
min = rng[1], max = rng[2],
value = rng
)
})
tagList(sliders) # render all sliders
})
}insertUI() — إضافة العناصر ديناميكيًا
تُدرج insertUI(selector, where, ui) عنصرًا من واجهة المستخدم في DOM دون إعادة بناء الصفحة بأكملها. استخدم محددات CSS لاستهداف موضع الإدراج. ويمكن أن تكون قيمة where إحدى القيم 'afterEnd' أو 'beforeEnd' أو 'afterBegin' أو 'beforeBegin'.
server <- function(input, output, session) {
item_count <- reactiveVal(0)
observeEvent(input$add_item, {
item_count(item_count() + 1)
id <- paste0('item_', item_count())
insertUI(
selector = '#item_container', # CSS selector
where = 'beforeEnd',
ui = div(
id = id,
style = 'padding: 5px; border: 1px solid #ccc; margin: 3px;',
textInput(id, paste('Item', item_count()), value = '')
)
)
})
}removeUI() — حذف العناصر
تزيل removeUI(selector) أول عنصر في DOM يطابق محدد CSS. استخدم multiple = TRUE لإزالة جميع العناصر المطابقة. وهذه الدالة مكملة لـ insertUI() في واجهات المستخدم القائمة على القوائم، حيث يمكن للمستخدمين إضافة العناصر وإزالتها.
server <- function(input, output, session) {
observeEvent(input$remove_last, {
# Remove the last item div
n <- isolate(item_count())
if (n > 0) {
removeUI(selector = paste0('#item_', n))
item_count(n - 1)
}
})
observeEvent(input$clear_all, {
# Remove all items matching a class
removeUI(selector = '.dynamic-item', multiple = TRUE)
item_count(0)
})
}conditionalPanel() — التحكم في الظهور من جانب العميل
تُظهر conditionalPanel(condition, ...) عناصر واجهة المستخدم أو تخفيها استنادًا إلى شرط JavaScript يُقيَّم في المتصفح. وعلى خلاف renderUI()، تكون العناصر موجودة دائمًا في DOM، لكنها تكون ظاهرة أو مخفية فحسب. وهذا أسرع لمنطق الإظهار والإخفاء البسيط، إذ لا يتطلب ذهابًا وإيابًا إلى الخادم.
ui <- fluidPage(
selectInput('plot_type', 'Plot Type:',
choices = c('scatter', 'histogram', 'boxplot')),
# Only shown when scatter is selected
conditionalPanel(
condition = "input.plot_type == 'scatter'",
selectInput('x_var', 'X Variable:', choices = names(mtcars)),
selectInput('y_var', 'Y Variable:', choices = names(mtcars))
),
# Only shown when histogram is selected
conditionalPanel(
condition = "input.plot_type == 'histogram'",
sliderInput('bins', 'Number of bins:', 5, 50, 20)
),
plotOutput('main_plot')
)updateSelectInput() — تعديل المدخلات الموجودة
بدلًا من استبدال عنصر إدخال كامل، استخدم updateSelectInput(session, id, choices, selected) لتحديث الخيارات أو القيمة المحددة فقط في عنصر selectInput موجود. وتوجد دوال تحديث مماثلة لجميع أنواع المدخلات، مثل updateSliderInput() وupdateTextInput() وغيرهما.
server <- function(input, output, session) {
# When dataset changes, update the column selector
observeEvent(input$dataset, {
df <- get(input$dataset)
updateSelectInput(
session = session,
inputId = 'column',
choices = names(df),
selected = names(df)[1]
)
})
# Reset slider when reset button pressed
observeEvent(input$reset_btn, {
updateSliderInput(session, 'n_items',
value = 20, min = 1, max = 100)
})
}updateSliderInput() وupdateNumericInput()
ترسل دوال التحديث رسالة إلى المتصفح لتعديل القيمة الحالية أو الحد الأدنى أو الحد الأقصى أو التسمية لعنصر إدخال موجود. وهذا أكثر كفاءة من حذف عنصر التحكم وإعادة إنشائه باستخدام renderUI()، كما يحافظ على موضعه في تخطيط الصفحة.
server <- function(input, output, session) {
# When data loads, set slider max to actual data length
observeEvent(input$load_data, {
data <- readRDS(input$upload$datapath)
updateSliderInput(session, 'row_slider',
min = 1,
max = nrow(data),
value = c(1, min(50, nrow(data)))
)
updateNumericInput(session, 'page_size',
max = nrow(data),
value = min(10, nrow(data))
)
})
}الوصول إلى مدخلات renderUI باستخدام req()
تكون المدخلات التي تُنشأ ديناميكيًا باستخدام renderUI() مساوية لـ NULL حتى يتم عرضها. استخدم req(input$dynamic_input) في أي شيفرة خادم تعتمد على مدخلات أُنشئت ديناميكيًا، لمنع الأخطاء أثناء التهيئة.
server <- function(input, output, session) {
# dynamic input: 'col' is created by renderUI
output$column_selector <- renderUI({
selectInput('col', 'Column:', choices = names(get(input$dataset)))
})
output$summary_stats <- renderPrint({
req(input$col) # wait until 'col' exists
req(input$dataset) # and dataset is chosen
df <- get(input$dataset)
summary(df[[input$col]])
})
}علامات التبويب الديناميكية باستخدام appendTab()
تضيف appendTab(inputId, tab, select) علامة تبويب جديدة إلى tabsetPanel() أثناء تشغيل التطبيق. وتزيل removeTab(inputId, target) علامة تبويب واحدة. ويتيح هذا النمط سير عمل يمكن للمستخدمين فيه فتح عروض التحليل المُنشأة ديناميكيًا وإغلاقها والتنقل بينها.
ui <- fluidPage(
actionButton('add_tab', 'Open New Analysis Tab'),
tabsetPanel(id = 'analysis_tabs', type = 'tabs')
)
server <- function(input, output, session) {
tab_count <- reactiveVal(0)
observeEvent(input$add_tab, {
tab_count(tab_count() + 1)
n <- tab_count()
appendTab(
inputId = 'analysis_tabs',
select = TRUE,
tab = tabPanel(
title = paste('Analysis', n),
value = paste0('tab_', n),
plotOutput(paste0('plot_', n)),
actionButton(paste0('close_', n), 'Close')
)
)
})
}renderUI في مقابل insertUI — متى تستخدم كلًّا منهما
اختر الأداة المناسبة بناءً على حالة الاستخدام:
- renderUI(): استبدال المحتوى الكامل لموضع مؤقت بطريقة تفاعلية. وهي الأنسب عندما تتغير الكتلة بأكملها معًا.
- insertUI(): إضافة عناصر جديدة إلى محتوى موجود. وهي الأنسب للقوائم المتنامية التي لا تريد إعادة عرضها بالكامل.
- updateXxxInput(): تعديل عنصر إدخال موجود في موضعه. وهي الأنسب لتغيير الخيارات أو القيم دون إعادة العرض.
- conditionalPanel(): الإظهار أو الإخفاء دون ذهاب وإياب إلى الخادم. وهي الأنسب لمنطق الظهور البسيط.
# Decision guide:
# - 'Show filter only when advanced mode' -> conditionalPanel
# - 'Populate column choices from loaded CSV' -> updateSelectInput
# - 'Show different controls per selected tab' -> renderUI
# - 'Add a row editor for each row user adds' -> insertUI
# - 'Remove a row editor' -> removeUI
# Combining strategies:
server <- function(input, output, session) {
# Use renderUI for column selectors (replaces whole block)
output$col_selectors <- renderUI({ ... })
# Use insertUI for dynamically added rows
observeEvent(input$add_row, { insertUI(...) })
# Use conditionalPanel for show/hide (in UI, no server code)
}تحقق سريع
ما الفرق الأساسي بين renderUI() وinsertUI() عند إنشاء واجهة مستخدم ديناميكية في Shiny؟
مراجعة واجهة المستخدم الديناميكية
أهم النقاط المستخلصة من واجهة المستخدم الديناميكية باستخدام renderUI وinsertUI:
renderUI({}) + uiOutput('id'): استبدال المحتوى الكامل لموضع مؤقت بطريقة تفاعلية.- أرجِع
tagList()منrenderUI()لعرض عدة عناصر دفعة واحدة. insertUI(selector, where, ui): إدراج عناصر في أي موضع من DOM.removeUI(selector): إزالة العناصر باستخدام محدد CSS.conditionalPanel(condition, ...): إظهار العناصر أو إخفاؤها من جانب العميل دون الخادم.updateSelectInput()وupdateSliderInput(): تعديل المدخلات الموجودة في مواضعها.- استخدم دائمًا
req(input$dynamic_id)للتحقق من أن القيمة ليست NULL قبل عرض المدخلات الديناميكية.
# Typical pattern: dynamic column selector
ui <- fluidPage(
fileInput('upload', 'Upload CSV'),
uiOutput('col_ui'), # placeholder
plotOutput('col_plot')
)
server <- function(input, output, session) {
df <- reactive({
req(input$upload)
read.csv(input$upload$datapath)
})
output$col_ui <- renderUI({
req(df())
selectInput('col', 'Column:', choices = names(df()))
})
output$col_plot <- renderPlot({
req(input$col)
hist(df()[[input$col]])
})
}الأسئلة الشائعة
هل درس «واجهة مستخدم ديناميكية باستخدام renderUI وinsertUI» مجاني؟
نعم — نص درس «واجهة مستخدم ديناميكية باستخدام renderUI وinsertUI» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة R Academy، انتقل إلى CoddyKit PRO. تتضمن دورة R Academy 4 دروس في المجموع.
ماذا ستتعلم في «واجهة مستخدم ديناميكية باستخدام renderUI وinsertUI»؟
ولّد عناصر واجهة المستخدم ديناميكيًا استنادًا إلى إدخال المستخدم وحالة الخادم تتمرن على R Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ R Academy؟
لا تُشترط خبرة سابقة. R Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «واجهة مستخدم ديناميكية باستخدام renderUI وinsertUI»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس R Academy هذا؟
نعم. كل درس في R Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- تعمّق في البرمجة التفاعلية
- وحدات Shiny لإعادة استخدام التعليمات البرمجية
- واجهة مستخدم ديناميكية باستخدام renderUI وinsertUI
- نشر تطبيقات Shiny