Hi Jean-Christophe,
Thanks for your pointer. I have got this working now with Vaadin and Intellij.
Process was:
- Download Vaadin 18 starter
- Install paper-input-place using npm from the Terminal in Intellij - this installed in node_modules/paper-input-place
- Added PaperInputPlace class as below:
Response updated.. In order to integrate with Vaadin Flow, I have had to make some changes to the WebComponent as it was not returning the selected value correctly. This is not really a Vaadin issue, just that the WebComponent is not really ‘Vaadin ready’. The updated Vaadin Class is as follows:
import com.vaadin.flow.component.*;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.dependency.NpmPackage;
import com.vaadin.flow.shared.Registration;
@Tag("paper-input-place")
@NpmPackage(value = "paper-input-place", version = "2.0.1")
@JsModule("paper-input-place/paper-input-place.js")
public class PaperInputPlace extends AbstractSinglePropertyField<PaperInputPlace, String> {
private static final PropertyDescriptor<String,String> placeJSON = PropertyDescriptors.propertyWithDefault("placeJSON", "not entered");
private static boolean geoReady=false;
private static String value="not set";
public PaperInputPlace(String k) {
super("value", "not set", false);
setKey(k);
minimizeAPI(true);
}
public void setKey(String k)
{
getElement().setProperty("apiKey",k);
}
public void minimizeAPI(Boolean k)
{
getElement().setProperty("minimizeAPI", k);
}
public void setCountry(String countryCode) {
getElement().setProperty("searchCountryCode",countryCode);
}
public void fillValue(String placeString)
{
// this does not need to be encoded...
String comm = "this.fillValue($0)";
if(geoReady) {
getElement().executeJs(comm, placeString);
}
else
{
System.out.println("Goecoder is not yet ready: = make sure GeoReadyEvent is used:"+placeString );
}
}
public String getPlace()
{
//this should return a string...but does not
return placeJSON.get(this);
}
//
@DomEvent("api-loaded")
public static class GeoReadyEvent extends ComponentEvent<PaperInputPlace>
{
private String value;
//was event.detail.text
public GeoReadyEvent(PaperInputPlace source,boolean fromClient,@EventData("event.detail.text") String value)
{
super(source,fromClient);
this.value=value;
geoReady=true;
}
}
public Registration addGeoReadyEventListener(ComponentEventListener<GeoReadyEvent> listener)
{
return addListener(GeoReadyEvent.class, listener);
}
//
@DomEvent("input-change")
public static class ValueChangeEvent extends ComponentEvent<PaperInputPlace>
{
private String value;
//was event.detail.text
public ValueChangeEvent(PaperInputPlace source,boolean fromClient,@EventData("event.detail.text") String value)
{
super(source,fromClient);
this.value=value;
}
}
public Registration addValueChangeEventListener(ComponentEventListener<ValueChangeEvent> listener)
{
return addListener(ValueChangeEvent.class, listener);
}
//
@DomEvent("change-complete")
public static class ValueCompleteEvent extends ComponentEvent<PaperInputPlace>
{
private String value;
//was event.detail.text
public ValueCompleteEvent(PaperInputPlace source,boolean fromClient,@EventData("event.detail.text") String value)
{
super(source,fromClient);
this.value=value;
}
}
public Registration addValueCompleteEventListener(ComponentEventListener<ValueCompleteEvent> listener)
{
return addListener(ValueCompleteEvent.class, listener);
}
@DomEvent("click")
public static class ClickEvent extends ComponentEvent<PaperInputPlace>
{
private String value;
//was event.detail.text
public ClickEvent(PaperInputPlace source,boolean fromClient,@EventData("event.detail.text") String value)
{
super(source,fromClient);
this.value=value;
}
}
public Registration addClickEventListener(ComponentEventListener<ClickEvent> listener)
{
return addListener(ClickEvent.class, listener);
}
}
A new event was added to the WebComponent (change-complete) because the input-change event was not returning the selected value - it was only returning what the user has typed in in the control. Also note that, If you are setting values, you have to wait until the geocoder is ready before passing values to it. Here is an example.
PaperInputPlace p2 = new PaperInputPlace("enter key");
// p2.fillValue("leeds, uk");
p2.setCountry("GB");
p2.addGeoReadyEventListener(event->
{
p2.fillValue("");
System.out.println("API is ready "+p2.getPlace());
}
);
p2.addValueCompleteEventListener(event->
{
System.out.println("new value "+p2.getValue());;
});
Button button = new Button("Fill value");
button.addClickListener(event->
{
p2.fillValue("liverpool,uk");
});
Button button2 = new Button("Get Values");
button2.addClickListener(event->
{
Notification.show("event:"+event.getSource().getText()+", Value:" +p2.getValue()+",Place:"+p2.getPlace());
});
add(p2,button,button2);
Changes to the JavaScript are required a) add new function fillValue
fillValue(valueToFill)
{
//alert("fillvalue:"+valueToFill);
this.geocode(valueToFill).then(
function(result) {
// set the control to this place
this.putPlace(result);
}.bind(this),
function(status) {
// do something with status - the reason the geocode did not work
// alert("The GeoCoding API failed - Status failure:"+status)
}.bind(this)
);
}
b) modify _onChangePlace() to include a new event change-complete
_onChangePlace(e) {
var pl = this._places.getPlace();
if (pl.geometry) {
var p = this._extractPlaceInfo(pl, this.$.nativeInput.value);
this._setPlace(p);
this._invalid = false;
this._setInvalid(false);
this._setLatLng({
lat: p.latLng.lat,
lng: p.latLng.lng
});
this._value = this.$.nativeInput.value;
this.value = {
search: this.$.nativeInput.value,
place_id: p.place_id,
latLng: {
lat: p.latLng.lat,
lng: p.latLng.lng
}
};
this.placeJSON="{ \"place\": {\"name\":\""+p.search+"\",\"latLng\":{\"lat\":"+p.latLng.lat+" ,\"long\":"+p.latLng.lng+"}}}";
// alert("values of placeJSON - search:"+this.placeJSON);
// alert("this is the new value"+this.$.nativeInput.value+":"+this.$.nativeInput.value.search);
this.dispatchEvent(new CustomEvent('change-complete', {
detail: {
text: this.value.search
}
}));
this.placeName=this._value.place_id;
}
}
I have tried to return the values back using a JavaScript variable but this does not work (but it is not necessary for correct operation).
/**
*provides place as a JSON string to enable returning back to Vaadin 10+
* name as displayed in panel and lat long
* ***
*/
placeJSON: {
type: String,
value: "not set"
},
/**
If you make these changes, you can
- use Google drop down
- return to Vaadin what has been selected by the user
- set the values based on previous input.
It is a really useful WebComponent !