I'm using js-interop to use the File System Access API with Dart in a web environment. I would like to store a FileSystemDirectoryHandle
in IndexedDB to reuse it later.
When storing an instance of FileSystemDirectoryHandle
in IndexedDB, the data is a Dart object (Symbol when exploring the value in DevTools). When I read back, value is not a FileSystemDirectoryHandle
and all informations of the object is lost and useless.
I did not find a way to store a handle into IndexedDB and read it back as a FileSystemDirectoryHandle
.
Below is parts of the code I declare with js-interop:
// Only to keep track of API's types definitions.
typedef Promise<T> = dynamic;
// FileSystemHandle and *Options are declared in the same way.
@JS()
class FileSystemDirectoryHandle extends FileSystemHandle {
external Promise<FileSystemFileHandle> getFileHandle(String name, [FileSystemGetFileOptions? options]);
external Promise<FileSystemDirectoryHandle> getDirectoryHandle(String name, [FileSystemGetDirectoryOptions? options]);
external Promise<void> removeEntry(String name, [FileSystemRemoveOptions? options]);
external Promise<List<String>?> resolve(FileSystemHandle possibleDescendant);
}
Here is what I'm trying to achieve:
final handle = await js.promiseToFuture(window.showDirectoryPicker());
// Storage use dart:indexed_db in a homebrew implementation (tested and works fine with
// primitive types).
await storage.set("dir", handle);
// Reload page...
// Dynamic only
final directory = await storage.get("dir");
print(directory.name);
// Typed
FileSystemDirectoryHandle dirHandle = directory as FileSystemDirectoryHandle;
print(dirHandle.name);
Calling dynamic directory.name
throws a NoSuchMethodError
:
Uncaught (in promise) Error: NoSuchMethodError: 'name'
method not found
Receiver: Instance of 'LinkedMap<dynamic, dynamic>'
Calling typed dirHandle.name
throws an Error
:
Error: Expected a value of type 'FileSystemDirectoryHandle', but got one of type 'LinkedMap<dynamic, dynamic>'
Screenshot of IndexedDB in DevTools, when storing from Dart, and storing from JavaScript
My understanding of js-interop is that it translates JavaScript object into a Dart proxy. As I'm sending a Dart object, it does not serialize the JavaScript object, but the Dart proxy object. Therefore the JavaScript object is lost in the process.
Is there a way to pass the JavaScript object to IndexedDB from Dart? Or at least serialize the native JavaScript object from Dart proxy and then send it into IndexedDB?
Any guidance would be much appreciated.
Issue on dart-lang/sdk repository #50621
More on this repository , usage in example here , and js-interop here .
It will throw a NoSuchMethodError as the instance returned from IndexedDB is not a FileSystemDirectoryHandle.
Are you saying directory.name
throws a NoSuchMethodError
? What is the static type of directory
here? Is it possible you need to cast the result to storage.set
to FileSystemDirectoryHandle
?
My understanding of js-interop is that it translates JavaScript object into a Dart proxy. As I'm sending a Dart object, it does not serialize the JavaScript object, but the Dart proxy object. Therefore the JavaScript object is lost in the process.
This shouldn't be the case. The object is still a JavaScript object, you're just using a Dart type to interact with that object. So, you can use the Dart members you declared for it, but we don't wrap that object if you just write a @JS()
interface for it.
A workaround is available in issue linked in original post. Problem comes from dart:indexed_db
package.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.