I would like to have the Shiny app remember which tab was selected at the time of a session$reload() (refreshing the page) to clear all inputs except the value of the current tab selected in a navbarPage().
The only idea that comes to mind, though I don't know how I could implement this, would be to assign a global variable tabIndicator as the value of the current tab selected (how do you get this value?), then on refresh, rm() all variables in global environment except tabIndicator, and set selected = tabIndicator in navbarPage().
How can I accomplish this?
You have two options, both are beyond the basics of shiny.
You could use cookies. Every time a new tab is entered, send a message to javascript and set a cookie. When the app initializes, check for the presence of the cookie, and if it's set then read its value and change to the appropriate tab
Use the shinyStore package, which gives you the ability of leveraging HTML5's local storage (but this won't work on older browsers because HTML5 is relatively new)
I don't have time to provide full code right now, but hopefully this helps
It's doable, I think, but tricky. The issue is that session$reload() is equivalent to hitting the refresh button in the browser, so you're creating a new session, and losing all of the context. I guess you could use cookies somehow to do it, but I'd recommend using an actionButton that resets all of your inputs using updateWhatever, instead of actually doing the session$reload().
I was able to figure it out using a global variable.
I put this code at the top of my app (before ui and server)
# Clear global environment except 'currentTab'
rm(list=setdiff(ls(), 'currentTab'))
# If current tab exists, restore to that tab. Otherwise, start at home screen
if(!exists('currentTab')){
currentTab <- 'HOMEPAGE'
}
And this code at the bottom of my server
# Current tab
observe({
currentTab <<- input$navbar
})
Works like a charm. Thanks to all for the help.
Related
I don't understand how to make the Client ui aware of a server side change in a document.
My use case is the following : I'm adding a button to my form, that calls a custom document method :
In MyDocType.py, I have :
class MyDocType(Document):
#frappe.whitelist()
def change_some_value_in_doc(self):
self.the_field_i_want_to_change = 50
It work in the sense that the_field_i_want_to_change is immediately updated to the new value.
However, If I hit Save, I get the message "No changes in document". I managed to determine that this is because on the JS side, the form is not marked as "dirty", but despite reading the documentation over and over, I cannot find the right way.
I tried with self.notify_update() which seems to have no effect.
Is it a bug ? Or am I misunderstanding how this is supposed to work ?
I'm using frappe v 14.0.0-beta.3
[EDIT]
Actually, I realized that doing
class MyDocType(Document):
#frappe.whitelist()
def change_some_value_in_doc(self):
self.the_field_i_want_to_change = 50
self.save()
Does work in the sense that it save the new value, but it's not exactly what I'm looking for, because my purpose is actually to pre-fill some data with the custom method and leave to the user to complete before saving...
Any help to get me in the right direction would be very appreciated.
To pre-fill data in your form - that you want the user to confirm before saving to the database, you should use client-side scripting (in JS). Changing the value on the server is not going to help you since you want the user to get pre-filled values before inserting a record in the database.
Is it possible to clear the Shiny cache history when reloading an app? Specifically, I have a textInput for adding a title that doesn't clear when the app is restarted. In other words, all of the titles entered into the app on previous runs have been "remembered" and show up in a dropdown list when the app is rerun or restarted again. I have tried using shinyjs::reset, but that clears the current value and not the ones in the "history". I've also tried updateTextInput with an action button set to " ", but also clears only the current value and not the ones in the "history". I have also tried setting ui as a function using:
ui <- function(req) {
fluidPage(...)
}
as well as:
I found that cache of R Shiny server is updated when the date of creation for the file "app.R" is changed.
So, here is the trick I used:
server <- function(input, output, session) {
Trick file date creation update
onStop(function() {
# File name
p <- paste0(getwd(), "/app.R")
# Update file 'date creation'
Sys.setFileTime(p, now())
}) # onStop
} # server
The idea is to update the date of "app.R" creation after each session.
Neither of these solutions worked for me. Finally, I found this post:
I also found this post:
I have been struggling with this problem for quite a while, and thought I had tried everything, including putting a js button on the shiny sidebar to manually refresh (unfortunately that did not work either). There are two things that did work for me:
Make sure all code to read data from files is NOT in a code chunk with a name OTHER THAN global OR
Manually restart the shiny server when new data is uploaded
Obviously the first one is much more manageable, and a solution that I wish I had known weeks ago when I started playing with workarounds.
But I am not sure what is involved in implementing either, so if someone could clarify that, that would be great.
Any help would be much appreciated.
This is a follow-up for my previous question Automatically reloading shiny app when add changes.
The solution options(shiny.autoreload = TRUE) works perfect when you want to automatically see changes on the browser which you put in the code.
However, the potential problem occurs when you save unfinished/corrupted file. For example, the following ui code lacks a , sign after the titlePanel function:
fluidPage(
titlePanel("Old Faithful Geyser Datass")
sidebarLayout(...
When you save such a file, you will get an error on your browser
ERROR: Error sourcing your_path/ui.R
R console will help detect the problem with the , sign. My impression was that if I improve my code and save the file, it should reload the browser and show my app correctly. Unfortunately, it doesn't do it.
Interesting thing is that an error in the app does not terminate the connection with the browser. To confirm my word, just reload the app manually using reload button in the browser (after improving your code).
Therofore, I examined how this shiny.autoreload option works. As I expected, it checked the time of file modification and then execute reload function. Then reload function send a message via sendMessage to the addMessageHandler:
addMessageHandler('reload', function(message) {
window.location.reload();
});
So it seems that after improving your code the function should be reexecuted, but it's not gonna happen.
To summarise, I think it's not possible to change it without major changes in shiny but maybe I am wrong. Thanks for any suggestion.
PS.You can manipulate example code here to see the problem.
Tokenize2 is a javacsript lib to select multiple options.
It provides a very neat UI to start writing and then get a list of options to select from. Selected options will show up as "tags" that can be removed with "x" link.
So far all is fine. But Right now you need to know what your looking for and start write at least one character to see matching alternatives.
In my scenario there are very few alternatives and they are not known to the user. I would like to show ALL options when the user clicks the input box. There is a configuration option named searchMinLength but it is already set to 0.
Is there a workaround that can be used? Maybe like triggering load and dropdown manually?
I know there are a lot of similar alternatives but I picked Tokenize2 because:
It looks clean and nice
It works in mobile browsers
I don't know if there is an "official" approach, but after some investigation I have found an acceptable workaround.
After downloading the Tokenizer2 sourceode I found the following line that triggered my attention:
if(this.input.val().length > 0){
this.trigger('tokenize:search', [this.input.val()]);
}
My interpretation is that the internal search command is not triggered unless the user input has at least one character. This line in sourcecode could easily be modified. I have filed a suggestion for this here: https://github.com/zellerda/Tokenize2/issues/26
My current workaround is to add an event listener for the select event and there trigger the internal search command. That works fine for my scenario and does not force a source code rewrite.
$("#my-dropdown").on("tokenize:select", function (e: Event, routedEvent: boolean) {
$("#my-dropdown").trigger('tokenize:search', "");
});
Tokenize2
This link worked for me GitHub
$('.tokenize-sample-demo1').on('tokenize:select', function(container){
$(this).tokenize2().trigger('tokenize:search', [$(this).tokenize2().input.val()]);
});
Let's take a look at one of the demos.
runExample("09_upload")
I am using the supplied file to perform some computations and to display an aggregated performance across all uploaded files. Therefore, I use something like
tryCatch(compute.smth(), error=function(e){})
so that the displayed result is not affected by the bad input. However, I'd like to indicate somehow that uploading the bad file lead to an error, notifying the user about the problem with his input. It'll be something like
tryCatch(compute.smth(), error=badFile())
where badFile() should modify some displayable output. Any ideas?
As a last resort, this is probably an option, but I'd like some native Shiny.
You can show alerts like below with the ShinySky package: https://github.com/AnalytixWare/ShinySky
You can install the package using
install.packages("devtools")#if not alrady installed
devtools::install_github("ShinySky","AnalytixWare")
Place a shinyalert(id) in the ui.R for where you want the alert to appear.
In your server.R
Make sure you have a 3 parameters funciton being passed to shinyServer e.g.shinyServer(function(input, output,session) {
use showshinyalert(id,HTMLText,session) to show the alert. Clicking on the alert will dismiss it.
See this gist for example https://gist.github.com/xiaodaigh/7707701
Run this too see an example
shinysky::run.shinysky.example()