How can I expand a rich:collapsibleSubTable with expandMode="client" via Javascript?
As I understood, the usual way to expand the subTable would be to either use the expanded-attribute
<rich:collapsibleSubTable
value="#{list.items}"
var="item"
expandMode="client"
expanded="true">
<rich:column><h:outputText value="#{item.model}" /></rich:column>
</rich:collapsibleSubTable>
or use the rich:collapsibleSubTableToggler. But because we have the need to open every second sub-table on a datatable, I'm looking for a way to do that via javascript on client-side. Is there a way, to trigger the expand via the javascript RichFaces object or anything? Help appreciated...
The subTable has collapse() and expand() methods.
If you need to access all subtables you can do it with jQuery:
$('[id$=sbtbl]');
then as you go through the elements, the JS object that represents the table is:
element.rf.component; // element = $('[id$=sbtbl]')[n];
Related
I'm still developing my data table UI application, and finally I'm about the final stage of the development of this component: inline cell editing.
First of all, the data table is built fully dynamically at the Java side, and no facelet declarations are used to describe the table. If I'd have a static table declaration, the editing could be specified like this (see the In-Cell Editing chapter):
<p:dataTable>
...
<p:ajax event="rowEdit" listener="#{tableBean.onEdit}"/>
...
</p:dataTable>
I can easily specify the data table editable with dataTable.setEditable(true) in the Java code - and it works, please note, the editing Save/Cancel icons are working nice but have no effect at the back end. Since I cannot it declare in the way specified at the PF ShowCase Labs page (must I always use the listeners there?) because of the data tables are rendered dynamically, I'm trying to use the following:
public static AjaxBehavior createAjaxBehavior(MethodExpression expression) {
final AjaxBehavior behavior = new AjaxBehavior();
behavior.addAjaxBehaviorListener(new AjaxBehaviorListenerImpl(expression));
return behavior;
}
...
dataTable.addClientBehavior("rowEdit", createAjaxBehavior(createMethodExpression(TableBean.class, "onEdit", void.class, new Class<?>[] {RowEditEvent.class})));
But as soon as I add the rowEdit listener, like I'm trying to do above, and wow I suddenly got: mojarra is not defined and no Save/Cancel row edit buttons are working. Ok, I've found a similar problem described and resolved here, included the necessary script manually, and now the client-side JavaScript error is gone, however I still cannot exit the row editing mode, and the row is still not updated.
I wasted all day trying to figure out what's going on, and I'm blind to see the correct way. Do I simply miss something behind (like identifying a certain row, or probably specifying something else somewhere -- but my Java code does not generate anything more than specified in the PF example), or anything whatever?
Thanks in advance.
Well, I've just figured out the real reason in the following method:
public static AjaxBehavior createAjaxBehavior(MethodExpression expression) {
final AjaxBehavior behavior = new AjaxBehavior();
behavior.addAjaxBehaviorListener(new AjaxBehaviorListenerImpl(expression));
return behavior;
}
In fact, the method actually returned javax.faces.component.behavior.AjaxBehavior (h:ajax?) instead of org.primefaces.component.behavior.ajax.AjaxBehavior (p:ajax) -- this happened because of quick auto-complete so I simply missed that fact.
I'm frustrated that the PrimeFaces library didn't reply any error.
Just to complete the Q & A:
Mojarra 2.1.7
PrimeFaces 3.2
Should now (at least for PF 6.0) be org.primefaces.behavior.ajax.AjaxBehavior.
My specific usage case is that I'm using a .net postback to display an update panel of elements that have tooltips associated with them. I have already initialized the ZURB Foundation (provides tooltips) script on the page, and the first-page tooltips work great. After the postback, I want to *re*initialize the script so that these new tooltip items are bound to the 'hover' event.
Generic usage case is any situation where new tooltip-enabled elements are added in any way.
It appears to me that the 'hover' binding is done on page init to the existing collection of '.has-tip' elements, but there is handling of future .has-tip elements coming into existance.
I'd like to do the following:
a) Reinitialize the tooltip plugin and search for new .has-tip elements to attach the 'hover' event to.
have tried a number of different ways to try and reinitialize, but
$.fn.tooltips('init');
seems to be the most hopeful, in that it successfully calls the init method in the script, but does not bind the hover event to the new .has-tip elements.
Edit/Clarification:
it seems like there was a bug with dynamic content:
https://github.com/zurb/foundation/pull/465
When the bug is fixed
(you can fix it yourself, read the pull req. for more info), the bug is fixed, so you can
trigger a page-wide tool-tip refresh with:
$(document).tooltips('reload');
Original answer
If you didn't figure it out yet, jquery.tooltips.js has a method/function called .reload that actually seems to be the most promising (code is from the foundation plugin):
reload : function() {
var $self = $(this);
return ($self.data('tooltips')) ? $self.tooltips('destroy').tooltips('init') : $self.tooltips('init');
},
It's really just a chain of their other methods, but it's probably best to .destroy before .init to avoid double tooltips or some other collision.
I have tried a lot of suggestions, but what truly works is:
After you finish editing the DOM, you have to call to
$(document).foundation();
This sentence is going to refresh everything, including your tooltips. WORKS LIKE A CHARM.
I had the same problem when genereted modal windows with Ajax,
Here is my fix for that:
$(document)
.on('opened.fndtn.reveal', '[data-reveal]', function () {
$('html').css({'overflow': 'hidden'});
$('.has-tip').each(function(i){
var tip = $(this);
Foundation.libs.tooltip.create(tip);
});
})
It works for ZF v5.2+
I've just updated my project from jquerymobile 1.0a1 to version 1.0.
I've encountered a problem with dynamic content. Based on an ajax search I populate an unordered list with list items. Previous the following code refreshed the list so that all the styling appeared correctly:
$('#myContent').find("ul").listview();
$('#myContent').find("ul").listview('refresh');
However as of 1.0 this no longer seems to work.
The list appears but the styling is all wrong and the data-theme on all the elements gets ignored.
Has anyone come across a similar issue with updating and come across the solution.
Updating lists If you add items to a listview, you'll need to call the refresh() method on it to update the styles and create
any nested lists that are added. For example:
$('#mylist').listview('refresh');
Note that the refresh() method only affects new nodes appended to a
list. This is done for performance reasons. Any list items already
enhanced will be ignored by the refresh process. This means that if
you change the contents or attributes on an already enhanced list
item, these won't be reflected. If you want a list item to be updated,
replace it with fresh markup before calling refresh.
http://jquerymobile.com/demos/1.0/docs/lists/docs-lists.html
if #myContent is the listview you can do this:
$('#myContent').listview('refresh');
if #myContent is the page you can do something like this:
$('#myContent').trigger('create');
Create vs. refresh: An important distinction Note that there is an important difference between the create event and refresh method
that some widgets have. The create event is suited for enhancing raw
markup that contains one or more widgets. The refresh method should be
used on existing (already enhanced) widgets that have been manipulated
programmatically and need the UI be updated to match.
For example, if you had a page where you dynamically appended a new
unordered list with data-role=listview attribute after page creation,
triggering create on a parent element of that list would transform it
into a listview styled widget. If more list items were then
programmatically added, calling the listview’s refresh method would
update just those new list items to the enhanced state and leave the
existing list items untouched.
http://jquerymobile.com/demos/1.0/docs/pages/page-scripting.html
What you want can be achieved by replacing your 2 lines of code with the following:
$('#myContent ul').listview('create');
Hope this helps...
I've had this issue. The reason you are getting things all messed up is you are initalizing and refreshing the element multiple times. I noticed I had 2 different functions running that would call .listview('refresh') on the same element. After I took one out the themes and data went back to looking normal. Also are you getting any JS errors?
EDIT:
To be more specific you are calling .listview() somewhere in your code 2 times which is initializing it twice. I would wait to before you page is loaded to run the refresh so you only call it once.
Another thing you could do is check if the element is initialized already or not so you don't do it twice. Just check the element or in some cases the parent to see if the class ui-listview is present.
var element = $('#myContent').find('ul');
if ($(element).hasClass('ui-listview')) {
//Element is already initialized
$(element).listview('refresh');
} else {
//Element has not been initiliazed
$(element).listview().listview('refresh');
}
Just an FYI you can chain those events to look like $('#myContent').find('ul').listview().listview('refresh');
It cand be achived through.
$('#myContent').listview('refresh');
The below snippet shows you to load data from xml and dynamically create a list view.
function loadData()
{
$.ajax({
url:"BirthdayInvitations.xml",
dataType: "xml",
success: function(xml)
{
$(xml).find("event").each(function()
{
$("#mymenu").append('<li>' + this.textContent + ' </li>');
});
$("#mymenu").listview('refresh');
}
});
}
See if this is related to ur question http://www.amitpatil.me/demos/jquery-mobile-twitter-app/ and this one also http://www.amitpatil.me/demos/ipad-online-dictionary-app/
In first example i am using listview('refresh'); method and in second example i am using
$(document).page("destroy").page();
In two other questions (here and here) BalusC makes a straight up declaration:
Getters are solely there to access bean properties, not to do some business logic. There you have the bean constructor, initialization blocks or event methods for. All are executed only once during bean's life and that's exactly what you want.
Well gee -- this just invalidated a gazillion lines of code I have already written. Ok, then, what is the correct way of implementing a backing bean that fills a data table? I understand his point and the concept, but not the practice. My question is twofold:
Why is the way I am doing it wrong?
How do I fix it?
I use PrimeFaces p:dataTable a lot, and it's value attribute resolves to a collection. For reasons I don't go into here, I do not use PrimeFaces' lazy table loading feature. Instead I implement my own filter/sort controls, but they trigger AJAX events, which then results in the table being filled with records fetched from the data base.
The table is marked up like this:
<p:panel id="mqTable">
<h:outputText value="Sort/Filter: #{maintCategory.tableQueryParameters}" />
<p:dataTable
id="mqDataTable"
rows="#{maintCategory.pageSize}"
value="#{maintCategory.dataModel}"
selection="#{maintCategory.selected}"
var="cat"
selectionMode="single"
emptyMessage="No Categories Found">
Now the INCREDIBLY BAD UN-JSFish (or so I just found out) getter for dataModel goes like this:
public ATMDataModel getDataModel() {
TableQueryParameters p = getTableQueryParameters();
if (p.isChangePending()) clearDataModel();
p.setChangePending(false);
if (dataModel != null) return dataModel;
List<ET> list = getDAO().runQuery(p);
if (p.isNeedResultSize()) p.setResultSize(getDAO().runQueryCount(p));
dataModel = new ATMDataModel(list);
return dataModel;
}
A few explanations.
This is from an abstract super-class where ET is the "Entity Type." All my CRUDs use this same routine.
The class ATMDataModel is a wrapper for the list which implements SelectableListModel. The row selection logic in PrimeFaces requires this. (It is a pain that appeared in PF 3 but it makes row selection work more reliably.)
The class TableQueryParameters is something I wrote to encapsulate the current state of the table on the user's screen. It includes what sort parameters, what filter parameters, what page we are on, etc. Because this needs to be preserved, the backing bean is ViewAccesScoped (via MyFaces CODI) and the TableQueryParameters is a property within it.
The TableQueryParameters are updated in response via AJAX events, which also update the form causing getDataModel to be called. The method isChangePending goes true when anything changes. So the getDataModel method uses this to generate only one fetch from the DAO between changes no matter how many times it is called.
BUT if the TableQueryParameters do change, I have to call runQuery with those parameters to fetch the new set of records the user wants to see. If I don't call it in getDataModel where do I call it?
Please advise.
You're basically lazily loading the data in the getter. You're not hitting the DB on every getter call within the same request (or view) scope. This is affordable. I don't use CODI, but I'd imagine that the getTableQueryParameters() call is also particularly cheap and nothing to worry about.
As to the concrete question, you'd normally do the DB/business job in an action(listener) method which is attached to the UICommand component and/or the ajax event tag.
For example (works also as <p:commandButton action> though)
<p:ajax listener="#{bean.deleteSelectedRow}" />
...
<p:ajax listener="#{bean.saveRowDetail}" />
with
public void deleteSelectedRow() {
someService.delete(selectedRow);
dataModel = loadDataModel();
}
public void saveRowDetail() {
someService.save(selectedRow);
dataModel = loadDataModel();
}
Depending on the meaning of p.isChangePending(), I think you could also get rid of it this way, it look like that you were setting it in the action(listener) methods.
I am relatively new to jQuery and web development.
I am using jQuery UI Tabs to create tabs.
But I want the contents to be loaded only when I select a particular tab.
OK, I assume when the user clicks a tab, you intend to fetch content dynamically, via AJAX. This really involves two things, setting an onclick even for your tab and fetching the data via ajax.
Setting an onclick event
Give your tab an class, for example my_tab. Let's say that when the user clicks the tab you want the handle_tab_click() function to fire. Here's an example of binding the onclick event to your my_tab tab:
$(".my_tab").bind("click", handle_tab_click);
Your handle_tab_click() function will be given an event argument which will be able to provide you with information on the element that fired the event (in this case, the element with class name my_tab).
function (event) {
if ($(event.target).hasClass("my_tab")) { /* handle tab click */ }
if ($(event.target).hasClass("my_tab_2")) { /* a different tab click */ }
if ($(event.target).hasClass("my_tab_3")) { /* ... */ }
}
See the JQuery event documentation for more details here.
Fetching the data via ajax
Fetching data will require you to invoke a remote script while supplying information about which tab was clicked (in order to fetch the appropriate information). In the following snippet, we're invoking the remote script myscript.php, supplying the HTTP GET argument tab_clicked=my_tab and calling the function tab_fetch_cb when the script returns. The final parameter is the type of data being returned (it's up to you to choose).
$.get("myscript.php", {tab_clicked, "my_tab"}, tab_fetch_cb, "text/json/xml")
It's up to you to design myscript.php to handle the tab_clicked parameter, fetch the appropriate data and return it (i.e. write it back out to the client).
Here's an example for tab_fetch_cb:
function tab_fetch_cb(data, status) {
// populate your newly opened tab with information
// returned from myscript.php here
}
You can read more about the JQuery get function here, and JQuery ajax functions here
I'm sorry I can't be more specific in my examples, but a lot of the processing is really dependant on your task. As it looks as it has already been pointed out, you may look to some JQuery plugins for a canned solution to your problem. That being said, it never hurts to learn how to do this stuff manually w/ JQuery.
Good luck.
UI/Tabs support loading tab content on demand via Ajax, check this example.
Loading content via Ajax adds the complexity of dealing with bookmarking / browser back buttons. Depending on your situation, you should consider loading new content with a full page request. Handling the bookmarking/browser back involves using adding anchor info in the URL.
Also, check out LavaLamp for tab selection. It's pretty nifty looking.
By default a tab widget will swap between tabbed sections onClick, but the events can be changed to onHover through an option. Tab content can be loaded via Ajax by setting an href on a tab.
source: http://docs.jquery.com/UI/Tabs
If you're using Rails, you can try this gem bettertabs
It supports ajax tabs.