Problem dropping same file twice in a row - plotly-dash

I'm using the Dash Upload component, which in turn uses react-dropzone.
I can drag a file into the component and the corresponding callback will fire.
I can then drag a different file into the component and the callback will fire again.
But, if I drag a file into the component (which fires the callback) and then drag the same file into the component again, the callback does not fire.
There's a demo app in this Gist that demonstrates the behavior.
Searching for similar problems (stack-overflow, github) suggests that this behavior is to be expected because from the browser's point of view nothing has changed. Both of those discussions seem to end up with solutions that involve setting the .value part of some element to '', so that the browser sees the second drop event as a change.
Chriddyp contributed links to the relevant bit of code in Dash and pointed me to the react-dropzone component.
Is there a way to make dropping the file twice in a row work in Dash using react-dropzone?
Thanks!
g.

In Dash, callbacks are invoked every time a property changes. If you upload the same file a second time, the properties (e.g. the file name) are unchanged, and the callback will thus not be invoked. This is expected behavior.
To ensure that a callback is invoked every time, you must ensure that the Input property actually changes. One option would be to add a new property to the Upload component similar to the n_clicks property of buttons, say n_uploads, which is incremented each time a file is uploaded.
The easiest solution for the problem at hand would probably be to use the custom dash uploader instead. Among other things, it supports uploading the same file multiple times.

A bit late answer. I found a solution which is just reset the contents and filename to None in the Output of the callback.
A simple example
import dash
from dash import dcc, html
from dash.dependencies import Input, Output, State
app = dash.Dash(__name__)
app.layout = html.Div([
dcc.Upload(html.Button('Upload File', id='btn_id'), id='upload_id'),
html.P(id='show_id'),
])
#app.callback(
Output('show_id', 'children'),
Output('upload_id', 'contents'),
Output('upload_id', 'filename'),
Input('upload_id', 'contents'),
State('upload_id', 'filename'),
State('btn_id', 'n_clicks'),
)
def uploaded_a_file(contents, filename, n_clicks):
if not contents:
raise dash.exceptions.PreventUpdate
msg = f'Uploaded {filename} for {n_clicks} time.'
return msg, None, None
if __name__ == '__main__':
app.run_server(debug=True)

Another workaround, similar to #aura's, is to replace the upload component entirely with a callback. This strategy can be useful when replacing "contents" would lead to circular callbacks.
See https://github.com/plotly/dash-core-components/issues/816#issuecomment-1032635061

Related

Unable to watch loading state of a dbc.Container

My goal in my multi-page app is to make the page load itself a trigger for a specific page’s callback, but since I don’t think this is possible, I am attempting to watch the loading state of the page’s dbc.Container.
When I run something similar to below, per the docs, I would have expected it to print a dict with the component name and True for the loading state. Instead, it prints None.
Can anyone offer any input on how to achieve this goal? thank you
#dash.callback(
Output("update_message", "children"),
Input('main_container', 'loading_state'),
)
def func(loading_state):
print(loading_state)
def layout():
return dbc.Container([***page contents here], id='main_container', fluid=True)

DataVizExtention: issue with clearing viewables while a sprite is selected

In my code, I have this workflow:
When user wants to see some things, add Sprites using 'DataVizCore.addViewables()'
Use 'viewer.addEventListener(DataVizCore.MOUSE_CLICK, onDotClick)' to show info bubble
When user wants to show other things, call 'DataVizCore.removeAllViewables()' to clear Sprites
Repeat from step 1
This sequence works OK except in one situation.
If a sprite was selected (by clicking on it) before removeAllViewables() is called, I don't get MOUSE_CLICK event for newly added Sprites. In browser console, I see following error is thrown.
CustomViewables.js:318 Uncaught TypeError: Cannot read property 'style' of undefined at ViewableData.getViewableUV (developer.api.autodesk.com/modelderivative/v2/viewers/7.*/extensions/DataVisualization/DataVisualization.js:454)
As a workaround, I added 'event.hasStopped = true' to click event handler to prevent Sprite getting selected internally. That seems to work.
This seems like a bug in DataVizExtension to me. Or, my workflow is wrong?
Thanks
Bandu
Bandu. Thanks for the detailed steps to reproduce this issue. I tried with v7.46.0 version of the DataVisualization.js (latest as of my message) but was not seeing the same issue. I'd be curious if you are using this same version of the Forge Viewer (you can figure that out by looking at the viewer3D.js fetched under the Network tab of Chrome DevTools).
Setting event.hasStopped = true works because it internally avoided the code path calls into getViewableUV that threw the exception, but the flag is meant for other use cases (e.g. overriding default sprite selection behavior).
In any case, I've just tweaked our internal code to make use-cases like yours more robust. The changes will be released with the upcoming v7.47.0. Thank you for your feedback 🙂

Property '_popup' does not exist on type 'Marker<any>'

So, I am building a map using angular and leaflet. One of the things that I use is leaflet.markercluster. When i click on the cluster I want the popup content of a random marker of a cluster to be written somewhere. To access the popup content of some random cluster I did this:
cluster.getAllChildMarkers()[0]._popup._content
and got an error: Property '_popup' does not exist on type 'Marker'.
But the thing is, if I do ng serve first time it failes to compile, but if I change anything and save all it compiles sucessfully with the errors and I can see the content of the popup.
Also, if I do console.log(cluster.getAllChildMarkers()[0]) and I inspect element on webpage I get the regular console log of a marker with latlng andall other atributtes, including _popup.
Does anybody know why does typescript/vscode log an error, but html console sees it normally?
Because TypeScript is more strict than JavaScript, it warns you of potential issues that may actually work just fine once transpiled in JS.
In this specific case, this is simply due to the pseudo private properties ("_popup" follows the usual JS libraries convention of using an underscore _ prefix to denote pseudo private members) not being declared on the TS types of Leaflet, since you are not expected to use them.
But of course this is still technically valid in JS, so you can tell the TS compiler "I know what I am doing" by using the //#ts-ignore comment directive just above that line.
Or longer but much better, since you can remain under TS watch: use actual Leaflet API to achieve what you are doing:
getPopup() method
getContent() method
cluster.getAllChildMarkers()[0].getPopup()?.getContent()

Angular Performance: DOM Event causes unnecessary function calls

I have a simple page with an input element that has a DOM event (input). The HTML page also calls a function that just outputs something via console.log. Now when I open the page, it will show the log, but when I type something into the input field, it will also trigger the function EVERY time I type something.. (Actually, when I type a letter, it will console.logs TWICE every time)
Why does this happen? How to prevent it? I read some things about changeDetection, but is there another solution?
HTML:
{{test()}}
<input class="input-msg" [value]="textValue" (input)="textValue = $event.target.value;">
.ts:
export class TestComponent implements OnInit {
constructor() {
}
test() {
console.log('test message');
}
}
Expected Behavior:
The {{test()}} should not be called when typing something into the input field
Since you're calling a function in one of the data-binding syntaxes, whenever Angular performs Change Detection, it will call this method.
Before for a function, anything that cases is the value that it returns. And for Angular to know that the returned value has changed, Angular will have to run it.
This is the exact same issue that people have raised a several questions here:
Angular: Prevent DomSanizer from updating on DOM Events
Angular performance: ngStyle recalculates on each click on random input
Angular 7 ,Reactive Form slow response when has large data
You might want to read through these threads to understand what's going on here and how you can fix this issue.
The solution is to basically design your implementation in such a way, that it never calls a method in one of the data-binding syntaxes, i.e.
In String Interpolation - {{ methodCall() }}
In Property Binding - [propertyName]="methodCall()"
In Attribute Binding - [class.className]="methodCall()" / [style.style-name]="methodCall()"
An alternative solution is do move this code to a Child Component and configure the changeDetectionStrategy on that child component to ChangeDetectionStrategy.OnPush

Where is the uri of the new window, in create-web-view?

According to the documentation, the create-new-window signal is called when a webkit is creating a new window. I've been trying to override this to handle <a target='_blank' links in PyGTK webkit browser. In a subclass of WebView I have:
...
self.connect("create-web-view", self.newWin)
...
def newWin(view, frame, data):
print view.get_property('uri')
print frame.get_property('uri')
print data.get_property('uri')
It is called when a new-window link is clicked, but for some reason all of these objects show the same url, the terminal prints out the current page url three times. How can I find the url that is supposed to be passed to a new window?
Thanks to ptomato, I found a solution. Setting the signal to this function works:
...
self.connect("new-window-policy-decision-requested", self.newWin) #requires webkit 1.1.4
...
def newWin(self, view, frame, request, nav_action, policy_decision):
"""
Calls the default browser on external link requests.
"""
functiontoviewurl(request.get_uri())
# According to the documentation: http://webkitgtk.org/reference/webkitgtk/stable/webkitgtk-webkitwebview.html#WebKitWebView-new-window-policy-decision-requested
# call ignore on the policy decision, then return true (that is, we handled it).
policy_decision.ignore()
return True
You can't intercept the creation of a new window by catching that signal - by that time, the browser has already decided it will create a new window. Instead, connect to new-window-policy-decision-requested and get the URI from the request parameter.