How do i pass an Entity from selected row in rowtemplate to AbstractEntityListProvider - codenameone

I have fetched data and populated in view using provider and rowTemplate.
Upon clicking the row, I want to pass the entity to another provider which will trigger getRequest with the values of the entity.
How do I go about passing this selected entity to the provider?

You can do this by adding a lead component button to your row, and bind it to an action, so that it triggers an action which will be caught by your controller. Your controller will contain the logic that does something with this event, such as passing the entity to a provider.
I've created a github repo with a small example of this here:
https://github.com/shannah/coderad-entitylist-sample
The key parts. The view:
<define-category name="ROW_CLICKED" />
...
<entityList layout-constraint="center"
provider="com.example.myapp.providers.SampleListProvider.class"
>
<row-template>
<y rad-leadComponent="ClickMeButton">
<radLabel tag="UserProfile.name"/>
<button uiid="ClickMeButton" hidden="true">
<bind-action category="ROW_CLICKED"/>
</button>
</y>
</row-template>
</entityList>
Notice the define-category tag, which defines a ROW_CLICKED action category, which we will use in our button.
Next, inside the <row-template> we wrap the row in a container. I use a <y> container, but you can use any type. The key is the rad-leadComponent="ClickMeButton" which will pipe all events for the container to the child component with uiid "ClickMeButton", which will be our button.
Then the Button has a bind-action with our ROW_CLICKED category, so that it will fire events up to our controller.
In the controller:
protected void initControllerActions() {
super.initControllerActions();
addAction(StartPage.ROW_CLICKED, evt-> {
evt.consume();
UserProfile profile = (UserProfile)evt.getEntity();
Dialog.show("Hello", "You clicked " + profile.getName(), "OK", null);
});
}
So you can see that we can get the entity from the event. Here I just show a dialog with some entity details, but you could alternatively pass the entity to another provider.

Related

Can I keep the model value when click browser back button with angularjs?

I am new to AngularJS, I have a dropdown and a link. When I click the link, Anagularjs will route a different view (for example, display a chart and table).
Then when I click browser's back button, the dropdown will show the default value, other than the value I selected before.
Is it possible to let AngularJS remember the selected value of my dropdown when the link is clicked when I click browser's back button?
<select ng-model="selectedManagerFilter" ng-init="selectedManagerFilter= selectedManagerFilter || '*'"
ng-options="item.Code as item.Name for item in ManagerFilters" id="lstManagementGroup" name="lstManagementGroup"></select>
Your scope will get cleared when you exit the page and recreated with the default values when you get back to it.
You have 2 options:
use a Service to keep this kind of information (like selectedItem from your dropdown) and other useful things. The option selected in the dropdown should be bound to the service object:
angular.module('shared').factory('UsefulService', function() {
var UsefulService = {};
UsefulService.myPageSettings = {
currentDropDownItem: 1, //this is what you need
otherSetting: "blah"
};
return UsefulService;
});
and in your controller you should bind the scope variable to it (don't forget to require the UsefulService in your controller's dependencies):
$scope.myDearSettings = UsefulService.myPageSettings;
and then access it with $scope.myDearSettings.currentDropDownItem;
you can set a hash on your route when the dropdown changes (bound to the value) so when you hit Back you will get to the same state because of the hash. Basically, the url in your address bar will look like: http://your_server:your_port/myPage#Today where Today is the selected item.
The most recommended solution is option #1.

Backbone.Collection.reset() => child view is out of sync with parent

I have a list of items. They are stored in backbone pageable collection.
They are displayed like this
|---item1---------------------------|
|---item2---------------------------|
|---item3---------------------------|
|---item4---------------------------|
|---item5---------------------------|
|---item6---------------------------|
|---item7---------------------------|
<< 1,2,3...end >>
User can click on individual item to open detail view in a separate page. Detail view has listeners initialized
when it's created. Those listeners are bound to the item model.
Since the detail view is huge, I cache it in the DOM by toggling the visibility.
The subsequent click on the item will toggle the cached view.
------ here is the problem -----
When item list is switched to another page, the collection is reset (by paginator). And all the models previously stored in the collection is dereferenced and
a new set of models is created. So after the page is switched back and forth, the previously opened item has a different copy of itself stored
in the collection. So when I change the name of the item in the detail view (in the view cache), the name in the item list is not changed.
The views are out of sync! because they are referencing to different models.
Not sure if anyone else encounter this before. If you do, please share with me how you solve it.
Thanks very much.
The most straight-forward way to maintain a fresh reference between your list view items and the corresponding detail view, on page change, is to re-render the detail view. But I'm assuming this options is not acceptable within the scope of your project.
What I often do, when I have the task of forming relationships within logically separate views is use listeners. As long as the views share a unique identifier (for example, they both share a model, or at least identical model ids), I can always send a message that will reach the view I'm interested in.
For this you'll need a centralized event hub, which with Backbone is trivially easy to generate. In some appropiately global variable (like, for example, MyApp) we simply do:
MyApp.EventBus = _.extend({}, Backbone.Events);
Set up the detail view
On the detail view initialize function I would drop this listener,
initialize: function () {
// Listen to a toggle visibility on this view
this.listenTo(MyApp.EventBus, 'detail-view:toggle-view', toggleView);
},
toggleView: function (id) {
if (this.model.id == id) {
// Show this view if I have the passed id
this.$el.show()
// Notify the parent list item view that its detail view exists
MyApp.EventBus.trigger('detail:view:exists', true);
} else {
// Hide all other views
this.$el.hide();
}
},
changeName: function () {
// logic that parses DOM user input to
// local variable name
// We now trigger an event 'detail-view:change:name', and we send as
// parameters our model's id and the new name
MyApp.EventBus.trigger('detail-view:change:name', this.model.id, name);
}
Setting up the list item view
The list item view will want to listen to a name change (or any other model property in the detail view that you want the list item to be aware of). So we'll set up a handler for the 'detail-view:change:name' event.
We'll also want to wire our click handler to toggle the visibility of the list item's detail view. The tricky part is to handle the event that a view has not been rendered yet (I'm assuming you're lazy loading the detail view). So we set up a second listener for the detail:view:exists event the detail view triggers when it catches a detail-view:toggle-view event. If we don't hear the detail:view:exists event from the targeted detail view in a timely manner (I'm using 100 ms, but you can play around with that to suit your needs), then we render the view.
initialize: function () {
// Listen to when the detail associated with this list item changes
// the the list item name
this.listenTo(MyApp.EventBus, 'detail-view:change:name', onNameChange);
// Set a property in this view if its detail view exists
this.listenTo(MyApp.EventBus, 'detail:view:exists',
_.bind(function () { this.detailViewExists = true; }, this));
// Create a debounced function that tests whether this view's
// detail view exists
_.debounce(_.bind(this.handleViewState, this), 100);
},
events {
click: 'toggleDetailView'
},
toggleDetailView: function (id) {
MyApp.EventBus.trigger('detail-view:toggle-view', this.model.id);
this.handleViewState();
},
// Debounced function that will wait 100ms asynchronously for the
// detail view to respond. If the detailViewExists bit is not set to true
// then we assume the view does not exist and we render it
handleViewState: function () {
if (!this.detailViewExists)
// The view does not exist, render and attach the view
// Set the bit to false to allow testing in the event that the detail view
// is destroyed in the future
this.detailViewExists = false;
},
changeName: function (id, newname) {
if (this.model.id == id) {
// Change the name of this list item view
this.$('.item-name').text(newname);
}
The take-away
Now, the reference between these two disparate views is the shared unique identifier. Since, by design, these two identifiers are unique in their scope, and should not change, and assuming the detail view has been rendered and attached to the DOM, then regardless of the rendering its state the list item view will always be able to communicate with its detail view.

adf declarative component custom methods queueEvent() not working

I am using Oracle ADF JDev 12.1.3
I have a custom declarative LOV component and one custom method "valueChangeEvent",
after user select some values from the popup, i will do some validations, if all validations are ok, then I need to raise "valueChangeEvent" event,
so that in the final jspx page additional logic's can be implemented,
My declarative component method definition as follows
<method-attribute>
<attribute-name>
valueChangeListener
</attribute-name>
<method-signature>
java.lang.Void method(javax.faces.event.ValueChangeEvent)
</method-signature>
<required>
false
</required>
</method-attribute>
In my custom LOV Component, i have one input text and button, I tried the following to invoke my custom method within the command button action, but it does not invoke the event at the main form, but no error shows
// get the component reference using Face Context ValueExpression
_this = getThisDeclarativeCompoent();
//try to queue the valueChangeEvent - but this does not work
_this.queueEvent(new ValueChangeEvent(_this, NewValue, OldValue));
Consuming application code is as follows
<af:declarativeComponent viewId="/ASGLOVBrowser.jspx" id="dc3" label="Modules" LOV_Name="MODULE"
bindingAttribute="#{bindings.ModuleId}" showDescription="true"
multiSelect="false" matchingField="CODE"
valueChangeListener="#{viewScope.DeclarativeTestBean.test_valueChangeEvent}"/>
appreciate if someone can help...
Value Change event is raised by the framework only, when input value changes, therefore you can't initiate the event without the value being changed either from UI or programatically.
So, you can get a reference of the input text UIComponent and change the value programatically:
RichInputText uiComp = <<<get reference>>>;
uiComp.setValue(newValue);

Adobe CQ EXTJS component data post to servlet

I got a EXTJS CQ component with two text fields and and button.
When the "save" button clicked, the dialog data has to be submitted to custom sling servlet.
Custom sling servlet will call a osgi service and finally saves data to crx using jcr api.
Question : How to post the dialog data to servlet ?
I am new to CQ, Thanks for any help!
-Sri
I'm assuming when you say "save" you are referring to some custom button and not the "OK" button that saves the dialog data to the node.
Add a handler to the save button. The handler function must retrieve the dialog object, loop over all the fields in it and post the values to your custom servlet. The handler should be something like this
function(button,event){
//fetch dialog using the save button
var dialog = button.findParentByType('dialog');
var params = {}; //parameters to post
var textfields = dialog.findByType('textfield'); //returns all textfields in the dialog
for(i=0;i<textfields.length;i++){
params[textfields[i].name] = textfields[i].getValue(); //add the value to params with name same as the name you have provided to the textfield
}
$.post( "path to your servlet" , params ); // you can also use CQ.shared.HTTP of cq's ext js package to do the post
}
In case all you want to do is post the form data on clicking the "OK" button that comes by default, set the formurl property of the dialog to the path of your custom servlet. In this case if the values aren't stored back as properties with appropriate names on the corresponding node like a dialog normally does, the dialog will not be able to load the values when the component is re-edited.

undelegating events handlers on 'lose-focus'

I am trying to phrase this as clearly as I can.
I have a view that shows a form. I am tying an event handler to the submit button like this:
events: {
'click #bsubmit': 'save'
}
In the save function, on success, I take care to undelegateEvents() before I navigate away:
...
that.undelegateEvents();
window.router.navigate('#/home');
...
So if someone comes to this page, submits the page and goes to (actually: is sent back) the home page, is all good.
However, there is also a 'home' link shown there, which part of the top level template. It is specified like this:
Home
So if someone comes to this page, clicks on the home link, and (from there) returns to this page, the event is mapped a second time. Now when someone submits the form, it gets submitted two times.
Given that I have many views, and the navigation away can happen in many ways, what is the common pattern to undelegateEvents when navigation happens at a higher (uncontrollable) manner? Or am I doing something fundamentally wrong?
In your case you don't need to undelegate events. Simply remove your form from the DOM with $('el').remove(), javascript events will automatically be removed
The best solution would be to have a HomepageView and FormView each in the same container (let say .container).
Example of a complete scenario:
User go to #homepage, we instanciate a HomepageView and render it in .container
User go to #form, we instanciate a FormView and render it in .container
User go to #homepage, we instanciate a HomepageView and render it in .container
...etc, etc
So, each time the user navigate to a new route the previous view is replaced by the new one.
As the previous view HTML no longer belongs to the DOM you don't need anymore to undelegate events.
Of course the .container element do not belongs to our views, each view has it's own element rendered inside the .container element.
Read this blog post for more informations.

Resources