Rich Picklist + A4j Support + onlistchange - ajax

There are a weird behavior happening when I use rich picklist component attached to an a4j support onlistchange event.
If I have "n" selected items into picklist component, the server will try to populate it "n" times (running gruposDeTributosQuery.resultListOrdered() "n" times!!!)!
This causes a hard delay, because the query used to populate is a little bit slower...
Above is my code:
<rich:pickList id="picklisttributos" value="#{criarEstudo.tributosDoAssuntoList}"
label="Tributos" >
<s:selectItems var="_tributos" value="#{gruposDeTributosQuery.resultListOrdered}"
label="#{_tributos.nome} | #{_tributos.id}" />
<s:convertEntity />
<a4j:support event="onlistchange" process="picklistOF" reRender="picklistOF" />
</rich:pickList>

Bizarre.
New discover...
The problem is gruposDeTributosQuery.resultListOrdered!
public List<Tributo> getResultListOrdered() {
this.setOrder("nome");
//ArrayList<Tributo> lista = new ArrayList<Tributo>(
// this.getResultList());
return this.getResultList();
}
If I use direclty resultList this bahavior doesn´t happen!

Related

<ui:inputText> keyup returns incorrect value (one less)

I am using in one of the lightning components and I am using it to filter a table. But when I'm trying to get its value in JS controller with the keyup function, it's giving one less value than actual.
This question has been already asked for HTML here , But for HTML, we have a solution that we can use onkeyup instead of keyup.
But in salesforce lightning, we don't have any onkeyup function for ui:inputText Source ,
So how to solve this issue?
I have already tried keypress, keyup, keydown.
All are giving one less value than actual one
Component :
<ui:inputText aura:id="search-phrase" class="slds-input" keyup="{!c.filterTable}" placeholder="Search Table" />
JS Controller :
, filterTable :function(component, event, helper) {
var dynamicVal = component.find("search-phrase");
var week = dynamicVal.get("v.value") ;
alert((week+'').toLowerCase());
var searchTerm = (week+'').toLowerCase() ;
$('#userTbl tbody tr').each(function(){
var lineStr = $(this).text().toLowerCase();
if(lineStr.indexOf(searchTerm) === -1){
$(this).hide();
}else{
$(this).show();
}
});
}
I found it's solution.
Just need to add updateOn="keyup" in <ui:inputText>
So new one will become :
<ui:inputText aura:id="search-phrase" class="slds-input" updateOn="keyup" keyup="{!c.filterTable}" placeholder="Search Table" />
Include updateOn attribute to ui:inputtext control. By default, it is mapped to change event so you will get only the exact value when the change event fires. updateOn="eventName"
event details : enter link description here

onClick Event on Element in customComponent

I am currently deep diving into JSF and I have a question.
I am using JSF 2.2 (Mojarra 2.2.9) in a small application. I have build a custom component to render a data structure as a menu. The code looks like something like this:
#FacesComponent(createTag = true, tagName = "UIRecursiveTree", namespace = "")
public class UIRecursiveTree extends UIComponentBase {
#Override
public String getFamily() {
return "";
}
#Override
public void encodeBegin(FacesContext context) throws IOException {
}
private void writeFolderStructure(Map<IContainer, ?> map, ResponseWriter writer, String prefix) {
}
}
I have stripped some code out and of course I have set the family and the namespace, just hid it. The control has a value attribute which receives a LinkedHashMap which is rendered in my application.
Everything works fine. Currently I am just printing some labels with a ResponseWriter which represent my structure. Problem is, the structure can be quite big and the mechanic to load the structure is not ideal, at least if I am loading everything at once, which takes ages.
So, my idea is that I want to bind my elements (currently just labels but will be replpaced by links or something like that) to an onClick event, which triggers the component to load itself again with new values (Ajax) (fetch the child elements of the current element and add them to my structure so that the values are only loaded when they are needed)
I know there are maybe some controls in some libraries which I could use to map such a structure, but I am learning JSF and using things already done teaches me nothing. =)
So, the question is, how can I bind an onClick event to my elements to force the component to refresh itself?
Thanks in advance.
after a bit of back and forth, I was able to solve my problem.
I delayed the "do it completely yourself" course and used the tree control from PrimeFaces.
<p:tree id="treeMap" value="#{treeView.root}" var="container" dynamic="true" selectionMode="single" selection="#{treeView.selectedNode}">
<p:ajax event="expand" update="treeMap" listener="#{treeView.onNodeExpand}" />
<p:ajax event="select" update=":form" listener="#{treeView.onNodeSelect}" />
<p:treeNode expandedIcon="ui-icon-folder-open" collapsedIcon="ui-icon-folder-collapsed">
<h:outputText value="#{container.getName()}" />
</p:treeNode>
<p:treeNode type="dummy" icon="ui-icon-video" rendered="false" styleClass="hidden" />
</p:tree>
<h:commandButton value="Reset Tree" action="#{treeView.reset()}" />
I use those actionListeners to build up my tree.
Initially I only fetch the first level of item, which is the root. Everything else is loaded when I expand the node. To be able to expand the node (I need a child node under the root node) I add a dummy node under every node. When I click on the expand symbol I fire the onExpand listener. This method calls my service which fetches the child nodes of the current node and puts them under the node in my bean and refresh the tree. That way I can build up my structure when I need the child nodes. The only problem is that of curse under every node there is a dummy node. I delete the dummy when I have expanded the parent node, but without a full refresh there is a expand icon in front of every node, no matter whether there is actually a node under it or not. But in my case that's not that important.
I hope I could help someone who is looking for a similar solution.

Exclude an id from update

Can I exclude a specific id from update=":myComponent"?
I have a larger page (with several tables, input fields and so on) which is wrapped in a <p:panel id="outerPanel">. Most of the time, I just execute update=":outerPanel", which works quite fine. But now I'm facing a problem that I have to update the page except for ONE table.
How can I exclude that table (or any component in general) from an update process?
If the ID not to refresh can be identified by some logic (i.e.:
if(myVar==1) { idToExclue = 'id1';}
else // ... etc
Then you can try building a JSF call using the jsf.util.chain: (Note this uses Mojarra JSF impl.)
function myJsfSubmit(callerElement) {
var myIdsToSubmit = 'main-form:id-to-refresh-1 main-form:id-to-refresh-2';
// put your logic to exclude the desired ID here
// ...
// then
jsf.util.chain(callerElement,null,'mojarra.ab(this,event,\'action\',
\'main-form:id_to-submit\',\'+ myIdsToSubmit +\')');
return false;
}
And use that above function on the onClick() or onSubmit() of your form or component:
<h:commandButton onclick="myJsfSubmit(this)" />
No, I think that is not possible from the facelet. On the server side you could manipulate the ajax request, but I don't think that is what you want.
Maybe your view allows to wrap some h:panelGroup around the parts to update.

Cancel JSF ajax call

I have an f:ajax tag inside an h:inputText tag, making ajax calls on keyup events :
<h:inputText id="searchinput" value="#{tvShowForm.name}">
<f:ajax event="keyup" render="results" listener="#{tvShowForm.search}" />
</h:inputText>
Each call takes enough time that the user has typed several characters before the first call is finished.
Is there a way to cancel the current ajax call (and the queued up ones), so that the last keyup event executes an ajax call immediately?
It sounds like you want to coalesce the events, for example this will wait
half a second before firing an ajax request, and any input typed at that
point will be included. But you won't fire an ajax request for each character
typed.
<h:inputText onkeyup="keyupHandler();"/>
...
<script>
var keystrokeTimeout;
keyupHandler = function(event) {
var minChars = 4;
var len = $(this).val().length;
if((len != 0) && (len < minChars)) {
return;
}
var ajaxRequest = function() {
jsf.ajax.request('results', null, {
execute: 'results',
render: 'results'
});
}
clearTimeout(keystrokeTimeout);
keystrokeTimeout = setTimeout(ajaxRequest, 500); // millisecs
}
</script>
Is this remotely like what you want to do?
EDIT: Another suggestion is that you check out the Richfaces 4 a4j:queue functionality.
This allows for combining events, for example in the keyup scenario if you've been
leaning on your keyboard, when the current ajax request completes only one further
request will be sent. It's also possible to specify a request delay and ignore stale
responses. The big mistake Richfaces doesn't make (that primefaces does make) is that
RF uses the same underlying queue as the JSF implementation, so you don't have the risk
of out-of-order processing.
I appreciate that if you're not already using this library it's not a small step to take.

Telerik RadGrid OnRowSelected Events, all done event for multiple selection?

I have a RadGrid with multiple select enabled:
<telerik:RadGrid runat="server" ID="RadGrid1" AutoGenerateColumns="false" AllowMultiRowSelection="true">
<MasterTableView TableLayout="Fixed">
<Columns>
<telerik:GridBoundColumn DataField="Dialog" HeaderText="Dialog" DataType="System.String" />
</Columns>
</MasterTableView>
<ClientSettings EnableRowHoverStyle="true">
<Selecting AllowRowSelect="True" />
<ClientEvents OnRowSelected="RowSelected"/>
</ClientSettings>
</telerik:RadGrid>
And the OnRowSelected event triggers for each row selected. When selecting 10 rows, the event gets fired 10 times. Simple enough.
My question is what event can I listen to to know when all the rows that are going to be selected are selected (as a result of the multiple selection)? I need to make a post request with the ids of the selected rows and I don't think it's a good idea to let 10 post request be made. I can query the grid to get the selected rows, I just need to know when to do it; ideally something that doesn't involve timeouts. There must an event for this that I'm overlooking.
Got something working with timeouts:
var rowSelectedTimeout;
function RowSelected(rowObject) {
if (window.rowSelectedTimeout) {
// If selecting multiple rows, clear the previous row's rowSelectedTimeout
window.clearTimeout(window.rowSelectedTimeout);
}
rowSelectedTimeout = window.setTimeout(function () {
window.rowSelectedTimeout = null;
alert('rows selected');
}, 10);
}
The trick here is really how to figure out when the user has "stopped" selecting. If the multiple selection is done via a shift+click then sure, you have a lot of items to go through, but what if you have the same number of items (10) and the user ctrl+clicks each one of them? It can very easily become a bit over-complicated. There unfortunately isn't an event in the RadGrid that you can subscribe to that triggers after a multiple select action has finished selecting all rows.
Your best option here would probably be to have an external button or something similar that would trigger this post, and then use the SelectedItems collection of the RadGrid since this would then allow for a more batch approach instead of posts occurring for every row.

Resources