Vaadin23 pass data between View and Layout - vaadin

This is my view with ComponentEvent defined:
#Route(value = "jobs/recommended", layout = JobsLayout.class)
#PermitAll
public class RecommendedJobsView extends VerticalLayout implements HasUrlParameter<String> {
public static class JobableInfo {
private final Long profileId;
private final Long recommendedJobsCount;
public JobableInfo(Long profileId, Long recommendedJobsCount) {
this.profileId = profileId;
this.recommendedJobsCount = recommendedJobsCount;
}
public Long getProfileId() {
return profileId;
}
public Long getRecommendedJobsCount() {
return recommendedJobsCount;
}
#Override
public String toString() {
return "JobableInfo{" +
"profileId=" + profileId +
", recommendedJobsCount=" + recommendedJobsCount +
'}';
}
}
public static class ProfileRecommendedJobsEvent extends ComponentEvent<RecommendedJobsView> {
private final JobableInfo jobableInfo;
public ProfileRecommendedJobsEvent(RecommendedJobsView source, JobableInfo jobableInfo) {
super(source, false);
this.jobableInfo = jobableInfo;
}
public JobableInfo getJobableInfo() {
return jobableInfo;
}
}
this is Layout:
#ParentLayout(MainLayout.class)
public class JobsLayout extends VerticalLayout implements RouterLayout, LocaleChangeObserver, BeforeEnterObserver {
public JobsLayout() {
addListener(RecommendedJobsView.ProfileRecommendedJobsEvent.class, event -> {
System.out.println(event.getJobableInfo());
});
}
In RecommendedJobsView I fire an event in the following way:
fireEvent(new ProfileRecommendedJobsEvent(this, new JobableInfo(profileId, jobPage.getTotalElements())));
but nothing happens in the JobsLayout. The listener doesn't react. What am I doing wrong and how to correctly send data from RecommendedJobsView to JobsLayout ?

Related

Google Guice binding using Annotation and Key class

Lets say we have A.java interface implemented by AImpl.java and B.java implemented by Bimpl.java
Above classes are binded in two modules as below
Module1 {
bind(A.class).to(AImpl.class);
bind(B.class).to(BImpl.class);
}
Module2 {
Key<A> aKey = Key.get(A.class, AnAnnot.class);
bind(aKey).to(AImpl.class);
Key<B> bKey = Key.get(B.class, AnAnnot.class);
bind(bKey).to(BImpl.class);
}
Class AImpl implements A {
}
Class BImpl implements B {
#Inject
BImpl(A aImpl) {
//??
}
}
BImpl refers to A
For BImpl binded using Annotation, I want corresponding aImpl, binded using Annotation but here I'm getting aImpl which is not binded using Annotation
Please suggest
I'm able to achieve using below pattern. May be there is a more easier way. Happy to know more
A.java
public interface A {
String aMethod();
}
AImpl.java
public class AImpl implements A {
private String moduleName;
public AImpl(String moduleName) {
this.moduleName = moduleName;
}
#Override
public String aMethod() {
return moduleName;
}
}
B.java
public interface B {
String bMethod();
}
Bimpl.java
public class BImpl implements B {
private final A a;
BImpl(A a) {
this.a = a;
}
#Override
public String bMethod() {
return a.aMethod();
}
}
AnAnnot.java
#Target(PARAMETER)
#Retention(RUNTIME)
#BindingAnnotation
public #interface AnAnnot {
}
BProvider.java
public class BProvider implements Provider<B> {
private final A a;
#Inject
BProvider(A a) {
this.a = a;
}
#Override
public B get() {
return new BImpl(a);
}
}
BHavingAnnotatedA.java
public class BHavingAnnotatedA implements Provider<B> {
private final A a;
#Inject
BHavingAnnotatedA(#AnAnnot A a) {
this.a = a;
}
#Override
public B get() {
return new BImpl(a);
}
}
ABModule1.java
public class ABModule1 extends AbstractModule {
#Override
protected void configure() {
bind(A.class).to(AImpl.class);
bind(B.class).toProvider(BProvider.class);
}
}
ABModule2.java
public class ABModule2 extends AbstractModule {
#Override
protected void configure() {
Key<A> aKey = Key.get(A.class, AnAnnot.class);
bind(aKey).to(AImpl.class);
Key<B> bKey = Key.get(B.class, AnAnnot.class);
bind(bKey).toProvider(BHavingAnnotatedA.class);
}
}

Updating adapter of AutoCompleteTextView from LiveData

I have a AutoCompleteTextView that I give it 2 different adapters depending on the amount of text that is being present at the textview - if it has 0 characters I want it to display a list of "recently searched" strings adapter, while if it has more than 1 characters I want it to display auto completion list.
My getRecentlySearchedQueries method along with the RecentSearchedViewModel-
private List<String> recentlySearchedQueries = new ArrayList<>(); // pasted from the top of the class
#Override
public void getRecentlySearchedQueries() {
recentSearchViewModel.getAllQueries().observe(getActivity(), databaseRecentlySearchList -> {
if (databaseRecentlySearchList == null) {
return;
}
for (int i = 0; i < databaseRecentlySearchList.size(); i++) {
Log.d("localDBValue", "Added value - " + databaseRecentlySearchList.get(i).toString() + "\n");
String query = databaseRecentlySearchList.get(i).getQuery();
recentlySearchedQueries.add(query);
}
//Log.d("localDBValue", "recent search list value - " + recentlySearchedQueries);
});
}
public class RecentSearchViewModel extends AndroidViewModel {
private RecentSearchRepository recentSearchRepository;
private LiveData<List<RecentSearchModel>> allRecentlySearched;
public RecentSearchViewModel(#NonNull Application application) {
super(application);
recentSearchRepository = new RecentSearchRepository(application);
allRecentlySearched = recentSearchRepository.getAllRecentSearches();
}
public void insert(RecentSearchModel model) {
recentSearchRepository.insert(model);
}
public void update(RecentSearchModel model) {
// add implementation in the future if needed
}
public void delete(RecentSearchModel model) {
// add implementation in the future if needed
}
public LiveData<List<RecentSearchModel>> getAllQueries() {
return allRecentlySearched;
}
}
public class RecentSearchRepository {
private RecentSearchDao recentSearchDao;
private LiveData<List<RecentSearchModel>> allRecentSearches;
public RecentSearchRepository(Application application) {
MarketplaceDatabase database = MarketplaceDatabase.getRecentSearchInstance(application);
recentSearchDao = database.recentSearchDao();
allRecentSearches = recentSearchDao.getRecentSearchList();
}
public void insert(RecentSearchModel model) {
new RecentSearchRepository.InsertRecentSearchAsyncTask(recentSearchDao).execute(model);
}
public void update (RecentSearchModel model) {
//TODO - implement in future if needed
}
public void delete(RecentSearchModel model) {
//TODO - implement in future if needed
}
public LiveData<List<RecentSearchModel>> getAllRecentSearches() {
return allRecentSearches;
}
private static class InsertRecentSearchAsyncTask extends AsyncTask<RecentSearchModel, Void, Void> {
private RecentSearchDao recentSearchDao;
public InsertRecentSearchAsyncTask(RecentSearchDao recentSearchDao) {
this.recentSearchDao = recentSearchDao;
}
#Override
protected Void doInBackground(RecentSearchModel... recentSearchModels) {
recentSearchDao.insert(recentSearchModels[0]);
return null;
}
}
private static class UpdateRecentSearchAsyncTask extends AsyncTask<RecentSearchModel, Void, Void> {
private RecentSearchDao recentSearchDao;
public UpdateRecentSearchAsyncTask(RecentSearchDao recentSearchDao) {
this.recentSearchDao = recentSearchDao;
}
#Override
protected Void doInBackground(RecentSearchModel... recentSearchModels) {
recentSearchDao.update(recentSearchModels[0]);
return null;
}
}
}
#Dao
public interface RecentSearchDao {
#Insert()
void insert(RecentSearchModel model);
#Update
void update(RecentSearchModel model);
#Delete
void delete(RecentSearchModel model);
#Query("select * from recent_search_table")
LiveData<List<RecentSearchModel>> getRecentSearchList();
}
#Entity(tableName = "recent_search_table")
public class RecentSearchModel {
#PrimaryKey(autoGenerate = true)
private int ID;
private String query;
public RecentSearchModel(){
}
public RecentSearchModel(String query) {
this.query = query;
}
public void setID(int ID) {
this.ID = ID;
}
public int getID() {
return ID;
}
public String getQuery() {
return query;
}
public void setQuery(String query) {
this.query = query;
}
#Override
public String toString() {
return "RecentSearchModel{" +
"query='" + query + '\'' +
'}';
}
#Override
public boolean equals(#Nullable Object obj) {
if (obj instanceof RecentSearchModel)
return this.query.equalsIgnoreCase(((RecentSearchModel) obj).query);
return false;
}
}
So, what I am doing here is for start getting all values inside my local DB and adding them to my String list that is part of the adapter. So far so good.
The issue I am facing is that the adapter won't show the amount of strings available in the list that populates it. In fact, it sometimes shows a view half-cut with wierd information, sometimes does not show anything and sometimes shows part of the corrent information. What am I missing?
Another thing I am facing is that the "recently searched" adapter won't work when clicking on the AutoCompleteTextView - it only works when typing and deleting values so the char length is 0. How can I make it work from start of focus?
Here is the way I am populating the information to the ViewModel -
/**
* Shows the searched products following
*/
#Override
public void getSearchedProducts(String searchedQuery) {
MarketplaceUtils.getSearchedProducts(searchedQuery, marketApiCalls, false, initialSearchTake, initialMarketplacePage, new MarketplaceUtils.OnProductsFetchCompleteListener() {
#Override
public void onSuccess(List<MiniProductModel> list) {
if (!searchedQuery.equals(currentSearchedText))
return;
if (list == null) {
//reaching here means we do not have a result to show to the UI so we empty the list.
currentProductList.clear();
productsAdapter.notifyDataSetChanged();
return;
}
if (searchedQuery.length() > 3 && searchAutoCompleteStrings.contains(searchedQuery)) {
Log.d("localDBValue", "searchedValue - " + searchedQuery);
recentSearchViewModel.insert(new RecentSearchModel(searchedQuery));
}
mPresenter.setDiscoverProductsLayoutVisibility(View.GONE);
currentProductList.clear();
currentProductList.addAll(list);
productsAdapter.notifyDataSetChanged();
}
#Override
public void onError(Throwable throwable) {
Log.d("searchedProducts", throwable.getMessage());
}
});
}
The default behaviour for #Insert method of Room is OnConflictStrategy.ABORT - so what I did is to implement equals() method to verify that the RecentSearchModels that are being compared are compared by their string value. Still does seems to effect anything.

Dagger generated code compilation failed when using #Singleton annotation

I am using Dagger - 2.6 and i have the following classes.
public class Trigger {
public static JSONObject triggerLambda(JSONObject jsonObject) {
DataTransformerComponent daggerDataTransformerComponent = DaggerDataTransformerComponent.create();
return daggerDataTransformerComponent.getHandler().handle(jsonObject);
}
}
Data Handler class:
public class DataHandler {
private static final Logger LOGGER = Logger.getLogger(DataHandler.class.getName());
private A a;
#Inject
public DataHandler(A a) {
this.a = a;
}
public JSONObject handle(JSONObject input) {
LOGGER.info("Json input received - " + input.toString());
return a.executeTransformation(input);
}
}
And a dependency:
public class A {
#Inject
public A() {
}
public JSONObject executeTransformation(JSONObject jsonObject) {
System.out.println("a");
return null;
}
}
My component class looks like:
#Component
public interface DataTransformerComponent {
DataHandler getHandler();
}
When i compile the above code it runs absolutely fine.
Now i want to make my A dependency #Singleton.
So i change my dependency class and component class as follows:
#Singleton
#Component
public interface DataTransformerComponent {
DataHandler getHandler();
}
Dependency class:
#Singleton
public class A {
#Inject
public A() {
}
public JSONObject executeTransformation(JSONObject jsonObject) {
System.out.println("a");
return null;
}
}
But now the generated component shows compilation errors saying:
A_Factory not found and it fails in the initialize() method.
DaggerDataTransformerComponent :
#Generated(
value = "dagger.internal.codegen.ComponentProcessor",
comments = "https://google.github.io/dagger"
)
public final class DaggerDataTransformerComponent implements DataTransformerComponent {
private Provider<A> aProvider;
private Provider<DataHandler> dataHandlerProvider;
private DaggerDataTransformerComponent(Builder builder) {
assert builder != null;
initialize(builder);
}
public static Builder builder() {
return new Builder();
}
public static DataTransformerComponent create() {
return builder().build();
}
#SuppressWarnings("unchecked")
private void initialize(final Builder builder) {
this.aProvider = DoubleCheck.provider(A_Factory.create());
this.dataHandlerProvider = DataHandler_Factory.create(aProvider);
}
#Override
public DataHandler getHandler() {
return dataHandlerProvider.get();
}
public static final class Builder {
private Builder() {}
public DataTransformerComponent build() {
return new DaggerDataTransformerComponent(this);
}
}
}
I am unable to figure out why it does not create _factory class when i use #Singleton annotation.?.
Just use regular JavaScript + node.js, its a lot simpler

NestedSlot presenter with own url- how to setup url for NestedSlot presenters

I have parent presenter: UsersListPresenter that contains nested presenter: UserPresenter in NestedSlot.
public class UsersListPresenter extends ApplicationPresenter<UsersListPresenter.MyView, UsersListPresenter.MyProxy> implements UsersListUiHandlers,
OpenWindowEvent.OpenModaHandler, UserAddedEvent.UserAddedHandler {
#ProxyStandard
#NameToken(ClientRouting.Url.users)
#UseGatekeeper(IsUserLoggedGatekeeper.class)
public interface MyProxy extends TabContentProxyPlace<UsersListPresenter> {}
#TabInfo(container = AppPresenter.class)
static TabData getTabLabel(IsUserLoggedGatekeeper adminGatekeeper) {
return new MenuEntryGatekeeper(ClientRouting.Label.users, 1, adminGatekeeper);
}
public interface MyView extends View, HasUiHandlers<UsersListUiHandlers> {
void setUsers(List<UserDto> users);
void addUser(UserDto user);
}
public static final NestedSlot SLOT_USER_WINDOW = new NestedSlot();
//interface Driver extends SimpleBeanEditorDriver<UserDto, UserEditor> {}
private static final UserService userService = GWT.create(UserService.class);
private AppPresenter appPresenter;
private UserTestPresenter userPresenter;
#Inject
UsersListPresenter(EventBus eventBus, MyView view, MyProxy proxy, AppPresenter appPresenter, UserTestPresenter userPresenter) {
super(eventBus, view, proxy, appPresenter, AppPresenter.SLOT_TAB_CONTENT);
this.appPresenter = appPresenter;
this.userPresenter = userPresenter;
getView().setUiHandlers(this);
}
#Override
protected void onBind() {
super.onBind();
updateList();
setInSlot(SLOT_USER_WINDOW, userPresenter);
addRegisteredHandler(OpenWindowEvent.getType(), this);
}
#Override
protected void onReveal() {
super.onReveal();
initializeApplicationUiComponents(ClientRouting.Label.users);
}
#Override
public void onOpenModal(OpenWindowEvent event) {
openModal(event.getUser());
}
#Override
public void openModal(UserDto user) {
userPresenter.openModal(user);
}
}
public class UsersListView extends ViewWithUiHandlers<UsersListUiHandlers> implements UsersListPresenter.MyView {
interface Binder extends UiBinder<Widget, UsersListView> {}
#UiField
SimplePanel windowSlot;
#Inject
UsersListView(Binder uiBinder) {
initWidget(uiBinder.createAndBindUi(this));
}
#Override
public void setInSlot(Object slot, IsWidget content) {
if (slot == UsersListPresenter.SLOT_USER_WINDOW) {
windowSlot.setWidget(content);
}
};
}
public class UserTestPresenter extends Presenter<UserTestPresenter.MyView, UserTestPresenter.MyProxy> implements UserTestUiHandlers {
public interface MyView extends View, HasUiHandlers<UserTestUiHandlers> {
void openModal(UserDto user);
}
#ProxyStandard
#NameToken("/user/{userid}")
public interface MyProxy extends ProxyPlace<UserTestPresenter> {
}
private PlaceManager placeManager;
#Inject
public UserTestPresenter(EventBus eventBus, MyView view, MyProxy proxy, PlaceManager placeManager) {
super(eventBus, view, proxy, UsersListPresenter.SLOT_USER_WINDOW);
this.placeManager = placeManager;
getView().setUiHandlers(this);
}
#Override
public void prepareFromRequest(PlaceRequest request) {
GWT.log("Prepare from request " + request.getNameToken());
}
#Override
protected void onReveal() {
super.onReveal();
};
public void openModal(UserDto user) {
getView().openModal(user);
}
#Override
public void onSave(UserDto user) {
// TODO Auto-generated method stub
MaterialToast.fireToast("onSaveClick in new presenter for " + user.toString());
}
#Override
public void onClose() {
PlaceRequest placeRequest = new PlaceRequest.Builder().nameToken("/users/{userid}").with("userid", "list").build();
placeManager.revealPlace(placeRequest);
}
public class UserTestView extends ViewWithUiHandlers<UserTestUiHandlers> implements UserTestPresenter.MyView {
interface Binder extends UiBinder<Widget, UserTestView> {}
#UiField
MaterialRow main;
#UiField
MaterialWindow window;
#UiField
MaterialLabel userName, userFullName;
#UiField
MaterialButton saveButton;
private HandlerRegistration saveButtonClickHandler;
#Inject
UserTestView(Binder uiBinder) {
initWidget(uiBinder.createAndBindUi(this));
// adding default click handler
saveButtonClickHandler = saveButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {}
});
}
#Override
public void openModal(final UserDto user) {
userName.setText(user.getEmail());
userFullName.setText(user.getId() + " " + user.getEmail());
saveButtonClickHandler.removeHandler();
saveButtonClickHandler = saveButton.addClickHandler(new ClickHandler() {
#Override
public void onClick(ClickEvent event) {
getUiHandlers().save(user);
}
});
window.openWindow();
}
}
when user from list is clicked the window with clicked users is opened. At this moment url should change from http://localhost:8080/cms/#/users/list to http://localhost:8080/cms/#/user/3
for better understanding below is screencast from that code:
and now some job done, but still not ideal:
here is my gwtp configuration:
public class ClientModule extends AbstractPresenterModule {
#Override
protected void configure() {
bind(RestyGwtConfig.class).asEagerSingleton();
install(new Builder()//
.defaultPlace(ClientRouting.HOME.url)//
.errorPlace(ClientRouting.ERROR.url)//
.unauthorizedPlace(ClientRouting.LOGIN.url)//
.tokenFormatter(RouteTokenFormatter.class).build());
install(new AppModule());
install(new GinFactoryModuleBuilder().build(AssistedInjectionFactory.class));
bind(CurrentUser.class).in(Singleton.class);
bind(IsAdminGatekeeper.class).in(Singleton.class);
bind(IsUserLoggedGatekeeper.class).in(Singleton.class);
bind(ResourceLoader.class).asEagerSingleton();
}
}
As You can see I use tokenFormatter(RouteTokenFormatter.class)
how it can be achieved with gwtp framework?
One way to achieve this is to change the URL of your UserListPresenter to support passing in the user id as an optional parameter:
#NameToken("/users/{userid}")
public interface MyProxy extends ProxyPlace<UserListPresenter> {
}
You need to override the prepareFromRequest method of your UserListPresenter and there you check if the userid is set and open your modal window if it is.
#Override
public void prepareFromRequest(PlaceRequest request) {
String userid = request.getParameter("userid", "list");
if (userid != "list") {
# open modal
}
else {
# close modal
}
}
You also need to change the logic when you click your on a user in your list:
#Override
public void onOpenModal(OpenWindowEvent event) {
PlaceRequest placeRequest = new PlaceRequest.Builder()
.nameToken("/users/{userid}")
.with("userid", event.getUser().getId())
.build();
placeManager.revealPlace(placeRequest);
}
This will change the URL and open the modal.

Vaadin 7 : RPC call from Server to Client

I would like to create custom image component .So I followed step by step from Integrating with Server-side. For basic or first-step , I created for the test Server to Client RPC call as following steps.
MyComponentWidget.java
public class MyComponentWidget extends HTML {
public MyComponentWidget() {
getElement().setAttribute("class", "thumbnail");
}
public final void createCustomImage(final String url) {
getElement().setInnerHTML("<div class='delete-block'></div><img src=" + url + " />");
}
}
MyComponentState.java
public class MyComponentState extends AbstractComponentState {
private String url;
private String html;
public final String getUrl() {
return url;
}
public final void setUrl(final String url) {
this.url = url;
}
public final String getHtml() {
return html;
}
public final void setHtml(final String html) {
this.html = html;
}
}
MyComponentConnector.java
public class MyComponentConnector extends AbstractComponentConnector {
public MyComponentConnector() {
registerRpc(MyComponentClientRpc.class, new MyComponentClientRpc() {
#Override
public void getMessage() {
// never reach to this place
System.err.println("Reach Here !");
getState().setHtml(getWidget().getHTML());
}
});
}
#Override
public final MyComponentWidget getWidget() {
return (MyComponentWidget) super.getWidget();
}
#Override
public final MyComponentState getState() {
return (MyComponentState) super.getState();
}
#OnStateChange("url")
final void updateText() {
getWidget().createCustomImage(getState().getUrl());
}
}
MyComponentClientRpc.java
import com.vaadin.shared.communication.ClientRpc;
public interface MyComponentClientRpc extends ClientRpc {
void getMessage();
}
MyComponent.java
public class MyComponent extends AbstractComponent {
public MyComponent(final String url) {
getState().setUrl(url);
}
public final MyComponentState getState() {
return (MyComponentState) super.getState();
}
public final String getHTML() {
getRpcProxy(MyComponentClientRpc.class).getMessage();
return getState().getHtml();
}
}
and call as
MyComponent image = new MyComponent("myImageUrl");
System.out.println(image.getHTML());
My problem is why I always get null value at my console ? I can see the image at browser but System.out.println(image.getHTML()); produces null. What am I missing ?
To make a rpc call from client to server, you must extend the ServerRpc interface, for example:
package com.example.client.MyServerRpc
public interface MyServerRpc extends com.vaadin.shared.communication.ServerRpc {
void sendHTML(String html);
}
In your connector your register the rpc:
private MyServerRpc rpc = RpcProxy.create(MyServerRpc.class, this);
And then you can send a value by using the registered rpc in your connector:
rpc.sendHTML(html);
To receive the value on your component's or extension's server-side class, you must create an instance of the rpc interface:
private MyServerRpc rpc = new MyServerRpc() {
#Override
public void sendHTML(String html) {
// this method will be called!
}
};
and register that in the constructor:
registerRpc(rpc);
After these steps RPC from client to server should work.

Resources