How to matching tabview component in server and client side with jsf? - jsf

I have two question as below;
I have a Menu and submenus in left side of my page and a Tabview on center of my page. when click to menuItem, I add tab to tabview with javascript dynamically
but I can't get tabs of tabview from backing bean. I can read only first tabs before I added with javascript.
so I want to match tabview at server side and client side synchronously.
how can i do this ?
and second;
When I closed to tab, I use TabCloseEvent in onTabClose method but event is always null. May be it will be solved with matching tabview with server and client side
i don't know.
codes are as below.
Please advise me.
thanks..
xhtml code :
<p:menuitem value="#{itemMenu.menuAck}"
action="#{MenuBean.OpenPage(itemMenu.pageName)}"
ajax="true"
oncomplete="handleTabViewEvent(args);" />
<script type="text/javascript">
function handleTabViewEvent(args) {
alert('Add tab here..');
}
</script>
bean code :
public void OpenPage(String pageName) {
String s = "Divert to handleTabViewEvent function";
}
public void onTabClose(TabCloseEvent event) {
FacesContext context = FacesContext.getCurrentInstance();
TabView tw = (TabView)context.getViewRoot().findComponent("centerForm:tw");
String s = "I must delete tab here from tw which closed.
But event does not give me tab information. It is always null. And tw has old values";
}

I add tab to tabview with javascript dynamically
This was completely wrong approached in first place.
You need to add the tab using JSF instead of using JS. Right now JSF is completely unaware about the changed client side state and will never know about the new tab. Any workaround would only end up to be uglier and harder to maintain than when just doing it by JSF instead of JS.
See also:
How to add button for adding new tabs near last tab?
What is the need of JSF, when UI can be achieved from CSS, HTML, JavaScript, jQuery?

Related

ValueChangeEvents being fired only after other components are clicked

I'm trying to use an InputFile within JSF (1.1.7) and Apache Trinidad (1.0.11). I define a change event for it but the event is not being fired when I change the file selection but when I click on another component of the form.
Here is the jsp code:
<trh:body>
<tr:panelPage>
<tr:form usesUpload="true" id="myForm">
<tr:inputFile columns="80" id="archivo"
valueChangeListener="#{myBean.changeInputFile}"
immediate="true">
</tr:inputFile>
<tr:commandButton text="Begin"/>
</tr:form>
</tr:panelPage>
</trh:body>
Here is the relevant part of the bean:
public void changeInputFile(ValueChangeEvent event) {
UploadedFile f = (UploadedFile)event.getNewValue();
}
The code only enters into the myBean.changeInputFile method when I click the Begin button (having changed the file selection previously). I would like it to enter into myBean.changeInputFile when I change the selected file in the inputFile component.
Any idea why could be this happening?
Your expextation is wrong. The valuechangelistener is a server-side action that will fire when something is submitted to the server and effectively has a different value than it did before. It is NOT telling the component to behave like modern ajax (jsf 1.1.7 and its valuechangelistener predate the ajax era). The form value is only submitted to the server when you, well, in 'old' html terms use form submission like pressing a submit button (or use some javascript to trigger that like you would in the old plain html days). And since without pressing a button or the added javascript, nothing is submitted to the server the valuechangelistener will not spontaneously do something.
So the behaviour you see is exactly as it should be.

How to use h:outputLink without destroying the bean

Im using a especial protocol (SIP) to open a softphone trough my xhtml page using something like this
<h:outputLink value="sip:123456" />
But is destroying my bean, leaving the page useless, is there a workaround for this? any ideas would be apreciated
pd:i also trying with primefaces.
UPDATE
What scope is your bean?
Is a viewscope, and i dont have to pass any parameters, this is a special protocol sip: , what it does is that it opens a program called softphone
How would you do this is normal html?
I corrected the title thanks, in normal html would be something like this <a href="sip:3378984" > call </a>
When will your bean be destroyed? When the page is shown or if you
click the link? But, you can't click the link because there is no
content to render. How do you check the destroyed bean? Which bean?
when i hit the link it goes to my #Predestroy method, and it opens the softphone program (there is no page to show), after i hit the link the page becomes unusuable, like the links, buttons etc, wont work
i also used primefaces commandlink
<p:commandLink value="prime link" action="#{testBean.redirect()}"/>
public void redirect() throws IOException {
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.redirect("sip:123456");
}
So after some reasearch and some comments from previous users i created a script to open the new window and close it after some milliseconds
function clicktocallwindowf(number) {
var wnd = window.open("sip:" + number);
setTimeout(function () {
wnd.close();
}, 10);
return false;
}
<p:commandLink onclick="clicktocallwindowf(#{phonebean.number})" styleClass="Fs16 icon-phone-1"/>
Hope this helps somebody, thank you guys for the comments it gave me more direction!

RequestContext sends response but the page doesn't change

I have a JSF page, with some components rendered if a certain value is selected in SelectOneMenu. For that I change their rendered value and call RequestContext.getCurrentInstance().update("#form").
From the client point of view, whenever I select the value, I get a response from server:
<update id="mainForm:addUser:menu_14:menu">
<...some updated values...>
</update>
Yet, the element with id mainForm:addUser:menu_14:menu did not update.
Can anybody tell me what is wrong?
Update
I can add commandButton with update="#form", and pressing this button actually redraws the form as needed. But I need to do this from the backing bean, so...
From the docs:
public abstract void update(String name)
Update a component with ajax.
name - Client side identifier of the component.
So you can't use selectors like you do from the xhtml file, you have to give client ID of the component.
RequestContext.getCurrentInstance().update("mainForm")
How to programmatically ajax-update specific component in backing bean
Are you using Primefaces? You should pass client id to RequestContext.update method. #form won't work. Try update(mainForm).

HTML object as JSF UIComponent

I have a TabView whose tabs i generated with :
<p:tabView>
<c:forEach var="app" items="#{data.apps}">
<p:tab title="#{app.name}" closable="true" id="app_#{app.id}">
<object data="#{app.startUri}" height="800" width="1150" />
</p:tab>
</c:forEach>
</p:tabView>
However, I had a problem with adding new tabs. I had to update the TabView which caused the tabs and their contents to reload which was a problem for my situation.
I then switched to create my TabView with a TabViewHelper bean.
But then there was a problem with adding the object tag as a child to the tab:
public TabView initializeTabView(List<App> apps) {
tv = new TabView();
Tab tab;
for (App app : apps) {
tab = new Tab();
tab.setTitle(app.getName());
HTMLObjectElementImpl content = new HTMLObjectElementImpl(owner, "test-object");
tab.getChildren().add(content);
tv.getChildren().add(tab);
}
return tv;
}
I get the following error:
The method add(UIComponent) in the type List is not applicable for the arguments (HTMLObjectElementImpl)
I can only add an UIComponent.
I'm not sure if HTMLObjectElementImpl is right for <object> but I did not find something better.
Is there an UIComponent for the HTML <object>-tag or is there another class available for HTML <object>?
Did anyone else have this problem and found a solution?
<object> is not a JSF component. It's basically considered as plain text.
Simplest way would be to create a HtmlOutputText with escape set to false.
HtmlOutputText html = new HtmlOutputText();
html.setEscape(false);
html.setValue("<object>...</object>");
Beware of XSS attack holes in case you pass user-controlled variables to that.
In future you try to create a JSF component programmatically, use a subclass of UIComponent and not some random JAXP implementation specific class. Or, better, fix that update problem so you can keep using XHTML code to create the view instead of verbose Java code.

Redirecting to an external URL in a new tab and performing an action in backing bean at the same time

I'm working at a jsf application that at a certain time need to open an external page in a new tab, leaving the first page active. I need to find a way to make the application perform, in a single button click:
a redirect to an external URL in a new tab
an action which disables the button itself in the original page
I've tried using an <outputLink /> but it has no action attribute.
I've tried using a <commandLink />but it's unable to redirect outside.
I've also tried a <commandLink /> with target="_blank" and a redirection coded in the backing bean:
<h:commandLink onclick="submit();" target="_blank" action="#{myBean.execute}" disabled="#{myBean.linkDisabled}" value="external link" />
and, in the backing bean:
public String execute() {
linkDisabled = true;
try{
ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
externalContext.redirect(Constants.EXTERNAL_URL);
} catch(Exception e){
throw new FacesException("Redirection failed");
}
return THIS_PAGE;
}
A page is opened in a new tab but it's the current page instead of the that with URL Constants.EXTERNAL_URLand the button is still enabled. No error message is shown. Any suggestion?
Thanks in advance, Andrea
Your question is confusing. You're mixing "link" and "button". You basically need to disable the element in the client side by JavaScript because the response does not return to the current browser window/tab, but to a different browser window/tab. In JavaScript, it's easy to disable a button, but not a link. For simplicity, I'll assume that you mean and can use a <h:commandButton> and that this is the only button in the current form.
To solve your problem, you need to remove onclick="submit()" (because it's disturbing the default behaviour) and you need to remove the navigation outcome (it should not matter, but you never know in some JSF impls) and you need to disable the button by JS in the client side.
All with all your code should look just like this:
<h:form target="_blank">
<h:commandButton
value="external"
action="#{myBean.execute}"
onclick="setTimeout('document.getElementById(\'' + this.id + '\').disabled=true;', 50);" />
</h:form>
And
public void execute() throws IOException {
FacesContext.getCurrentInstance().getExternalContext().redirect(Constants.EXTERNAL_URL);
}
The setTimeout() is necessary because the button is otherwise disabled before the form data is sent which would cause that the button's own name=value pair won't be sent as request parameter and so JSF won't invoke any action.
why don't you use action="someaction" and map it in faces-config.xml to go to another page?

Resources