I have the following Vue.js (3) component, which uses Bootstrap (5):
<template>
<div class="dropdown">
<button class="btn btn-secondary dropdown-toggle btn-link text-decoration-none text-dark" type="button" id="languageDropdown" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ languages[$i18n.locale] }}
</button>
<div class="dropdown-menu" aria-labelledby="languageDropdown" v-for="(value, key) in languages" v-bind:key="key">
<a class="dropdown-item" href="#" #click="changeLanguage(key)">{{ value }}</a>
</div>
<li v-for="(value, key) in languages" v-bind:key="key">
{{ key }}: {{ value }}
</li>
</div>
</template>
<script>
export default {
name: "LanguageSwitcher",
data() {
return {
languages: {
'en': 'English',
'de': 'Deutsch',
}
};
},
methods: {
changeLanguage: function(lang){
this.$i18n.locale = lang;
}
}
};
</script>
Without the v-for everything works fine. But as soon, as I add it, only the first element of the object languages gets rendered.
As you can see, the list is rendered correctly, with both languages.
Only in the dropdown, "Deutsch" (German) is not rendered.
Is this a bug with Bootstrap/Vue or am I missing something?
im able to solve this by moving the v-for syntax to a template
so instead of this:
<div class="dropdown-menu" aria-labelledby="languageDropdown" v-for="(value, key) in languages" v-bind:key="key">
<a class="dropdown-item" href="#" #click="changeLanguage(key)">{{ value }}</a>
</div>
do this:
<div class="dropdown-menu" aria-labelledby="languageDropdown">
<template v-for="(value, key) in languages" v-bind:key="key">
<a class="dropdown-item" href="#" #click="changeLanguage(key)">{{ value }}</a>
</template>
</div>
Related
i am using angular powered bootstrap dropdown and here whenever i do enter key press in input, it always changes the dropdown value to first option.
DEMO LINK
HTML:
<div class="row mb-3 mt-3">
<div class="col">
<div ngbDropdown class="d-inline-block">
<button
type="button"
class="btn btn-outline-primary"
id="dropdownBasic1"
ngbDropdownToggle
>
{{ clickMessage }}
</button>
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
<button
ngbDropdownItem
class="nav-link"
href="#"
(click)="getText($event.target.innerText)"
>
Option 1
</button>
<button
ngbDropdownItem
class="nav-link"
href="#"
(click)="getText($event.target.innerText)"
>
Option 2
</button>
<button
ngbDropdownItem
class="nav-link"
href="#"
(click)="getText($event.target.innerText)"
>
Option 3
</button>
</div>
</div>
</div>
</div>
TS:
clickMessage = 'Choose an option';
getText(text) {
this.clickMessage = text;
}
The behaviour you are seeing is due to you have some buttons without any type attribute and by default the buttons in the form trigger the submit event.Add the type to the buttons in the dropdown and it should work.
<div ngbDropdownMenu aria-labelledby="dropdownBasic1">
<button
type="button"
ngbDropdownItem
class="nav-link"
href="#"
(click)="getText($event, $event.target.innerText)"
>
Option 1
</button>
<button
type="button"
ngbDropdownItem
class="nav-link"
href="#"
(click)="getText($event, $event.target.innerText)"
>
Option 2
</button>
<button
ngbDropdownItem
class="nav-link"
href="#"
(click)="getText($event, $event.target.innerText)"
>
Option 3
</button>
</div>
Add the following code to your ts file.
#HostListener('keydown', ['$event']) public onKeyDown(evt) {
if (evt.key === 'Enter') {
evt.preventDefault();
this.onSubmit();
}
}
I write it for you in the following stackblitz.
https://stackblitz.com/edit/angular12-bootstrap-skiant?file=src%2Fapp%2Fapp.component.ts,src%2Fapp%2Fapp.component.html,src%2Fapp%2Fapp.module.ts
I have 3 Dropdown menu to filter applicants data in my list, from the database
but when I filter with the 2nd filter, the 1st filter will reset it..
I want to do the filter records the 1st filter and then move to 2nd filter without resetting it. and then apply filters to get the data
this is my first time using laravel and everything inside it.
If anyone has a way how this is work, I'm really thank you for that
I'm really appreciate that.
this is the screenshot of the button
the applicants list
this is the controller
public function index()
{
$branches = \App\Branch::all();
$batches = \App\Batch::all();
$users = \App\User::all();
$user_details = \App\UserDetail::all();
$applicant_info = DB::table('applicants')
->join('user_details', 'applicants.fk_user_details_id', '=', 'user_details.user_detail_id')
->join('users', 'users.id', '=', 'user_details.fk_users_id')
->join('batches', 'applicants.fk_batches_id', '=', 'batches.batches_id')
->join('branches', 'applicants.fk_branches_id', '=', 'branches.branches_id')
->select('applicants.*', 'user_details.*', 'branches.*', 'batches.*', 'users.*')
->orderBy('applicants_id', 'asc');
if(request()->has('country')){
$applicant_info = $applicant_info->where('applicants.applicant_country', request('country'));
}
if(request()->has('branch')){
$applicant_info = $applicant_info->where('branches.branch_name', request('branch'));
}
if(request()->has('batch')){
$applicant_info = $applicant_info->where('batches.batch_name', request('batch'));
}
$applicant_info = $applicant_info->get();
// $applicants = $applicants->paginate(5)->appends(['country' => request('country')]);
$branch = \App\Branch::orderBy('branch_name')->pluck('branch_name')->unique();
$batch = \App\Batch::orderBy('batch_name')->pluck('batch_name')->unique();
$countries = \App\Applicant::orderBy('applicant_country')->pluck('applicant_country')->unique();
return view('backend.applicant_management.applicant_list', ['applicant_info'=>$applicant_info, 'branches'=>$branches, 'batches'=>$batches, 'users'=>$users, 'countries'=>$countries, 'branch'=>$branch, 'batch'=>$batch]);
}
and this is the view.blade
<div class="pull-right">
<div class="btn-group">
<button data-toggle="dropdown" class="btn btn-default dropdown-toggle" type="button" aria-expanded="false">Branch Name<span class="caret"></span>
</button>
<ul role="menu" class="dropdown-menu" name="branch">
<li>All Branch
#foreach($branch as $branch)
<li><a id="filterbranch" href="/applicant_list/?branch={{ $branch }}"> {{ $branch }}</a></li>
#endforeach
</ul>
</div>
<div class="btn-group">
<button data-toggle="dropdown" class="btn btn-default dropdown-toggle" type="button" aria-expanded="false">Batch Number<span class="caret"></span>
</button>
<ul role="menu" class="dropdown-menu" name="batch">
<li>All Batch
#foreach($batch as $batch)
<li> {{ $batch }}</li>
#endforeach
</ul>
</div>
<div class="btn-group">
<button data-toggle="dropdown" class="btn btn-default dropdown-toggle" type="button" aria-expanded="false">Country<span class="caret"></span>
</button>
<ul role="menu" class="dropdown-menu" name="country">
<li>All Country</li>
#foreach($countries as $country)
<li> {{ $country }}</li>
#endforeach
</ul>
</div>
</div>
I am trying to create a top menu with dropdown buttons when iterating over an object that looks like this:
links: {
store: 'store',
language: [{'target': '/english'},{'target': '/norwegian'}],
login: 'user/login'
}
I have tried to achieve that by making a loop that looks like this:
<div v-for="(value, key) in links" :key="key" class="control">
<div v-if='Array.isArray(value)'>
<dropdown-menu :menu="value"></dropdown-menu>
</div>
<div v-else>
<a :href="value">
{{ key }}
</a>
</div>
</div>
But, I get errors:
Property or method "value" is not defined on the instance but
referenced during render. Make sure to declare reactive data
properties in the data option.
Even if I declare the value and key with initial values of null, it is not rendering anything:
data() {
return {
data: null,
value: null,
key: null,
};
},
This is the dropdown menu component:
<template>
<div class="dropdown is-active">
<div class="dropdown-trigger">
<button class="button" aria-haspopup="true" aria-controls="dropdown-menu">
<span>Dropdown button</span>
<span class="icon is-small">
<i class="fa fa-angle-down" aria-hidden="true"></i>
</span>
</button>
</div>
<div class="dropdown-menu" id="dropdown-menu" role="menu">
<div class="dropdown-content">
<a href="#" class="dropdown-item">
Dropdown item
</a>
<a class="dropdown-item">
Other dropdown item
</a>
<a href="#" class="dropdown-item is-active">
Active dropdown item
</a>
<a href="#" class="dropdown-item">
Other dropdown item
</a>
<hr class="dropdown-divider">
<a href="#" class="dropdown-item">
With a divider
</a>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'dropdown-menu',
props: ['menu'],
data() {
return {};
},
};
</script>
But, the dropdown menu is not even shown in the vue dev tools when I go to the top-bar component.
Update
For some reason if I removed the divs, and changed the template to this:
<dropdown-menu v-if='Array.isArray(value)' :menu="link"></dropdown-menu>
<a :href="value" v-else>
{{ key }}
</a>
If somebody could explain it, that would be great.
The following is the code of my .vue. swapping between div worked just fine and the transition fade works well too. but mode out-in not working at all. both elements were shown at the same time while transitioning.
EDIT##
Sorry that I am not familiar with fiddle. Please find the full code of my .vue below for your best reference.
<template>
<div>
<div class="col-md-3">
<namecard :shop="shop" :owner="user"></namecard>
</div>
<div class="col-md-9">
<div>
<ul class="nav nav-tabs shop-manage-tabs">
<li class="nav-item">
<a class="nav-link" :class="isActive == 'items' ? 'active' :''" #click.prevent="activateTab('items')">Items</a>
</li>
<li class="nav-item">
<a class="nav-link" :class="isActive == 'operaters' ? 'active' : ''" #click.prevent="activateTab('operaters')">Operaters</a>
</li>
<li class="nav-item">
<a class="nav-link" :class="isActive == 'info' ? 'active' : ''" #click.prevent="activateTab('info')">Info</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false" :class="isActive == 'statistics' ? 'active' : ''">Statistics</a>
<div class="dropdown-menu">
<a class="dropdown-item" #click.prevent="activateTab('statistics')">Action</a>
<a class="dropdown-item" #click.prevent="activateTab('statistics')">Another action</a>
<a class="dropdown-item" #click.prevent="activateTab('statistics')">Something else here</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" #click.prevent="activateTab('statistics')">Separated link</a>
</div>
</li>
</ul>
</div>
<transition-group name="fade" mode="out-in">
<div v-if="isActive == 'items'" key="items">
<div class="card" style="padding: 1rem">
<h1>Control Panel</h1>
<button type="button" class="btn btn-success" #click="addNewProduct = true">Add New Product</button>
<button type="button" class="btn btn-danger" #click="addNewProduct = true">Delete Product</button>
</div>
<add-new-product v-show="addNewProduct"></add-new-product>
<div class="card" style="padding: 1rem">
<item-card :productId="product.id" v-for="product in shop.products" :key="product"></item-card>
</div>
</div>
<div v-else-if="isActive == 'operaters'" key="operaters">
<div class="card" style="padding: 1rem">
<h1>Control Panel</h1>
<button type="button" class="btn btn-success" #click="addNewProductModal = true">Add Operator</button>
<button type="button" class="btn btn-danger" #click="addNewProductModal = true">Delete Operator</button>
</div>
<div class="card">operaters</div>
</div>
<div v-else-if="isActive == 'info'" class="card" key="info">
<div class="card">info</div>
</div>
<div v-else-if="isActive == 'statistics'" class="card" key="statistics">
<div class="card">statistics</div>
</div>
</transition-group>
</div>
</div>
</template>
<script>
import itemCard from './Item-card.vue'
import nameCard from '../Namecard.vue'
import addNewProduct from './Add-new-product.vue'
export default {
components:{
'item-card':itemCard,
'namecard':nameCard,
'add-new-product':addNewProduct,
},
data(){
return{
user:{},
shop:{},
isActive:'items',
addNewProduct:false,
}
},
props:[
],
created(){
this.getUserInfo()
},
mounted(){
},
methods:{
getUserInfo(){
var vm = this
vm.$http.get('/getAuthUser').then((response)=>{
vm.user = response.data
vm.$http.get('/getShop/'+vm.user.id).then((response)=>{
vm.shop = response.data.data.shop
})
})
},
activateTab(tab){
var vm = this
vm.isActive = tab
}
}
}
</script>
You need to give key attribute to each of the div to make the transition work smoothly. In your case I see an extra ', which might be an issue, try removing that.
Change
<div v-if="isActive == 'items'" key="'items'">
to
<div v-if="isActive == 'items'" key="items">
and similarly at other places as well.
I have a Component with view like below:
<div class="dropdown user-select">
<div class="gray-input dropdown-toggle" type="button" id="assigned_to" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<ng-content select="[selected-item-tmpl]"></ng-content>
<span class="caret"></span>
</div>
<ul class="dropdown-menu" aria-labelledby="assigned_to">
<li *ngFor="let item of items"
(click)="itemClick$.next(item)">
<ng-content select="[list-item-tmpl]"></ng-content>
</li>
</ul>
</div>
According to this and this, I now know that Transclusion with ngFor will not work.
But according to this, if I change my component to following:
<div class="dropdown user-select">
<div class="gray-input dropdown-toggle" type="button" id="assigned_to" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<ng-content select="[selected-item-tmpl]"></ng-content>
<span class="caret"></span>
</div>
<ul class="dropdown-menu" aria-labelledby="assigned_to">
<li *ngFor="let item of items"
(click)="itemClick$.next(item)">
<template [ngTemplateOutlet]="template"
[ngOutletContext]="{item: item}">
</template>
</li>
</ul>
</div>
For brevity the Component.ts after change:
#ContentChild(TemplateRef) template: TemplateRef<any>;
and use like following:
<ds-combobox [items]="attendeeService.users"
(itemClicked)="applySelectedUser($event)">
<div selected-item-tmpl>
--> <img *ngIf="newTask.assignedTo.photo" [src]="newTask.assignedTo.photo">{{newTask.assignedTo.name}}
<div *ngIf="!newTask.assignedTo.photo && newTask.assignedTo.initials" class="pull-left photo-avatar">
<div>{{newTask.assignedTo.initials}}</div>
</div>
</div>
<div list-item-tmpl>
<template let-item="item"><b>{{item.name}}</b></template>
</div>
</ds-combobox>
Then I do not get any errors and it seems to run but the template for the ngTemplateOutlet seems to take the template from the first slot and ends up being <img src="null">. If I remove the first slot and just leave <template let-item="item"><b>{{item.name}}</b></template> then it seems to work fine. So basically, how do I combine using Transclusion with Template Outlet in the same component?
NOTE:
After thinking for a while, I just reversed the <template> position with <ng-content> and it seems to work now as expected. But the question still remains why though?