I have been trying GWTP for the past couple of weeks and building a small project with it.
Here's the question :
I have a grid widget (attached screenshot) which shows a list of data. On selection of a checkbox of a row and clicking on Edit Request, I get into a detail page.
Since I have all the data (model) to be shown in the detail page in the summary screen presenter itself, I don't want to fetch it from the database again.
So, I did the following :
On selection and clicking edit request, I get the selected model
Make a place request to the detail page
Fire an edit event and pass the selected model as parameter.
I understand that I am doing it wrong because when I select an item and hit Edit Request, the detail page does not receive the selected item yet. It just shows a blank page with no data filled in (obviously, because the place has been reached much before the event has been fired).
Current code :
RequestModel selectedItem = getView().getGrid().getSelectionModel().getSelectedItem();
PlaceRequest placeRequest=new PlaceRequest(NameTokens.initiationedit);
getEventBus().fireEvent(new RequestEditEvent(selectedItem, PHASE_INITIATION));
placeManager.revealPlace(placeRequest);
Personally thought solution : Instead of firing an event, I could make a placerequest with a parameter of the selected item's id and then override the useManualReveal and the prepareFromRequest to fetch data fresh from database.
But is there a way I could avoid database call for the pre-existing data.
If you want to keep your current "RequestEditEvent" solution, then make sure to use #ProxyEvent (see http://code.google.com/p/gwt-platform/wiki/GettingStarted?tm=6#Attaching_events_to_proxies).
Another possibility may be to invert the direction of the event: In your details presenter, fire an event which requests data from the overview presenter.
However, when using the same data across multiple presenters, then it may be a good idea to keep the data in a central model: Create a model class (#Singleton) and inject it everywhere you need it. Then you can make a lookup (by id) from that local model instead of asking the server. In this case, you don't need any events - just the id somewhere, e.g. as a place parameter, or even as a "currentItemId" in the model.
Based on the answer by #Chris Lercher, I used the ProxyEvent. The implementation details are as follows.
In my RequestEditPresenter (the details presenter), I implemented the event handler RequestEditHandler as in
public class RequestEditPresenter extendsPresenter<RequestEditPresenter.MyView, RequestEditPresenter.MyProxy> implements RequestEditHandler{
then in the same RequestEditPresenter override the method in the RequestEditHandler as in
#Override
#ProxyEvent
public void onRequestEdit(RequestEditEvent event) {
getView().setModelToView(event.getRequestModel());
...various other initiation process...
placeManager.revealPlace(new PlaceRequest(NameTokens.initiationedit));
}
Since the Details presenter was a Place, I used the placeManager. For presenters that do not have a NameToken, just call the forceReveal() method
Related
Within the onBeforeRendering() function of a view how should I determine if a specific node is present in the model and modify the model to include the node if not? This question is about lazy loading of data to the model for data that will be infrequently accessed by users but would have a performance penalty if loaded with initial model data.
My use case has a list page leading to a detail page for whatever item in the list the use clicks. On the detail page is a set of tabs which expose sub-details related to the selected detail. Specifically a long text description of a the brief for a task.
The tab control leads via manifest.json style routing to display a view in the tabs content area.
This is my current working code which is within the onBeforeRendering event of the view controller:
onBeforeRendering: function(oEvent){
var sPath = this.getView().getBindingContext("Projects").getPath(); // something like /task/6
console.log('Path='+sPath)
var oModel = this.getView().getModel("Projects");
var oTask = oModel.getProperty(sPath + "/brief");
if (oTask) { // looks like /brief exists so must already have loaded the brief
// nothing to do
console.log('Use existing data')
}
else { // /brief not yet present so we need to load it up
console.log('Load new data')
oModel.setProperty(sPath + "/brief", "This is the brief...") // replace with loaddata() from server, use attachRequestCompleted to call function to modify model.
}}
Question - is this the correct approach?
Edit: Based on discussion in this question I modified my code to use an event that fires per display of the view. onBeforeRendering turned out to run without much apparent predictability - which I am sure it has but in any case I wanted a one-per-display event. Also, I fleshed out the code further but retained the basic structure and it appears to do what I wanted.
This is a valid approach. But you should think aboute following use case: What happens if the data you loaded have been changed at the backend? The JSONModel does not give you any support here as it acts dumb data store only.
I'm creating an Export wizard, including the possibility for the user to choose the format of the export and then to choose the location of the export with WizardNewFileCreationPage.
To do so, I've created 3 pages, one extending wizardPage with a radio to set the next page to call, and 2 others pages pending the format and extending WizardNewFileCreationPage.
It's working almost perfectly, my only problem concerns the "Finish" button, which requires to be clickable that all export format are fulfilled even if I overrided the function isPageComplete to limit the page validation only to the function validatePage.
It looks like the function validatePage doesn't valid only it's own control but also all the control implemented by the class WizardNewFileCreationPage in the Wizard.
Am I going wrong somewhere and does anybody know a solution ?
Regards,
Waldo
The WizardDialog showing the dialog drives button enablement. At various points it calls its updateButtons method. This in turn calls the Wizard canFinish method to set the Finish button state.
The default for canFinish is to call the WizardPage isPageComplete method for every page even for pages which are not currently active.
For WizardNewFileCreationPage the isPageComplete method consults the result of the validatePage method.
So you can override the Wizard canFinish method to only test the pages you care about. Or you can override the individual page isPageComplete methods to return the result you want.
So, I think my problem came from the fact I wasn't implementing canFinish method that's requires in it's default implementation that all page contained in the Wizard are fulfilled. To avoid my problematic, I did it this way :
#Override
public boolean canFinish() {
if (this.getContainer().getCurrentPage() == mainPage)
return false;
return this.getContainer().getCurrentPage().isPageComplete();
}
Note : My "mainPage" attribute is theone defining the format of the export and then the nextPage to use.
Also, I kept verifying if my page was complete this way by calling the WizardNewFileCreationPage this way :
#Override
public boolean isPageComplete() {
return this.validatePage();
}
I'm using page fragments to create a view and in the same page I have two forms to view / update specific information.
What I want know if it's possible to disable one form (or button, since it's the way I use to change from readable to updatable) based on if the other is in updatable mode.
Simplifying I have form A and B, both in the same page as readable. When I select A to update I want B to disable the option to edit until A is back to read mode, and the same to B form.
Can anyone help me?
---Update
Flows
A
B
In each fragment (view) I have a button that as an action to the fragment (edit)
What I need is to disable the button from B.view when A button is pressed and vice versa
If the forms are part of separate taskflows and these taskflows are used on the page as regions, then you will need to enable inter-region communication, so that an action in one region can affect the data and behavior of other region:
http://www.oracle.com/technetwork/developer-tools/adf/adfregioninteraction-155145.html
For your use case, contextual events can serve the purpose:
http://rohanwalia.blogspot.com/2013/07/contextual-events-basic-step-by-step.html
http://www.awasthiashish.com/2013/05/using-contextual-event-in-oracle-adf.html
https://blogs.oracle.com/raghuyadav/entry/refresh_bounded_taskflows_acro
To implement your case, follow the tutorials provided above with following changes:
Pass a boolean value in the customPayLoad of event
<event name="DisableButtonEvent" customPayLoad="${'true'}"/>
In the event handler method assign the payLoad value to a scope variable:
public void handleDisableButtonEvent(String payLoad) {
AdfFacesContext adfFacesContext = AdfFacesContext.getCurrentInstance();
Map pageFlowScope = adfFacesContext.getPageFlowScope();
pageFlowScope.put("disableButton", payLoad);
}
Use the scope variable for disabled property of button on second region
<af:commandButton text="EditButoonB" id="cb1"
disabled="#{pageFlowScope.disableButton ne null? pageFlowScope.disableButton : false}"/>
I have a window with a search form at the top and grid at the bottom.
User can enter values in the search form and click button - Get Records.
At the click of this button, I load the store of the grid by passing the values in form fields as parameters in following way:
store.load({
params:{
key1:Ext.getCmp('field1').getValue();
}
});
I tried giving parameters in the store proxy itself, but it unfortunately always takes up initial values (values when the form is rendered) and not the latest one entered by the users in the form fields. Following is the method I used for assigning values to params while creating the store:
extraParams:{
key1:Ext.getCmp('field1').getValue();
}
I wanted to seek guidance at two things:
a. While defining a store, can I ensure that store takes latest/current values from the form fields before querying server, so that I don't have to provide these values while calling load function?
This becomes more necessary as I have a paging toolbar at the bottom which carries a refresh button (along with next, last, previous, first icons for navigation).
Now, whenever user clicks at refresh (or any navigation icon), the store gets loaded without the query parameters.
Thus the second thing is:
b. If the answer of 'a' is that - Pass the latest values to parameters manually when calling load function - then how can I write the handler for 'refresh' button and navigation icons (that is, next, last, previous and first) in the paging toolbar, so that I can pass the latest form values to load function.
Thanks for any help in advance.
PS: I am using ExtJS 4.
yourStore.on('beforeload',function(store, operation,eOpts){
operation.params={
status:cmbStatus.getValue(),
value:txtBuscarPor.getValue(),
empresa:'saasd',
app:'dsads'
};
},this);
Related to your question (b) (and because you especially asked for this in the comments section):
I see only one standard way to hook into the PagingToolbar button handlers which is very limited.
Ext.toolbar.Paging fires a 'beforechange' event before it actually changes the current page. See API docs. A listener that returns false will stop the page change.
All other methods require extending Ext classes which wouldn't be a problem if the ComboBox would make it easier to use your own implementation of BoundList (which is the class that renders the dropdown) or pass through config parameters to BoundList resp. the paging toolbar.
I tried to bring this lack of flexibility up on the Ext message board once but was pretty much ignored.
A possible solution for this is to use 'beforeload' event of the store and provide the list of parameters in it. This way, whenever the store is loaded, then its beforeload event is fired and the values picked up are always the latest. Hope this helps someone looking for something similar.
I've followed the Wicket by Example guide to get the ObjectAutoCompleteField working, and it does so quite nicely.
I have a huge problem, though, and that is to show an initially set object in the field when the page loads. The object is retrieved from a model I use for the form where the ObjectAutoCompleteField is used. Changing the ObjectAutoCompleteField changes the model attribute it is "connected" to, and any subsequent changes in the field shows the appropriate label in its place, just not the initial one when the page loads—the only thing that shows is the edit link (to get to the autocomplete functionality).
I've looked around in the documentation for the ObjectAutoCompleteBuilder but haven't found any corresponding method to even set the initial value explicitly on page load.
I finally managed to find a solution by looking through the classes relating to ObjectAutoCompleteField.
The ObjectAutoCompleteField is constructed by the build method in ObjectAutoCompleteBuilder. So, by calling the readOnlyRenderer method on the builder, creating a new ObjectReadOnlyRenderer creating a label inside its getObjectRenderer, I got the ObjectAutoCompleteField to render a preselected object on page load.
ObjectAutoCompleteBuilder<Author, Long> builder = new ObjectAutoCompleteBuilder<Author, Long>(provider);
builder.readOnlyRenderer(new ObjectReadOnlyRenderer<Long>() {
public Component getObjectRenderer(String id, IModel<Long> pModel, IModel<String> pSearchTextModel) {
return new Label(id, new PropertyModel<Author>(model, "author"));
}
});
One would think that this was the standard behaviour, but now I know for future reference.