Stop TabChange in primefaces <p:tabView>` - jsf-2

I am using Primefaces 5 and use which has severl tabs.
In each tab I have a dataTable which either can be in editable or not depending to user action.
I want to stay in the same tab and prevent tab change if user is editing a row, otherwise go to the clicked tab. How should i do it ??
This is my xhtml :
<p:tabView id="customerTab"
orientation="left"
dynamic="false"
cache="false"
widgetVar="detailsTab"
activeIndex="#{myBean.activTab}"
>
<p:ajax event="tabChange" listener="#{myBean.onTabChange}" update="customerTabv" />
<p:tab tab1> </p:tab>
<p:tab tab2> </p:tab>
This is my backing bean:
public void onTabChange(
TabChangeEvent event) {
if (Tab.isInEditMode()) {
FacesMessage msg = new FacesMessage("Tab Changed", "Active Tab: " + event.getTab().getId()
+ "You can not change the tab when you are in Edit mode!");
FacesContext.getCurrentInstance().addMessage(null, msg);
this.messagesTab.setActiveIndex(0);
// // RequestContext.getCurrentInstance().execute("tabWidget.select(0)");
activTab = 0;
FacesContext.getCurrentInstance().setProcessingEvents(false);
} else {
TabView tabView = (TabView) event.getComponent();
int activeIndex = tabView.getChildren().indexOf(event.getTab());
this.messagesTab.setActiveIndex(activeIndex);
activTab = activeIndex;
}
}

The solution in short boils down to this:
In the onstart of the rowEditInit ajax event, set a client-side variable that you are in edit mode
In the oncomplete of the rowEditCancel event, set the client-side variable that your are in a non-edit mode
In the oncomplete of the rowEdit event, set the client-side variable that your are in a non-edit mode
In the onstart of the tab change event, write some javascript that checks for the value of this edit variable and if in edit mode, return false. The tabChange should not happen then. If in non-edit mode, return true and the tabChange happens
Sorry, I do not write an answer for you with a fully working example. This is mainly because I do not want to/have the time to write it (never used inline editing myself for complexity reasons like this) AND think that people 'learn' more from hints then fully worked out code.

I had a lot of problems with tabView and nested dynamic elements like dataTable in it. So I use the tabView now only as trigger. This means the tabView has tabs but inside the tabs are not elements. I react with ajax listener to tab changes and update a specific area in my UI which shows the content that should be inside the tab.
For your problem this could be a solution. You can ignore the tab change event when the dataTable is edited.
Or disable the other tabs with tab disabled attribute.

My solution was some javascript. In order to stop tabchange:
<p:tabView id="tabView" activeIndex="#{controller.tabSelected}" onTabChange="handleTabChange(index);return false;"
Check primefaces_user_guide_6_2 for the handleTabChange function.
I also needed p:remoteCommand to send the new selected tab to the bean.

Related

Vaadin Accordion with Button in summary

In my Vaadin 14 app, I want to add an Accordion component that has several components in its summary (which is always displayed), among which a Button. Clicking in the summary normally toggles the display of the AccordionPanel content. How can I prevent the AccordionPanel to collapse/expand when the button in the summary is clicked?
Objects are created simply as follows:
Accordion accordion = new Accordion();
MyPanel panel = new MyPanel();
accordion.add(panel);
with MyPanel constructor simply calling setSummary() with a layout containing the button.
I found the answer in this thread on the forum.
It turns out you can prevent the propagation of the button click with this hack:
button.getElement().addEventListener("click", click -> {
//do nothing
}).addEventData("event.stopPropagation()");
This seems like a core functionality that the framework should provide out of the box, but this ticket is still open.
Adding this to your view:
UI.getCurrent().getPage()
.executeJs("Array.from(document.getElementsByTagName('vaadin-accordion-panel')).forEach(element=>element.shadowRoot.querySelector(\"div[role=button]\").replaceWith(element.shadowRoot.querySelector(\"div[role=button]\").cloneNode(true)))");
will disable all clicks on all the accordions toggle and accordion summary. However you will need to include a button or trigger for opening and closing the accordion. I don't know if this is what you want?

Overlay button on NativeScript TabView?

I have a simple TabView like this using NativeScript w/angular:
<TabView [(ngModel)]="tabSelectedIndex" height="300px" (selectedIndexChanged)="onSelectedIndexChanged($event)">
<StackLayout *tabItem="{title: 'Tab 1'}">
<Label text="Content in Tab 1"></Label>
</StackLayout>
<StackLayout *tabItem="{title: 'Button 1'}">
<!-- these won't be content here because clicking this should not change to a another tab, but instead should do something else. -->
</StackLayout>
<StackLayout *tabItem="{title: 'Tab 2'}">
<Label text="Content in Tab 2"></Label>
</StackLayout>
</TabView>
I want a button in the tab bar that doesn't change the view, but instead does something else (such as open a modal dialog).
I tried a new <StackLayout> both inside and outside of <TabView>.
I also tried using an <AbsoluteLayout>. All methods caused the app to crash.
Is it possible to capture the tab view change using selectedIndexChanged and prevent the change?
I tried stopPropagation() on the event but got error:
Property 'stopPropagation' does not exist on type 'SelectedIndexChangedEventData'.
I tried changing the view back to the view that existed when the middle button was clicked, but there is a noticeable flicker because the view has to change before this event is even fired. What would have been acceptable is something like onSelectedIndexWill Change but that method does not exist.
onSelectedIndexChanged(args: SelectedIndexChangedEventData) {
if (args.newIndex === 1) { //the middle button
setTimeout(() => {
tabView.selectedIndex = args.oldIndex; //go back to the previous view (causes flicker)
//do stuff for the button click.
});
}
}
Or is there another way to incorporate a button in the tab bar that doesn't link to a new view?
Or should I not implement a native tab bar and instead just create a navigation bar from scratch?
Here's how it can be done for ios.
Here is a sample app in NativeScript playground showing the issue. Click center link to see the flicker.
Do to the fact that the NativeScript team has refused to export the delegates this is not something you can monkey patch in at this point. The only way to do this is to fork the TabView code and create your own plugin using it.
However, making this change should be fairly simple once you have your forked copy. You just need to on around line 64 public tabBarControllerShouldSelectViewController(tabBarController: UITabBarController, viewController: UIViewController): boolean {
You just need to detect which viewController it is trying to load; and then return false in the case where you don't want to actually change the view. ;-)
Two possible ways;
check the owner.selectedIndex; I believe it should be pointing to the proper new index at this point;
however if it is not then the second possible method would be to check the viewController against the owners viewcontroller list (i.e. const selectedIndex = owner._ios.viewControllers.indexOfObject(viewController); )

Open three tabs of accordion panel

I have an accordion panel with 5 tabs Namely Department Name, student Name, serial number, age and comments.In each tab, I have prime faces text area to enter. After entering all details I am saving it. Now I will try to edit this information. While editing information I want the accordion panel implementation as below,
When I click on edit how to make p:inputTextarea enable so that it can be edited. Currently tab is high lighted not the p:inputTextarea.
when any information is edited, respective tab should be highlighted after saving. For example age and comments are edited, I have to highlight two tabs after saving, so that user can understand that age and comments has been edited. setting Active index opens only one tab. setting mutiple to true opens all the tabs. How to implement this?
use the binding attribute of the accordian panel. when you save data, decide which tab need to be highlighted. In backing bean set the active tab accordingly.
Example:
In your view:
<p:accordionPanel autoHeight="false" binding="#{mybackingbean.panel}" ....other attributes you need... />
in backing bean:
#ManagedBean(name="mybackingbean")
public class MyBackingBean
{
private AccordionPanel panel;
//Setter and getter for panel
public String saveAction()
{
if(somecondition)
{
panel.setActiveIndex(1);
}
else
{
panel.setActiveIndex(0);
}
return "";
}
}

<p:focus does not work when it is in a p:tabView

<P:focus tag works fine in normal forms but when the form is in the second tab of a p:tabView it does not work.
What is the solution the set the focus of the first input of the form when the tab is selected?
Based on your hint I solve the problem this way:
onTabShow="tabShowHandler()"
And the javascript part:
function tabShowHandler() {
var inputUsername = $('#tabView\\:frmRegister\\:username');
inputUsername.focus();
}

Identifying which tab is clicked in accordion panel in JSF Primefaces

Is there any way to know which tab from the list is clicked in accordion panel in JSF Primefaces??
I need the property in the bean.
For eg: I have lstofItems<Item> on accordion panel tabs. If i click on one tab, i need a property Item clickedItem to be set to that value. I need it to load the data for that tab from DB.
Is there any way ? Maybe using PropertyActionListner or something else. I thought about propertyActionListner but couldn't figure out where to place it. Any suggestion ???
Thanks
The view:
<p:accordionPanel>
<p:ajax event="tabChange" listener="#{myBean.onTabChange}" />
<!-- Define your tabs here -->
</p:accordionPanel>
The managed bean:
#ManagedBean
public class MyBean {
public void onTabChange(TabChangeEvent event) {
System.out.println(event.getTab().getId());
}
}

Resources