I am using vue to make a menu which can show and hide the description when click the title.
The original menu is like this showing the title
The expanded menu is like this expanding the menu description
<li class="cursor-pointer p-2 flex" v-for="(menu, index) in menus" :key="index" >
<div class="w-full flex items-center justify-between px-2" #click="handleSelect(menu,index)">
<div class="text-sm w-full ">
<i class="el-icon-document" ></i> {{ menu.name }}
</div>
</div>
<!-- menu show and hide-->
<ul class="py-4 px-1 rounded-b border-gray-100" v-show="menu.showed">
{{ menu.description }}
</ul>
</li>
handleSelect(menu,index){
console.log('select',index,menu.showed);
this.menus[index].showed=!menu.showed
},
menus:[
{
name:'Introduction',
showed: false,
decription:''
},
{
name:'Feedback Is Important',
showed: false,
decription:''
},
{
name:'Client Briefing and Debriefing',
showed: false,
decription:''
},
]
my expected result is that the expanded status of the menu could show and hide when clicking the menu title. However, clicking the first menu could change the 'showed' variable but doesn't show the expansion, only clicking the second menu will show the first menu.
It seems like the v-show not working, any solution or idea to solve it or better way to deal with menu show-up.
Your data needs to be reactive. Put your menus array inside the data section when using options API , or inside a setup script when using composition API
Related
I am developing an algolia search solution for an ecommerce app with around ~30000 products.
I tried to use the <ais-configure/> component to filter my results before showing them on the page, as I am working with different pages for each category of products and some facet filters also need to be applied if a user was to click on a promotion which would lead to this search result in the code below.
The problem is:
Whenever I use the filters in <ais-configure/> the same filters are not picked up by my <ais-refinement-list/> component which should have the refined facets highlighted.
The below code is not working but descriptive enough for the problem.
Template
<ais-instant-search :search-client.camel="searchClient" index-name="products">
<ais-configure
:filters.camel="searchParameters.filters"
:facet-filters.camel="searchParameters.facetFilters"
/>
<ais-infinite-hits>
<div
slot="loadMore"
slot-scope="{ isLastPage, refineNext }"
class="w-full my-12 px-6 text-sm-black-primary"
>
<button
class="
w-full
h-20
border-4
rounded-md
border-sm-black-primary
font-semibold
text-xl
mb-24
"
:disabled="isLastPage"
#click="refineNext"
>
See more
</button>
</div>
</ais-infinite-hits>
<products-filter-section>
<div v-for="(filterType, id) in filterTypes" :key="id">
<ais-refinement-list :attribute="filterType" searchable show-more>
<template
slot-scope="{
items,
isShowingMore,
isFromSearch,
canToggleShowMore,
refine,
createURL,
toggleShowMore,
searchForItems,
}"
>
<div>
<UtilsFancyTitle
:text="filterType"
text-size="text-lg"
class="ml-4 my-4"
/>
<input
class="bg-white"
#input="searchForItems($event.currentTarget.value)"
/>
<ul class="flex flex-wrap">
<li v-if="isFromSearch && !items.length">No results ...</li>
<li v-for="item in items" :key="item.value" class="my-4 mr-4">
<a
:href="createURL(item)"
:class="
item.isRefined
? 'font-semibold bg-sm-yellow-primary border-sm-yellow-primary '
: 'font-medium'
"
class="
border-4 border-sm-black-primary
py-1.5
px-2
rounded-md
text-sm
"
#click.prevent="refine(item.value)"
>
<ais-highlight attribute="item" :hit="item" />
( {{ item.count.toLocaleString() }} )
</a>
</li>
</ul>
<div class="flex justify-center items-center">
<div class="w-1/4 h-1 bg-sm-black-primary rounded-md"></div>
<button
class="w-2/4 font-semibold my-6"
:disabled="!canToggleShowMore"
#click="toggleShowMore"
>
{{ !isShowingMore ? 'Show more' : 'Hide' }}
</button>
<div class="w-1/4 h-1 bg-sm-black-primary rounded-md"></div>
</div>
</div>
</template>
</ais-refinement-list>
</div>
</products-filter-section>
</ais-instant-search>
Script
import {
AisInstantSearch,
AisRefinementList,
AisInfiniteHits,
AisConfigure,
} from 'vue-instantsearch'
import algoliasearch from 'algoliasearch/lite'
import { mapGetters } from 'vuex'
export default {
components: {
AisInstantSearch,
AisRefinementList,
AisInfiniteHits,
AisConfigure,
},
data() {
return {
searchClient: algoliasearch(
'[API-ENDPOINT]',
'[API-KEY]'
),
filterTypes: [
'type',
'color',
],
searchParameters: {
filters: `category:${this.$route.path.split('/').pop()}`,
facetFilters: `type:someProductType`,
},
}
},
head() {
return {
link: [
{
rel: 'stylesheet',
href: 'https://cdn.jsdelivr.net/npm/instantsearch.css#7.4.5/themes/reset-min.css',
},
],
}
},
}
Is there any working solution for this?
The facets should be auto selected and in their refined state (for example: having their isRefined property set to rue) whenever the algolia query loads and the page renders.
This question has been posted a while ago, so you might already have found an answer, but I'll post mine anyway since I landed here after having the same issue.
In my case, at least, there were 2 problems:
I hadn't configured the "Attributes for faceting". This is explained in the docs and can be done easily via the admin or via API.
I was specifying the facets incorrectly in code. In your example above I think you should have:
searchParameters: {
facetFilters: [[`type:someProductType`]],
},
Note that now facetFilters is an array within an array.
What helps me when I'm unsure I open the admin UI of Algolia, select a search and apply whichever filter I want and then check the raw output. An example from my admin ui:
This gives me an idea of the correct shapes InstantSearch needs.
I am trying to get all images for a category using Vue
<div class="col-md-12 col-sm-2 p-2">
<a v-on:click="onCategoryManageImageClick($event)" data-target="#location-
category-images">
</span>
</a>
</div>
So the event onCategoryManageImageClick ($event) does not work, if I am adding a html block and then click on get image button.
this is index.js
methods:{
onImagesTabClick(){
this.$root.$emit('activated-tab:location-images');
},
onCategoriesTabClick(){
window.j1App.eventBus.$emit("j1-location-image-list:shown");
},
onCategoryManageImageClick: function(event) {console.log('working event..');
event.preventDefault();
window.j1App.eventBus.$emit("j1-location-category-image-
list:shown",event.currentTarget.id);
}
}
So basically it need to to work like we do in jQuery
$(document).on('click',function{
})
So it works either page load or if adding any new html element on DOM. same I want in Vue.
You cannot alter the Vue template outside of Vue. That won't work. Vue compiles the template once when starting up and adds the event listeners to the rendered elements. If you add elements afterwards, Vue will not know about them.
The correct way of doing this would be to add those new elements in Vue.
<div
class="col-md-12 col-sm-2 p-2"
v-for="item in items"
:key="item.id"
>
<a
v-on:click="onCategoryManageImageClick($event, item)"
data-target="#location-category-images"
>
</a>
</div>
See https://v2.vuejs.org/v2/guide/list.html for documentation. In this case you need the items array variable in data and add more array elements to it, if you need more links.
Try raplacing your a tag with p
<div class="col-md-12 col-sm-2 p-2">
<p v-on:click="onCategoryManageImageClick" data-target="#location-
category-images">
</p>
</div>
I just have an element that opens and closes on click
<div class="folderItemHeader" :class="{ bold: isFolder }" #click="toggleChild(item)" :title="item.name">
<span v-if="isFolder" style="color: Tomato;">
<!-- LINE 1 <i :class="['fas', item.show ? 'fa-folder-open' : 'fa-folder']" :key="item.show"></i> -->
<i class="fas fa-folder-open" v-if="item.show"></i>
<i class="fas fa-folder" v-if="!item.show"></i>
</span>
{{ item.name }} {{ item.show }}
</div>
The first time it renders properly
But when I click anything the first time nothing happens, (it should show the other icon)
When I click again, it adds a new element
When I uncomment LINE1, it shows all icons in the correct format (first one is open, other children are closed initially), but after that nothing updates.
Note that the true and false value for item.show does actually update
Just to add more information, issue is not with Vue.js, because using my custom class instead of font-awesome works fine
<span v-if="isFolder" style="color: Tomato;">
<i :class="[item.show ? 'showClass' : 'dontShowClass']">My Data</i>
</span>
I import all in my index.js.
// "#fortawesome/fontawesome-free": "^5.13.0"
import '#fortawesome/fontawesome-free/js/fontawesome';
import '#fortawesome/fontawesome-free/js/solid';
import '#fortawesome/fontawesome-free/js/regular';
import '#fortawesome/fontawesome-free/js/brands';
Do I need to update my webpack.js?
I have a menu button with a click event in Vue. When the button is clicked, it's supposed to activate the menu itself. This is the parent element which when clicked activates the menu (the toggleMenu function makes menuIsActive true). This part works fine:
<div class="navbar-item has-dropdown #click="toggleMenu">
<div class="navbar-link"></div>
<app-navmenu :class="{'is-active': menuIsActive}"/>
</div>
And this is the app-navmenu component that gets rendered:
<div class="navbar-dropdown" #click.stop>
<div class="container is-fluid">
<div class="column">
<h1 class="title">Title</h1>
<router-link class="navbar-item" :to="route" exact>
<div class="navbar-content">
<p class="has-text-info">info</p>
<small>meta info</small>
</div>
</router-link>
</div>
</div>
</div>
The problem I am running into is that I don't want the menu to disappear when I click on the actual navbar-dropdown div element, hence why I have a #click.stop. However, I do want the menu to disappear when I click on a router-link element, but since I have #click.stop in the navbar-dropdown element, the menu persists. If I don't have a #click.stop event on the navbar-dropdown element, then the menu disappears as soon as the navbar-dropdown element is clicked on, which I don't want.
How can I have the menu persist when clicking on the dropdown body, but also have it disappear when I click on a router-link? I've tried other click methods like .self and .prevent, but those don't seem to do what I need.
I am exactly not sure with your requirement, but following your comment, you can use something like this:
This will even push to the router link:
<router-link class="navbar-item" :to="route" exact
#click.native.prevent="callYourMethod">
This will prevent to go to the router link:
<router-link class="navbar-item" :to="route" exact
#click.native.prevent="callYourMethod" event="">
This is what I ended up doing to fix my issue. First, I moved the click function in the parent to one of its children:
<div class="navbar-item has-dropdown">
<div class="navbar-link" #click="toggleMenu"></div>
<app-navmenu :class="{'is-active': menuIsActive}"/>
</div>
This lets the body of the menu stay active even when I click on the body without having to use a #click.stop. Then in the menu itself, I did this so that links will close the menu:
<div class="navbar-dropdown" #click.stop>
<div class="container is-fluid">
<div class="column">
<h1 class="title">Title</h1>
<div #click="toggleMenu">
<router-link class="navbar-item" :to="route" exact>
<div class="navbar-content">
<p class="has-text-info">info</p>
<small>meta info</small>
</div>
</router-link>
</div>
</div>
</div>
</div>
One strange behavior I noticed is that if I put the #click="toggleMenu" function in the <router-link/> element itself, it doesn't get called on, even if I use .prevent. Hence the need for the div wrapper around the router-link element.
I am using el.tab('show') to show a bootstrap 3 tab, it works but when content of the tab is large, tabs are not visible anymore because of page scrolling (this is not the same behavior as if clicking on the tab itself). Any idea how to workaround this? Thanks.
Update: here is a sample code. Tab One is displayed by default, and clicking on the "Go To Tab 2" anchor moves to tab 2 which contains a large page. Problem is that top tabs are not visible anymore after the click as bottom of the page embedded in tab 2 is shown.
<div class="container-fluid">
<ul class="nav nav-tabs">
<li>Tab One</li>
<li>Tab Two</li>
</ul>
<div class="tab-content">
<div id="tab_one" class="tab-pane fade in">
<ul>
<li>Go to Tab 2 </li>
</ul>
</div>
<div id="tab_two" class="tab-pane fade in">
<p>content of tab 2, long page </p>
</div>
</div>
found a way around the problem, but well, it is not pretty:
jQuery('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
setTimeout( function (e) {
window.scrollTo(0,0);
}, 1);
});