Foundation 6 Multiple Accordions, how to have only one accordion expanded at once - zurb-foundation

I am using Foundation 6's Accordion feature and have three separate accordions on one page. By default, within a single accordion, you can only have one content expanded at a time. However, I want to have only one content open at a time for all accordions on the entire page.
I'm pretty sure I can accomplish this using their methods, specifically the "Up" method, however I cannot find any working examples and their documentation is pretty sparse. This is all they provide:
up
$('#element').foundation('up', $target);
Closes the tab defined by $target.
http://foundation.zurb.com/sites/docs/accordion.html
I am not really sure where to go from here.. so far this is what I have:
JS:
$(".accordion-title").click(function(e) {
//Not sure what to do with this
$('#element').foundation('up', $target);
});
HAML:
%ul.accordion#accordion-1{:'data-accordion' => "", :'data-allow-all-closed' => "true"}
%li.accordion-item
%a.accordion-title
Title 1
.accordion-content{:'data-tab-content' => ""}
Content 1
%li.accordion-item
%a.accordion-title
Title 2
.accordion-content{:'data-tab-content' => ""}
Content 2
%ul.accordion#accordion-2{:'data-accordion' => "", :'data-allow-all-closed' => "true"}
%li.accordion-item
%a.accordion-title
Title 1
.accordion-content{:'data-tab-content' => ""}
Content 1
%li.accordion-item
%a.accordion-title
Title 2
.accordion-content{:'data-tab-content' => ""}
Content 2
%ul.accordion#accordion-3{:'data-accordion' => "", :'data-allow-all-closed' => "true"}
%li.accordion-item
%a.accordion-title
Title 1
.accordion-content{:'data-tab-content' => ""}
Content 1
%li.accordion-item
%a.accordion-title
Title 2
.accordion-content{:'data-tab-content' => ""}
Content 2

I found the solution to my question in case anyone else is stuck:
$(".accordion-title").click(function(e) {
$('.accordion').foundation('up', $('.accordion .accordion-item.is-active .accordion-content'));
});

I couldn't get alexandraleigh's answer to work, it was also closing the accordion I had just clicked to open.
The following is what I wrote in the end. It works on accordions set with either data-multi-expand="true" or data-multi-expand="false"
/**
* on accordion section click
*/
$('.accordion-title').on('mouseup', function (e) {
var $accordionItem = $(this).parent(),
//is the section hidden? if the section is not yet visible, the click is to open it
opening = ($accordionItem.find('.accordion-content:hidden').length === 1);
//
if (opening) {
//the accordion that has just been clicked
var $currentAccordion = $accordionItem.parent();
//close all other accodions
$('.accordion').each(function () {
var $acc = $(this);
//ignore the accordion that was just clicked
if ($acc[0] !== $currentAccordion[0]) {
//find any open sections
var $openSections = $acc.find('.accordion-item.is-active .accordion-content');
//
$openSections.each(function (i, section) {
//close them
$acc.foundation('up', $(section));
});
}
});
}
});

I couldn't get r8n5n's answer to work - perhaps because of Foundation's updates since. But I managed to get it working with the following on v6.3.0..
jQuery('.accordion-title').on('mouseup', function (e) {
jQuery('.accordion').each(function () {
jQuery(this).foundation('up', jQuery('.accordion-content'));
});
});

I had some minds on a previous answers
if you have 2 accordion just add classname to them. For example class="accordion accordion-first" and class="accordion accordion-second".
//close active item on second accordion when click on first accordion
$(".accordion-first .accordion-title").click(function(e) {
$('.accordion').foundation('up', $('.accordion-second .accordion-item.is-active .accordion-content'));
});
//close active item on first accordion when click on second accordion
$(".accordion-second .accordion-title").click(function(e) {
$('.accordion').foundation('up', $('.accordion-first .accordion-item.is-active .accordion-content'));
});

Related

How do I route to a modal that takes in data specific to a user ID?

I am managing a list of items that open different modals, like so:
list() {
return [
{
click: () => this.modal.show(),
icon: 'fas fa-file-import',
text: 'Hello World'
}
]
}
But for one of the list items, I made a modal that needs to show data related to the user that is opening it. When it comes to data, I only know how to do it using router-links, like so:
list2() {
return [
{
label: data => data.item.orderName,
to: data => `/orders/${data.item.id}`
icon: 'fas fa-file-import',
}
]
}
But how can I do the same with a modal?
I tried linking to the modal component:
to: data => `/modal/${data.item.id}
but that has no effect. I just get routed to a blank page.

How to reset a Stack in a different Tab using React Navigation 6.x

i have bottom tab stack....in each stack there are either single screen or nested stack navigator.
Problem:
first tab - Home screen
second tab - MyDetailsStack(createStackNavigator)
- detailScreen1 (initialRoute)
- detailScreen2
Goal:
when user visits detail detailScreen2.... then goes back go homescreen and clicks back second tab....i need to reset the second tab to show initial route it is pointing which is detailScreen1.
At this moment what ever screen i left (that is detailScreen2) is shown.
Please check the expo for the problem.
https://snack.expo.dev/#rosnk/nested-route-reset-on-tabchange
Currently tried solution:
tried adding following code:
<Tab.Screen
name="MyDetailsTabStack"
component={MyDetailsStack}
options={{
title: 'My Details',
tabBarLabel: 'My Details',
}}
listeners={({ navigation, route }) => ({
tabPress: (e) => {
navigation.dispatch(
CommonActions.reset({
index: 1,
routes: [
{ name: 'DetailScreen1' },
{
name: 'DetailScreen2',
},
],
})
);
},
})}
/>
tried solution reference to this stack suggestion:
How to reset a Stack in a different Tab using React Navigation 5.x
I was also having this problem. I want to reset the navigation stack back to the first index when the user leaves the tab. I followed the reference in your link and from that, created my solution to the problem.
Using the useFocusEffect() described here, and after reading about the Navigation Lifecycle here, below is my solution that works for me.
const { reset } = useNavigation();
useFocusEffect(
useCallback(() => {
// If you want to do something when screen is focused
return () => {
// This is called when the screen is not focused
// i.e. switched to a different tab or the hardware back button is pressed (Android)
reset({ index: 0, routes: [{ name: "detailScreen1" }] });
};
}, []),
);
Place this inside your detailScreen2 and it should reset back that stack navigators state whenever the user leaves the screen

Unit testing user interaction in an angular2 component

I've recently started learning angular2, and I thought I'd try and write a combobox component similar to select2. Here's a simplified version of the component:
#Component({
selector: 'combobox',
template: `
<div class="combobox-wrapper">
<input type="text"></input>
<button class="toggle-button"></button>
</div>
<div *ngIf="isDropdownOpen" class="dropdown">
<div *ngFor="let option of options; let index = index;"
class="option"
[class.focused]="focusedIndex==index">
{{option.label}}
</div>
</div>
`
})
export class ComboboxComponent {
#Input() options: any[] = [];
isDropdownOpen: boolean = false;
focusedIndex: number = 0;
}
I'm struggling when it comes to writing unit tests involving user interaction. For example, I want the user to be able to navigate the list of options by using the up and down keys on the keyboard. The way I see it, I have two options.
Option 1:
describe('when the dropdown is open and the user presses the "UP" key', () => {
it('should focus the first available preceeding option', () => {
const button = fixture.debugElement.query(By.css('.toggle-button'));
const input = fixture.debugElement.query(By.css('input'));
button.triggerEventHandler('mousedown', {});
input.triggerEventHandler('keydown', { key: 'ArrowDown' });
input.triggerEventHandler('keydown', { key: 'ArrowDown' });
input.triggerEventHandler('keydown', { key: 'ArrowUp' });
fixture.detectChanges();
const options = fixture.debugElement.queryAll(By.css('.option'));
expect(options[1].nativeElement.className).toContain('focused');
});
});
Option 2:
describe('when the dropdown is open and the user presses the "UP" key', () => {
it('should focus the first available preceeding option', () => {
const combobox = fixture.componentInstance;
combobox.isDropdownOpen = true;
combobox.focusedIndex = 2;
input.triggerEventHandler('keydown', { key: 'ArrowUp' });
fixture.detectChanges();
expect(combobox.focusedIndex).toBe(1);
});
});
Neither option feels right. In the first case I'm making assumptions about behaviour that is not part of the test itself - namely that clicking the "toggle" button will open the dropdown, and that pressing the "ArrowDown" key will focus the next option on the list.
In the second case I'm accessing properties that are not part of the component's public interface (#Inputs and #Outputs), and the test itself requires detailed knowledge about the actual implementation.
How should I approach this?

React Native: Force reload of TabBarIOS.item

I have a TabBar based app in React Native.
Multiple tabs use the same datasource (AsyncStorage).
If I'm now updating the data in one tab and open the other one, the old data is displayed.
I can't figure out, how to force a reload every time the item become active.
FavoritesView: display saved data
ExploreView: Manipulate saved data
FavoritesView: expired data gets displayed (--> force reload)
<TabBarIOS.Item
title="Explore"
icon={{uri:'ic_explore'}}
selected={this.state.selectedTab === 'exploreTab'}
onPress={() => {
this.setState({
selectedTab: 'exploreTab'
});
}}>
<ExploreView/>
</TabBarIOS.Item>
<TabBarIOS.Item
title="Favorites"
icon={{uri:'ic_favorite_border'}}
selected={this.state.selectedTab === 'favoriteTab'}
onPress={() => {
this.setState({
selectedTab: 'favoriteTab'
});
}}>
// Reload this
<FavoritesView/>
</TabBarIOS.Item>
<TabBarIOS.Item
systemIcon="more"
selected={this.state.selectedTab === 'moreTab'}
onPress={() => {
this.setState({
selectedTab: 'moreTab'
});
}}>
<MoreView/>
</TabBarIOS.Item>
I already tried to set a new state to trigger an update, but it doesn't seem to change anything.
<TabBarIOS.Item
title="Favorites"
icon={{uri:'ic_favorite_border'}}
selected={this.state.selectedTab === 'favoriteTab'}
onPress={() => {
this.setState({
selectedTab: 'favoriteTab',
forceUpdate: Math.random()
});
}}>
<FavoritesView forceUpdate={this.state.forceUpdate}/>
</TabBarIOS.Item>
I had a similar issue and what eventually worked for me was to override componentWillReceiveProps on the embedded views. It gets called anytime the view is set as selectedTab in the TabBarIOS.
https://facebook.github.io/react/docs/component-specs.html#updating-componentwillreceiveprops
this references the parent component when using fat arrow notation (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#Lexical_this).
Try adding a ref to the TabBar item and use this.refs.refName.forceUpdate() (slightly nicer than updating the state with a random value as well).

bootstrap typehead dropdown doesn't expand over bootstrap collapse

So I have bootstrap collapse and inside it I have tabs, and inside one of the tabs I have a form with text_field that has bootstrap typeahead and the problem is that typeahead's dropdown dosn't expand over collapse.
that text_field with autocomplete is the last element in there.
here is the picture.
I want that dropdown expands below the collapse element (below the line on the picture)
EDIT:
Here is the haml for that view
- #i = 0
- #trainings.each do |training|
- #i = #i+1
.accordion#accordion2
.accordion-group
.accordion-heading
%a{:class => 'accordion-toggle', 'data-toggle' => 'collapse', :href => "#collapse#{#i}"}
= "Training #{#i}"
%div{:id => "collapse#{#i}", :class => 'accordion-body collapse'}
.accordion-inner
%pre= "Description: #{training.description}"
%ul.nav.nav-tabs#myTab
%li.active
%a{"data-toggle" => "tab", :href => "#planirano#{#i}"} Planirano
%li
%a{"data-toggle" => "tab", :href => "#napravljeno#{#i}"} Napravljeno
.tab-content
%div{:class => 'tab-pane active', :id => "planirano#{#i}"}
- training.exercises.each do |exercise|
%pre= "#{exercise.element.name} | #{exercise.description} | #{exercise.number_of_series}"
= form_for :training_exercise, :url => training_exercises_path(:training => training.id), remote: true, html: {:class => 'form-inline'} do |f|
= f.label :exercise
= f.text_field :exercise, :id => 'add_training_exercise'
= f.button :Add, :class => 'btn'
%div{:class => 'tab-pane', :id => "napravljeno#{#i}"} to sam napravio
f.text_ifeld :exercise, :id => 'add_training_exercise' is the field with autocomplete I am asking about.
EDIT:
and here is the rendered HTML
I somehow find the answer on stack overflow the solution is
.accordion-body.in { overflow:visible; }
It is from here.
I am sorry for asking question that already has the answer but I really was not able to find it because I didn't guess the right word for searching.
Applying the following css works only partially, accordion-body.in { overflow:visible; }, since it only displays the overflow of the "slice" that is being expanded. You'd need to apply it to the parent as well. In addition the above css affects the expand/collapse effect; i.e. the content of what is being shown get's displayed over the accordion, versus gradually being shown. A solution I tried is to:
1. Apply the overflow:visible only to the parent, i.e. #myAccordion { overflow:visible } AND
2. Apply overflow:visible only to the "slice" being opened when it is needed (on open), and removing it on close, like so:
$("#myAccordion").collapse();
// Here, we are attaching event handlers to the accordion "slice" body so that we can update it's overflow when opened AND when it's about to be closed.
$("#myAccordion .accordion-body").on("shown", function () {
$(this).css("overflow", "visible");
});
$("#myAccordion .accordion-body").on("hide", function () {
$(this).css("overflow", "hidden");
});
This worked for me since my typeahead is in a navbar
.navbar-collapse.in{
/*allows typeahead to overflow nav bar during collapse*/
overflow-y:initial !important;
}