# Programs controller i generate the filter options
# Gathering filter options
paises_filter = base_scope.includes(pelicula: :paises)
.map { _1.pelicula.paises }
.flatten
.uniq
.sort_by { |it| it.nome_pais }
.as_json(only: %i[id nome_pais])
mostras_filter = Mostra.where(edicao_id: EDICAO_ATUAL)
.to_a
.uniq { |m| m.id }
.sort_by { |it| it.permalink_pt }
.as_json(
only: %i[id permalink_pt nome_abreviado],
methods: [ :tag_class, :display_name ]
cinemas_filter = Cinema.where(edicao_id: EDICAO_ATUAL)
.to_a
.uniq { |m| m.id }
.sort_by { |it| it.nome }
.as_json(only: %i[id nome endereco edicao_id])
# down below i pass to the ProgramPage.vue
render inertia: "ProgramPage", props: {
rootUrl: @root_url,
tabBaseUrl: program_url,
items:,
elements: @programacoes,
pagy: @pagy,
mostrasFilter: mostras_filter,
cinemasFilter: cinemas_filter,
paisesFilter: paises_filter,
menuTabs: @menu_tabs,
current_filters: {
query: params[:query],
mostrasFilter: selected_mostra,
cinemasFilter: selected_cinema,
paisesFilter: selected_pais
},
has_active_filters: params.permit(:query, :mostrasFilter).to_h.values.any?(&:present?),
crumbs: breadcrumbs(
[ "", @root_url ],
[ "Programação", "" ],
[ "Programação Completa", "" ],
)
}In the program page i receive them as props
// ProgramPage.vue
const props = defineProps({
tabBaseUrl: { type: String, required: true },
items: { type: Array, required: true }
,elements: { type: Object, required: true }
,pagy: { type: Object, required: true }
,mostrasFilter: { type: Array, default: () => [] }
,cinemaOptions: { type: Array, default: () => [] }
,paisesOptions: { type: Array, default: () => [] }
// ...
}
// And below in the template i forward them to the ProgramFilterForm.vue
<ResponsiveFilterMenu
:is-open="isFilterMenuOpen"
:initialFilters="localFilters"
@filtersApplied="filterSearch"
@filtersCleared="clearSearchQuery"
@close-filter-menu="closeMenu"
>
<template #filters="{ modelValue, updateField }">
<ProgramsFilterForm
:model-value="modelValue"
:update-field="updateField"
:mostrasFilter="props.mostrasFilter"
:cinemaOptions="props.cinemaOptions"
:paisesOptions="props.paisesOptions"
/>
</template>
</ResponsiveFilterMenu>In the ProgramFilterForm i receive them as props and pass the options to the combobox component.
// ProgramFilterForm.vue
const props = defineProps({
modelValue: { type: Object, required: true },
updateField: { type: Function, required: true },
mostrasFilter: { type: Array, default: () => [] }, // Program-specific prop
cinemaOptions: { type: Array, default: () => [] }, // Program-specific prop
paisesOptions: { type: Array, default: () => [] }
});
<!-- MOSTRAS -->
<AccordionGroup
text="Mostra"
:isOpen="!!props.modelValue.mostrasFilter"
>
<template v-slot:content>
<div class="overflow-hidden w-full">
<ComboboxComponent
:collection="mostrasFilterOptions"
:modelValue="props.modelValue.mostrasFilter?.permalink_pt || null"
@update:modelValue="(val) => props.updateField('mostrasFilter', getMostraObjectFromTagClas(val))"
/>
</div>
</template>
</AccordionGroup>
<!-- CINEMAS -->
<AccordionGroup
text="Cinema"
:isOpen="!!props.modelValue.cinemasFilter"
>
<template v-slot:content>
<div class="overflow-hidden w-full">
<ComboboxComponent
:collection="cinemasFilterOptions"
:modelValue="props.modelValue.cinemasFilter?.id || null"
@update:modelValue="(val) => props.updateField('cinemasFilter', val)"
/>
</div>
</template>
</AccordionGroup>
<!-- PAISES -->
<AccordionGroup
text="Pais"
:isOpen="!!props.modelValue.cinemasFilter"
>
<template v-slot:content>
<div class="overflow-hidden w-full">
<ComboboxComponent
:collection="paisesFilterOptions"
:modelValue="props.modelValue.paisesFilter?.id || null"
@update:modelValue="(val) => props.updateField('paisesFilter', val)"
/>
</div>
</template>
</AccordionGroup>And what about the props.modelValue. Those, we receive the current_filters from the controller in the ProgramPage as you cansee up there in the controller.
in the program page we create the localFilters ref from the props.current_filters
// PRogramPage.vue
const localFilters = ref({ ...props.current_filters })
// and we forward the to the ResponsiveFilterMenu as :initialFilters
<ResponsiveFilterMenu
:is-open="isFilterMenuOpen"
:initialFilters="localFilters"
@filtersApplied="filterSearch"
@filtersCleared="clearSearchQuery"
@close-filter-menu="closeMenu"
>
<template #filters="{ modelValue, updateField }">
<ProgramsFilterForm
:model-value="modelValue"
:update-field="updateField"
:mostrasFilter="props.mostrasFilter"
:cinemasFilter="props.cinemasFilter"
:paisesFilter="props.paisesFilter"
/>
</template>
</ResponsiveFilterMenu>In the responsive filter we receive them as props and do a few things
const props = defineProps({
isOpen: { type: Boolean, required: true },
initialFilters: { type: Object, required: true },
});
// 1. we create the internalFilters
const internalFilters = ref({ ...props.initialFilters });
// 2. we forwatd it as v-model to searchFilter
<SearchFilter
v-model="internalFilters"
@update:modelValue="(val) => emit('update:modelValue', val)"
@filtersApplied="emit('filtersApplied', internalFilters)"
@filtersCleared="emit('filtersCleared')"
@close-filter-menu="emit('close-filter-menu')"
>
<template #filters="slotProps">
<slot
name="filters"
:modelValue="internalFilters"
:updateField="(field, value) => {
internalFilters[field] = value
}"
/>
</template>
</SearchFilter>
// And we get them back from the slot as well. So this is what makes possible the entire sttrucure and flow.What i dont get is why the cinema and pais is not behaving like the mostra when reopening the menu after the first form submit. If i refresh it works as expected but not in the first one after the submit.
So back to the ProgramFilter where we actually render over those slots and have access to modelValue which is internalFilters, so thats why in the Accordion > Combobox we can do props.modelValue.paisesFilter, which is actually not the option but the ref we use to store the selected option. So that's why i dont get the combobox not beign open and selected after we submit on pais or cinema option while mostra does.
So help me out to debug this. Dont come with solution right away. lets understand the problem and check things first, before changing anything.