F
Filamentā€¢10mo ago
Mansoor Khan

Upload image from URL

I am trying to upload a file from url to FileUpload field. Has anyone tried something like this before? I am able to upload the file locally, then save the path to db and then reset the FileUpload field state with new path. But I dont want to save it DB after downlaoding the file from url. I just want to pass it to FileUpload field, so that user can see a preview. Here is what i am trying. Everything works, file also saves correctly on submit and also previews after submit. But it does not preview unless you submit it. so wondering if there is a way to tell Filament to preview it.
Forms\Components\FileUpload::make('featured_image')->hintAction(
Filament\Forms\Components\Actions\Action::make('url_uploader')
->form([TextInput::make('url')->label('Image URL')])
->action(function (Set $set, Component $livewire, array $data) {
$filePath = UrlUploadedFile::createFromUrl($data['url'])
->store('livewire-tmp', ['disk' => 'local']);
$filePath = explode('/', $filePath)[1];

$file = TemporaryUploadedFile::createFromLivewire($filePath);

$set($livewire->mountedFormComponentActionsComponents[0], [$file], true);
}),
)
Forms\Components\FileUpload::make('featured_image')->hintAction(
Filament\Forms\Components\Actions\Action::make('url_uploader')
->form([TextInput::make('url')->label('Image URL')])
->action(function (Set $set, Component $livewire, array $data) {
$filePath = UrlUploadedFile::createFromUrl($data['url'])
->store('livewire-tmp', ['disk' => 'local']);
$filePath = explode('/', $filePath)[1];

$file = TemporaryUploadedFile::createFromLivewire($filePath);

$set($livewire->mountedFormComponentActionsComponents[0], [$file], true);
}),
)
29 Replies
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
Maybe i should find a way to refresh the field? so that it executes all the methods that are responsible to generate preview? I tried to refresh the data but that does not exist? errror: EditArticle::refreshFormData does not exist.
$livewire->refreshFormData(['featured_image' => [$file]]);
$livewire->refreshFormData(['featured_image' => [$file]]);
Ok so now i am trying this and preview and save would work just fine, but there is no way i can remove those custom-tmp files, once the file is saved or the form was reloaded and no one needs it any more
->action(function (Set $set, Component $livewire, array $data) {
$filePath = UrlUploadedFile::createFromUrl($data['url'])
->store('custom-tmp', ['disk' => 'public']);

$set($livewire->mountedFormComponentActionsComponents[0], [$filePath], true);
})
->action(function (Set $set, Component $livewire, array $data) {
$filePath = UrlUploadedFile::createFromUrl($data['url'])
->store('custom-tmp', ['disk' => 'public']);

$set($livewire->mountedFormComponentActionsComponents[0], [$filePath], true);
})
this isnt the way to go. If Livewire is saving the temp file to livewire-tmp which is not public, then how Filament is able to preview it?
awcodes
awcodesā€¢10mo ago
Iā€™m not sure filament is previewing it on upload to tmp. I think filepond is creating a base64 encoded version that it shows as the preview.
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
Hmm. Not sure what could be the solution. I am toying around for a plugin idea. We have these options: A) Save it to DB: But most of the user would never want to do that. Plus they would loose existing image. And how could we do this on create record page. B) Save it Publically: Security concerns and plus we never know when to delete it. C) Save it to livewire-tmp: It could be the best option but it cannot preview the image unless user submits the form and then Filament refreshes the it.
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
GitHub
filament/packages/forms/src/Components/BaseFileUpload.php at 1f3b4e...
A collection of beautiful full-stack components for Laravel. The perfect starting point for your next app. Using Livewire, Alpine.js and Tailwind CSS. - filamentphp/filament
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
oh its just for the saved files.
ralphjsmit
ralphjsmitā€¢10mo ago
Does $component->state(...) work?
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
I have to check that. By $component you mean $livewire, right?
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
No it does not work.
No description
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
this is what i tried.
->action(function (Set $set, $arguments, Component $livewire) {
// this saves the file to livewire-tmp dir
$filePath = UrlUploadedFile::createFromUrl($imageLink)
->store('livewire-tmp', ['disk' => 'local']);

$filePath = explode('/', $filePath)[1];

// Creates a TemporaryUploadedFile instance for given filepath/file
$file = TemporaryUploadedFile::createFromLivewire($filePath);

// $livewire->mountedFormComponentActionsComponents[0] is statePath of the FileUpload
$livewire->state($livewire->mountedFormComponentActionsComponents[0], [$file]);
})
->action(function (Set $set, $arguments, Component $livewire) {
// this saves the file to livewire-tmp dir
$filePath = UrlUploadedFile::createFromUrl($imageLink)
->store('livewire-tmp', ['disk' => 'local']);

$filePath = explode('/', $filePath)[1];

// Creates a TemporaryUploadedFile instance for given filepath/file
$file = TemporaryUploadedFile::createFromLivewire($filePath);

// $livewire->mountedFormComponentActionsComponents[0] is statePath of the FileUpload
$livewire->state($livewire->mountedFormComponentActionsComponents[0], [$file]);
})
ralphjsmit
ralphjsmitā€¢10mo ago
No, I meant the $component variable:
->action(function (Set $set, $arguments, Component $livewire, FileUpload $component) {
// this saves the file to livewire-tmp dir
$filePath = UrlUploadedFile::createFromUrl($imageLink)
->store('livewire-tmp', ['disk' => 'local']);

$filePath = explode('/', $filePath)[1];

// Creates a TemporaryUploadedFile instance for given filepath/file
$file = TemporaryUploadedFile::createFromLivewire($filePath);

$component->state($file);
// or [$file], not sure what it accepts
})
->action(function (Set $set, $arguments, Component $livewire, FileUpload $component) {
// this saves the file to livewire-tmp dir
$filePath = UrlUploadedFile::createFromUrl($imageLink)
->store('livewire-tmp', ['disk' => 'local']);

$filePath = explode('/', $filePath)[1];

// Creates a TemporaryUploadedFile instance for given filepath/file
$file = TemporaryUploadedFile::createFromLivewire($filePath);

$component->state($file);
// or [$file], not sure what it accepts
})
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
let me try that. same behavoir, it uploads the file succesffully but does not show the preview. But i never knew you could get the component itslef on which the action is mounted. Wow thanks for that man.
ralphjsmit
ralphjsmitā€¢10mo ago
OK, that's unfortunate! Then I'm out of ideas on this for now šŸ™‚ But I like the idea behind the Unsplash integration.
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
yes. Its a nice to have. One thing i could do is save it to the folder which is speicified by the user using ->disk() and ->directory() methods on fileupload field. but then it would remain there even if user cancel upload or never submitted the form.
ralphjsmit
ralphjsmitā€¢10mo ago
Yeah, I agree you would need some way to reset the Filepond thing, which is what you already concluded as well
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
Cant believe its not doable šŸ™‚
ralphjsmit
ralphjsmitā€¢10mo ago
No me neither, at least I think if the preview doesn't reset when changed using $set/->state(), it could even be considered a bug
ralphjsmit
ralphjsmitā€¢10mo ago
There is something about it in the source code though:
No description
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
ooooh. you are right...
ralphjsmit
ralphjsmitā€¢10mo ago
It seems like the process() function sets this to false, so I think that the issue is somewhere there You could try creating a quick reproduction repository for Filament and submit a bug report
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
ok good idea. i think i should use this snippet to keep it simple and understandable, instead of unsplash theory.
Forms\Components\FileUpload::make('featured_image')->hintAction(
Filament\Forms\Components\Actions\Action::make('url_uploader')
->form([TextInput::make('url')->label('Image URL')])
->action(function (Set $set, Component $livewire, array $data) {
$filePath = UrlUploadedFile::createFromUrl($data['url'])
->store('livewire-tmp', ['disk' => 'local']);
$filePath = explode('/', $filePath)[1];

$file = TemporaryUploadedFile::createFromLivewire($filePath);

$set($livewire->mountedFormComponentActionsComponents[0], [$file], true);
}),
)
Forms\Components\FileUpload::make('featured_image')->hintAction(
Filament\Forms\Components\Actions\Action::make('url_uploader')
->form([TextInput::make('url')->label('Image URL')])
->action(function (Set $set, Component $livewire, array $data) {
$filePath = UrlUploadedFile::createFromUrl($data['url'])
->store('livewire-tmp', ['disk' => 'local']);
$filePath = explode('/', $filePath)[1];

$file = TemporaryUploadedFile::createFromLivewire($filePath);

$set($livewire->mountedFormComponentActionsComponents[0], [$file], true);
}),
)
i would replace $set with the $component->state() though.
ralphjsmit
ralphjsmitā€¢10mo ago
Yes, agree! Or even just hardcode a URL from internet instead of an input
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
Forms\Components\FileUpload::make('avatar')
->image()
->hintAction(
\Filament\Forms\Components\Actions\Action::make('upload_from_url')
->action(function (FileUpload $component) {
$url = 'https://via.placeholder.com/150x150';

$filePath = UrlUploadedFile::createFromUrl($url)
->store('livewire-tmp', ['disk' => 'local']);

$filePath = explode('/', $filePath)[1];

$file = TemporaryUploadedFile::createFromLivewire($filePath);

$component->state([$file]);
})),
Forms\Components\FileUpload::make('avatar')
->image()
->hintAction(
\Filament\Forms\Components\Actions\Action::make('upload_from_url')
->action(function (FileUpload $component) {
$url = 'https://via.placeholder.com/150x150';

$filePath = UrlUploadedFile::createFromUrl($url)
->store('livewire-tmp', ['disk' => 'local']);

$filePath = explode('/', $filePath)[1];

$file = TemporaryUploadedFile::createFromLivewire($filePath);

$component->state([$file]);
})),
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
GitHub
Changing FileUpload field state() does not refresh the field on fro...
Package filament/filament Package Version v3.2 Laravel Version v10.0 Livewire Version v3.x PHP Version PHP8.2 Problem description I am trying to Upload a file from a URL using a Form Action. I down...
ralphjsmit
ralphjsmitā€¢10mo ago
Nice!
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
I did some debugging. I passed just the $file to ->state(), $file is an instance of TemporaryUploadedFile. And now file-upload.js is able to refresh the field and change the state but still no preview.
$component->state($file);
$component->state($file);
No description
No description
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
And the filepath that you see in console: "livewire-file:something.jpg" is stored in livewire-tmp.
Mansoor Khan
Mansoor KhanOPā€¢10mo ago
GitHub
Changing FileUpload field state() does not refresh the field/FilePo...
Package filament/filament Package Version v3.2 Laravel Version v10.0 Livewire Version v3.x PHP Version PHP8.2 Problem description I am trying to Upload a file from a URL using a Form Action. I down...
ralphjsmit
ralphjsmitā€¢10mo ago
It's a caveat I didn't know, but I think it makes sense

Did you find this page helpful?