Hi,
I cant display image in JMIX 2.0 after upload image. It display the download link but not the image. Does this have to do with SecurityConfiguration? Im using FileStorageUploadField
Hi,
I cant display image in JMIX 2.0 after upload image. It display the download link but not the image. Does this have to do with SecurityConfiguration? Im using FileStorageUploadField
Hello!
Could you clarify how do you set value to Image component?
For instance, if your FileStorageUploadField
is bound with property in InstanceContainer
, so you can do the same with Image
:
<data>
<instance id="documentDc"
class="com.company.tr.entity.Document">
<fetchPlan extends="_base"/>
<loader/>
</instance>
</data>
...
<layout>
<formLayout id="form" dataContainer="documentDc">
<fileStorageUploadField id="fileRefField"
property="fileRef"
fileNameVisible="true"/>
</formLayout>
<image id="image"
width="200px"
height="200px"
themeNames="scale-down"
dataContainer="documentDc"
property="fileRef"/>
...
</layout>
Otherwise you should manually set value to Image
component after uploading a file. For more details see: image :: Jmix Documentation.
Hye @pinyazhin, I am using jmix 2.0.1 with flowUI and i’m facing the same problem as mentioned above. I had tried manually to preview the uploaded image using .SetValueSource and .SetSrc before saving it to dB but the image does not load. If I am using Static Recourses based on the link you provided, the image is successfully load. Is there any ways/ workaround for me to solve the issue? Thanks, in advance!
**I even tried to use onUploadReceiptFileUploadSucceeded handlers, but the image did not load
Hello!
To show FileRef
or byte[]
types in Image, you can do the same as an example in docs with static resource. For FileRef
you should get FileStorage
and open input stream.
Example for FileStorageUploadField
with IMMEDIATE put mode. For MANUAL mode use FileUploadSucceededEvent
.
@Autowired
protected FileStorageLocator fileStorageLocator;
@ViewComponent
protected JmixImage<FileRef> image;
@Subscribe("fileRefField")
protected void onFileRefFieldComponentValueChange(final AbstractField.ComponentValueChangeEvent<FileStorageUploadField, FileRef> event) {
FileRef fileRef = event.getValue();
if (fileRef == null) {
image.setSrc("");
} else {
image.setSrc(new StreamResource(fileRef.getFileName(),
() -> fileStorageLocator.getByName(fileRef.getStorageName()).openStream(fileRef)));
}
}
Hi,
using the following coding I can see the uploaded image directly in the GUI.
But, when I click on OK,
it never got written into the DB table.
The column type is byte[]
What do I miss to write the data back into the DB?
(photo3UploadField is a fileUploadField and the coding is called in …uploadSucceededListener)
ByteArrayInputStream bais = new ByteArrayInputStream(photo3UploadField.getValueSource().getValue());
BufferedImage newImage = Scalr.resize(ImageIO.read(bais), targetSize); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageIO.write(newImage, "png", baos); byte[] bytes = baos.toByteArray(); ByteArrayInputStream bais2 = new ByteArrayInputStream(bytes); StreamResource resource = new StreamResource("test.png", () -> bais2); photo1Field.setSrc(resource);
got it… I did not set the dataContainer in the image in the descriptor
Hi @pinyazhin ,
I did exactly the way the documentation and what u shown but still doesnt show anything.
Hi,
I tried using your solution using the onFileRefFieldComponentValueChange. When i implement it i get this error.
Could you share your definition of Image
and FileStorageUploadField
in XML and controller code where you trying to set value to the Image
?
Hi,
This is my code
Dialog-view.XML code
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<view xmlns="http://jmix.io/schema/flowui/view"
title="msg://dialogView.title">
<data>
<instance id="fuelDetails2Dc"
class="com.company.hexagonamdu.entity.FuelDetails2">
<fetchPlan extends="_local">
<property fetchPlan="_base" name="driverId"/>
<property fetchPlan="_base" name="masterList"/>
<property fetchPlan="_base" name="supplier"/>
</fetchPlan>
</instance>
</data>
<formLayout id="form" dataContainer="fuelDetails2Dc">
<details summaryText="Upload">
<hbox>
<fileStorageUploadField dataContainer="fuelDetails2Dc" required="true"
property="document_ref" label="Upload" id="uploadReceipt"
fileNameVisible="true"/>
<image id="receiptPic" property="document_ref" dataContainer="fuelDetails2Dc" height="10em" width="10em" themeNames="scale-down" />
</hbox>
</details>
</formLayout>
DialogView.Java
package com.company.hexagonamdu.view.dialog;
import com.company.hexagonamdu.entity.FuelDetails2;
import com.company.hexagonamdu.entity.Supplier;
import com.company.hexagonamdu.entity.TruckDriver;
import com.company.hexagonamdu.entity.VehicleMasterList;
import com.company.hexagonamdu.view.fueldetails2.FuelDetails2DetailView;
import com.company.hexagonamdu.view.main.MainView;
import com.vaadin.flow.component.AbstractField;
import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.HasValue;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.html.Image;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.StreamResource;
import io.jmix.core.*;
import io.jmix.flowui.DialogWindows;
import io.jmix.flowui.Notifications;
import io.jmix.flowui.UiComponents;
import io.jmix.flowui.component.combobox.EntityComboBox;
import io.jmix.flowui.component.image.JmixImage;
import io.jmix.flowui.component.textfield.TypedTextField;
import io.jmix.flowui.component.upload.FileStorageUploadField;
import io.jmix.flowui.kit.component.button.JmixButton;
import io.jmix.flowui.view.*;
import org.springframework.beans.factory.annotation.Autowired;
import java.time.LocalTime;
import java.util.Date;
import static com.company.hexagonamdu.view.fueldetails2.FuelDetails2DetailView.setNewOdometerValue;
@Route(value = "DialogView", layout = MainView.class)
@ViewController("DialogView")
@ViewDescriptor("Dialog-view.xml")
public class DialogView extends StandardView {
@ViewComponent
private JmixButton saveButton;
@Autowired
private DataManager dataManager;
@Autowired
private Notifications notifications;
@Autowired
private Metadata metadata;
@ViewComponent
private TypedTextField receiptIdField;
@ViewComponent
private FileStorageUploadField uploadReceipt;
@Autowired
protected FileStorageLocator fileStorageLocator;
@ViewComponent
protected JmixImage<FileRef> image;
@Subscribe
protected void onInit(InitEvent event) {
saveButton.addClickListener(this::validateAndSave);
}
private void validateAndSave(final ClickEvent<Button> event) {
// Create a new instance of FuelDetails2 entity
FuelDetails2 fuelDetails = metadata.create(FuelDetails2.class);
// Set properties of the fuelDetails entity based on the form values
fuelDetails.setDocument_ref(uploadReceipt.getValue());
try {
// Save the fuelDetails entity to the database
dataManager.save(fuelDetails);
// Show a success notification
notifications.show("Fuel details saved successfully.");
// Call the updateDataGrid method to refresh the data grid
getParent().ifPresent(view -> {
if (view instanceof FuelDetails2DetailView) {
((FuelDetails2DetailView) view).updateDataGrid();
}
});
// Close the dialog
closeWithDefaultAction();
} catch (Exception e) {
// Handle any exceptions that may occur during saving
notifications.show("Error while saving fuel details: " + e.getMessage());
}
} else {
// Display an error message or handle the validation failure
}
}
@Subscribe("uploadReceipt")
protected void onFileRefFieldComponentValueChange(final AbstractField.ComponentValueChangeEvent<FileStorageUploadField, FileRef> event) {
FileRef fileRef = event.getValue();
if (fileRef == null) {
image.setSrc("");
} else {
image.setSrc(new StreamResource(fileRef.getFileName(),
() -> fileStorageLocator.getByName(fileRef.getStorageName()).openStream(fileRef)));
}
}
}
This is the FuelDetails2.java
Thank you in advance
Thank you for the provided code. Since you use StandardView
, you should set FuelDetails2
instance to the container manually when View is opened. For instance:
@ViewComponent
protected InstanceContainer<FuelDetails2> fuelDetails2Dc;
@Subscribe
protected void onInit(final InitEvent event) {
FuelDetails2 fuelDetails = dataManager.create(FuelDetails2.class);
fuelDetails2Dc.setItem(fuelDetails);
}
Thus when you upload an image via FileStorageUploadField
it automatically set picture to Image
component. And you don’t need onFileRefFieldComponentValueChange()
listener anymore.
Another way, just change:
@ViewComponent
protected JmixImage<FileRef> image;
To your image id:
@ViewComponent
protected JmixImage<FileRef> receiptPic;
And it should work.
Hi @pinyazhin , the images are able to preview now but we had issues when clicking to open the dialog button and when clicking the save button to save the details and images. When click to open the dialog box we hit this error:
java.lang.ClassCastException: class java.lang.String cannot be cast to class com.company.hexagonamdu.entity.TruckDriver (java.lang.String is in module java.base of loader ‘bootstrap’; com.company.hexagonamdu.entity.TruckDriver is in unnamed module of loader ‘app’)
at io.jmix.core.metamodel.model.utils.MethodsCache$SettersHolder.accept(MethodsCache.java:241)
at io.jmix.core.entity.BaseEntityEntry.setAttributeValue(BaseEntityEntry.java:104)
at io.jmix.core.entity.EntityValues.setValue(EntityValues.java:73)
at io.jmix.core.entity.EntityValues.setValueEx(EntityValues.java:198)
at io.jmix.core.entity.EntityValues.setValueEx(EntityValues.java:151)
at io.jmix.flowui.data.value.ContainerValueSource.setValue(ContainerValueSource.java:174)
at io.jmix.flowui.data.binding.impl.AbstractValueBinding.setValueToSource(AbstractValueBinding.java:282)
at io.jmix.flowui.data.binding.impl.AbstractValueBinding.onComponentValueChange(AbstractValueBinding.java:230)
at io.jmix.flowui.data.binding.impl.AbstractValueBinding.lambda$addComponentValueChangeListener$9601773c$1(AbstractValueBinding.java:376)
at com.vaadin.flow.component.ComponentEventBus.fireEventForListener(ComponentEventBus.java:233)
at com.vaadin.flow.component.ComponentEventBus.fireEvent(ComponentEventBus.java:222)
at io.jmix.flowui.component.textfield.TypedTextField.fireTypedValueChangeEvent(TypedTextField.java:267)
at io.jmix.flowui.component.textfield.TypedTextField.fireAllValueChangeEvents(TypedTextField.java:260)
at io.jmix.flowui.component.textfield.TypedTextField.setValueInternal(TypedTextField.java:189)
at io.jmix.flowui.component.textfield.TypedTextField.setValue(TypedTextField.java:174)
at com.company.hexagonamdu.view.dialog.DialogView.setDriverNameListField(DialogView.java:167)
at com.company.hexagonamdu.view.fueldetails2.FuelDetails2DetailView.onCustomParameterDialogButtonClick(FuelDetails2DetailView.java:597)
and when attempting to save we hit this error :
java.lang.NumberFormatException: For input string: “”
at java.base/java.lang.NumberFormatException.forInputString(NumberFormatException.java:67)
at java.base/java.lang.Integer.parseInt(Integer.java:678)
at java.base/java.lang.Integer.parseInt(Integer.java:786)
at com.company.hexagonamdu.view.dialog.DialogView.validateAndSave(DialogView.java:238)
This is our code when we retrieve the data from previous row to compare with the new filled in data, hope this can help you to point out what are our mistakes.
public void onCustomParameterDialogButtonClick(final ClickEvent<JmixButton> event) {
TruckDriver selectedDriver = driverNameListField.getValue();
VehicleMasterList selectedMasterList = masterListField.getValue();
String selectedDetailsDate = detailDateField.getValue();
LocalTime selectedTime = timeField.getValue();
if (selectedDriver != null && selectedMasterList != null && selectedDetailsDate != null && selectedTime != null) {
dialogWindows.view(this, DialogView.class).open();
// Pass any necessary data to the dialog
DialogView.setLastOdometerValue(lastodometerField.getValue());
DialogView.setDriverNameListField(String.valueOf(selectedDriver.getId()));
DialogView.setMasterListField(String.valueOf(selectedMasterList.getId()));
DialogView.setDetailDateField(detailDateField.getValue());
DialogView.setTimeField(String.valueOf(timeField.getValue()));
} else {
// Display an error message if any of the fields is empty
notifications.show("Please fill in 'Driver's Name', 'Registration No' fields, 'DetailDate' and 'Time'.");
}
}
We tried to perform some workaround with the code to counter the error but didn’t able to figure it out.
Truly appreciate if you can point out what mistakes that we made and share your insight on how to deal with this issues.
Thank you in advance.
Hello!
The first exception means that you are trying to set text value from TypedTextField
(or textField
in XML) to entity value (TruckDriver). If you want to bind field with TruckDriver type you should use entityPicker
field.
The second exception says that cannot parse empty string to Integer. Try to debug your dialog to find out where mismatch in types comes from.