Запустить реакцию после изменения textOutput () в блестящем - PullRequest
2 голосов
/ 10 октября 2019

Я пытаюсь использовать пакет JohnCoene / marker для выделения фрагментов текста в блестящем приложении. Мое намерение состоит в том, чтобы сначала сгенерировать текст с использованием некоторой серверной логики и отобразить его с помощью textOutput. Однако я борюсь с тем, как вызвать marker после того, как текст появился на сайте . Положить его в тот же observeEvent() не работает.

Вот мой представитель

# remotes::install_github("johncoene/marker")
library(shiny)
library(marker)

ui <- fluidPage(
  use_marker(),
  actionButton("click", "click"),
  textOutput("text_to_mark")
)
server <- function(input, output) {
   observeEvent(input$click, 
                {
                  output$text <- renderText("My house is yellow")
                })
  # observeEvent() below does not work. This is just for illustration
  observeEvent(input$text_to_mark,
               {
                 marker <- marker$new("#text_to_mark.shiny-text-output.shiny-bound-output")
                 marker$
                   unmark()$ # unmark all before we mark
                   mark("My house")
               })
}

# Run the application 
shinyApp(ui = ui, server = server)

Создан в 2019-10-10 пакетом представить (v0.3.0)

Для иллюстрации: я могу заставить маркер работать, добавив вторую кнопку, как показано в коде ниже, но я ищу решение, где оно срабатывает при появлении текста.

# remotes::install_github("johncoene/marker")
library(shiny)
library(marker)

ui <- fluidPage(
  use_marker(),
  actionButton("click", "click"),
  textOutput("text_to_mark"),
  actionButton("mark", "Mark!")
)

server <- function(input, output) {
  observeEvent(input$click, 
               {
                 output$text_to_mark <- renderText("My house is yellow")
               })
  observeEvent(input$mark,
               {
                 marker <- marker$new("#text_to_mark.shiny-text-output.shiny-bound-output")
                 marker$
                   unmark()$ # unmark all before we mark
                   mark("My house")
               })
}

# Run the application 
shinyApp(ui = ui, server = server)

Создано в 2019-10-10 пакетом представ. (v0.3.0)

Ответы [ 2 ]

1 голос
/ 13 октября 2019

Прослушивание изменений DOM - это один из вариантов, но ваш подход уже показывает, что существует чистое блестящее (не настраиваемое JS) решение, оно занимает всего один клик больше, поэтому вопрос заключается в том, как сделать это одним щелчком мыши. ,Я предлагаю использовать invalidateLater и обернуть его в оператор if, чтобы предотвратить его многократное повторение, как видно здесь .

Хитрость заключается в том, чтобыЗапустите вызовы вашего маркера в операторе observe. Включите сюда invalidateLater и оберните его в условие if со счетчиком, который подсчитывает, сколько раз выполнялся оператор. Поиграйте с количеством миллисекунд и отсчетов, в моем случае это нормально работает с if(isolate(val$cnt) < 1) и invalidateLater(1000). Не забудьте обернуть ваш счетчик в isolate, иначе он застрянет в цикле.

Обратите внимание, что input$click не только записывает текст в реактивное значение, но также сбрасывает счетчик val$cntна 0, чтобы вы могли снова использовать invalidateLater для нового текста. Эта же процедура поможет вам, если вы хотите обновить свой текст, используя наблюдаемое событие или подобное. Просто не забудьте также сбросить счетчик до 0, и подсветка будет работать с новой текстовой частью.

# remotes::install_github("johncoene/marker")
library(shiny)
library(marker)

ui <- fluidPage(
  use_marker(),
  actionButton("click", "click"),
  textOutput("text_to_mark")
)

server <- function(input, output) {

  val <- reactiveValues(cnt = 0,
                        text = NULL)

  observeEvent(input$click, {
    val$text <- "My house is yellow"
    val$cnt <- 0

  })


  observe({
    if(isolate(val$cnt) < 1) {
      invalidateLater(1000)
    }

    marker <- marker$new("#text_to_mark.shiny-text-output.shiny-bound-output")
    marker$
      unmark()$ # unmark all before we mark
      mark("My house")

    val$cnt = isolate(val$cnt) + 1
    })

  output$text_to_mark <-renderText({
    val$text
  })
}

# Run the application 
shinyApp(ui = ui, server = server)
1 голос
/ 13 октября 2019

Вы можете прослушивать изменения DOM с помощью javascript: Есть ли прослушиватель изменений DOM JavaScript / jQuery? .

Когда происходит изменение, вы можете проверить, есть ли у вашего целевого элемента текст:

  hasText = document.getElementById("text_to_mark").innerHTML != ""

Обратите внимание, что я предполагаю, что ваш элемент имеет идентификатор "text_to_mark".

результат, который вы можете «отправить в R» с помощью

  Shiny.onInputChange("hasText", hasText);

На стороне R вы узнаете, есть ли у элемента текст при прослушивании input$hasText.

Таким образом, вы можете добавить:

observeEvent(input$hasText,{
   ...
})

JavaScript, который вы можете добавить в свое приложение с помощью tags$script(jsCode) или использовать shinyjs.

Воспроизводимый пример:

library(shiny)
library(marker)

jsCode <- '
MutationObserver = window.MutationObserver || window.WebKitMutationObserver;

var observer = new MutationObserver(function(mutations, observer) {
  console.log(mutations, observer);
  hasText = document.getElementById("text_to_mark").innerHTML != ""
  Shiny.onInputChange("hasText", hasText);
});

observer.observe(document, {
  subtree: true,
  attributes: true
});
'

ui <- fluidPage(
  use_marker(),
  tags$script(jsCode),
  actionButton("click", "click"),
  textOutput("text_to_mark"),
  actionButton("mark", "Mark!")
)

server <- function(input, output) {

  observeEvent(input$click, {
                 output$text_to_mark <- renderText("My house is yellow")
               })
  observeEvent(input$hasText,{
                 marker <- marker$new("#text_to_mark.shiny-text-output.shiny-bound-output")
                 marker$
                   unmark()$ # unmark all before we mark
                   mark("My house")
               })
}

# Run the application 
shinyApp(ui = ui, server = server)

Обратите внимание, что это работает только при первом появлении текста. Если вы также хотите прослушать изменения текста, можно вместо этого отправить текст в R и проверить на стороне R, был ли текст обновлен. Не уверен, нужен ли он здесь.

...