Here is an working example https://jsfiddle.net/79epsrmw/
But same in vs code not targeting to item1 sub menu, After passing unique id also.
var app = new Vue({
el: '#app',
data: {
menuItems: [
{
name: 'Item 1',
children: [{name: 'Subitem 1'},{name: 'Subitem 2'},{name: 'Subitem 3'}]
},
{
name: 'Item 2'
}
],
selectedDropdown: 'None'
},
methods: {
setSelectedItem(item) {
this.selectedDropdown = item;
}
},
ready: function() {
$('.dropdown-submenu a.test').on("click", function(e){
$(this).next('ul').toggle();
e.stopPropagation();
e.preventDefault();
});
}
})
.dropdown-submenu {
position: relative;
}
.dropdown-submenu .dropdown-menu {
top: 0;
left: 100%;
margin-top: -1px;
}
<div class="container" id="app">
<h2>Vue.js multi-level dropdown example</h2>
<p>
Selected element: {{ selectedDropdown }}
</p>
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">Dropdown
<span class="caret"></span></button>
<ul class="dropdown-menu">
<li v-for="item in menuItems" v-bind:class="{'dropdown-submenu': item.children}">
<a class="test" tabindex="-1" href="#">{{item.name}}<span class="caret" v-if="item.children"></span></a>
<ul class="dropdown-menu" v-if="item.children">
<li v-for="child in item.children"><a tabindex="-1" href="#" #click="setSelectedItem(child.name)">{{child.name}}</a></li>
</ul>
</li>
</ul>
</div>
</div>
I am getting an error ""Elements in iteration expect to have 'v-bind:key' directives.eslint-plugin-vue
So in order to clear the error i have taken key and passed unique id to it
{{child.name}}
So in order to clear the error i have taken key and passed unique id to it. like :key="child"
Issue is in editor it is working fine, But in vs code after passing unique id, I am unable to select the sub menu in item1.
Check this fiddle
https://jsfiddle.net/negqvmjd/35/
var app = new Vue({
el: '#app',
data: function () {
return {
menuItems: [
{
name: 'Item 1',
children: [{name: 'Subitem 1'},{name: 'Subitem 2'},{name: 'Subitem 3'}]
},
{
name: 'Item 2',
children: []
}
],
selectedDropdown: 'None'
}
},
methods: {
setSelectedItem(item,childLength, bool) {
if(childLength === 0 && bool === false){
this.selectedDropdown = item;
}
else if(childLength !==0 && bool === true){
this.selectedDropdown = item;
}
}
},
ready: function() {
$('.dropdown-submenu a.test').on("click", function(e){
$(this).next('ul').toggle();
e.stopPropagation();
e.preventDefault();
});
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div class="container" id="app">
<h2>Vue.js multi-level dropdown example</h2>
<p>
Selected element: {{ selectedDropdown }}
</p>
<div class="dropdown">
<button class="btn btn-default dropdown-toggle" type="button" data-toggle="dropdown">Dropdown
<span class="caret"></span></button>
<ul class="dropdown-menu">
<li v-for="item in menuItems" v-bind:class="{'dropdown-submenu': item.children.length}">
<a class="test" tabindex="-1" href="#" #click=setSelectedItem(item.name,item.children.length,false)>{{item.name}}<span class="caret" v-if="item.children.length"></span></a>
<ul class="dropdown-menu" v-if="item.children.length">
<li v-for="child in item.children"><a tabindex="-1" href="#" #click="setSelectedItem(child.name,item.children.length,true)">{{child.name}}</a></li>
</ul>
</li>
</ul>
</div>
</div>
Related
I would like to show and hide events with a menu like bootstrap nav nav-tabs.
When on tab I click Event1 show only event with "cid: "1"", Event2 show only event with "cid: "2"" and ALL show all events.
Can anyone help me develop this?
Based on this question Fullcalendar v5 how to show and hide events with checkbox I made a codepen based on checkbox only for starting...
https://codepen.io/berettatim/pen/rNeXwLm
html:
<div class="row">
<div class="col-md-12">
<ul class="nav nav-tabs">
<li onclick="javascript:CalendarTypeSet(1)" class="nav-item"><a class="nav-link active" data-toggle="tab" href="#CalTab1" style="font-size:16px;"><b>EVENT1</b></a></li>
<li onclick="javascript:CalendarTypeSet(2)" class="nav-item"><a class="nav-link" data-toggle="tab" href="#CalTab2" style="font-size:16px;"><b>EVENT2</b></a></li>
<li onclick="javascript:CalendarTypeSet(3)" class="nav-item"><a class="nav-link" data-toggle="tab" href="#CalTab3" style="font-size:16px;"><b>EVENT3</b></a></li>
<li onclick="javascript:CalendarTypeSet('all')" class="nav-item"><a class="nav-link" data-toggle="tab" href="#CalTabAll" style="font-size:16px;"><b>ALL</b></a></li>
</ul>
</div>
<div class="col-md-12">
<input class="cs" value="1" type="checkbox" checked>Calendar1<br>
<input class="cs" value="2" type="checkbox" checked>Calendar2
<div id='calendar'></div>
</div>
script:
document.addEventListener("DOMContentLoaded", function () {
var calendarEl = document.getElementById("calendar");
var calendar = new FullCalendar.Calendar(calendarEl, {
now: "2020-07-11",
scrollTime: "00:00",
aspectRatio: 1.8,
headerToolbar: {
left: "today prev,next",
center: "title",
right: "dayGridMonth,timeGridWeek,timeGridDay,listMonth"
},
initialView: "dayGridMonth",
events: function (fetchInfo, successCallback, failureCallback) {
successCallback([
{
id: "1",
title: "event1",
start: "2020-07-01 19:30",
end: "2020-07-02 19:30",
backgroundColor: "#39CCCC",
cid: "1"
},
{
id: "2",
title: "event2",
start: "2020-07-09 19:30",
end: "2020-07-10 19:30",
backgroundColor: "#F012BE",
cid: "2"
}
]);
},
eventDidMount: function (arg) {
var cs = document.querySelectorAll(".cs");
cs.forEach(function (v) {
if (v.checked) {
if (arg.event.extendedProps.cid === v.value) {
arg.el.style.display = "block";
}
} else {
if (arg.event.extendedProps.cid === v.value) {
arg.el.style.display = "none";
}
}
});
}
});
calendar.render();
var csx = document.querySelectorAll(".cs");
csx.forEach(function (el) {
el.addEventListener("change", function () {
calendar.refetchEvents();
console.log(el);
});
});
});
//Not sure for this...
function CalendarTypeSet(fTip)
{
var x = document.getElementById('cal_tip');
x.value=fTip;
//$('#calendar').fullCalendar('rerenderEvents');
calendar.rerenderEvents('#calendar');
}
The changes you need are more related to the use of tabs than to the difference between fullCalendar 3 and 5. Compared to checkboxes, only one option can be selected at once, so you need to find out from the tabs themselves which tab is currently open.
So here's a simple idea which can work: when a tab is shown, run a function. In that function, call the calendar's refetchEvents() method (https://fullcalendar.io/docs/Calendar-refetchEvents). Then you can use the calendar's eventDataTransform callback to decide whether that event should be displayed on the calendar or not, based on which tab is currently "active". See (https://fullcalendar.io/docs/eventDataTransform) - this is preferable to eventDidMount because it runs before the event is rendered onto the calendar, rather than afterwards.
Something like this should do it:
HTML:
<div class="row">
<div class="col-md-12">
<ul class="nav nav-tabs">
<li data-tabid="1" class="nav-item"><a class="nav-link active" data-toggle="tab" href="#CalTab1" style="font-size:16px;"><b>EVENT1</b></a></li>
<li data-tabid="2" class="nav-item"><a class="nav-link" data-toggle="tab" href="#CalTab2" style="font-size:16px;"><b>EVENT2</b></a></li>
<li data-tabid="3" class="nav-item"><a class="nav-link" data-toggle="tab" href="#CalTab3" style="font-size:16px;"><b>EVENT3</b></a></li>
<li data-tabid="all" class="nav-item"><a class="nav-link" data-toggle="tab" href="#CalTabAll" style="font-size:16px;"><b>ALL</b></a></li>
</ul>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div id="calendar"></div>
</div>
</div>
JavaScript:
document.addEventListener("DOMContentLoaded", function () {
var calendarEl = document.getElementById("calendar");
var calendar = new FullCalendar.Calendar(calendarEl, {
initialDate: "2020-07-01",
aspectRatio: 1.8,
headerToolbar: {
left: "today prev,next",
center: "title",
right: "dayGridMonth,timeGridWeek,timeGridDay,listMonth"
},
initialView: "dayGridMonth",
events: function (fetchInfo, successCallback, failureCallback) {
successCallback([
{
id: "1",
title: "event1",
start: "2020-07-01 19:30",
end: "2020-07-02 19:30",
backgroundColor: "#39CCCC",
cid: "1"
},
{
id: "2",
title: "event2",
start: "2020-07-09 19:30",
end: "2020-07-10 19:30",
backgroundColor: "#F012BE",
cid: "2"
}
]);
},
eventDataTransform: function (eventData) {
var selectedTab = document.querySelector(".nav-tabs li a.active").dataset.tabid;
if (selectedTab == "all" || eventData.cid == selectedTab) {
return eventData;
}
else return false; //discard the event
}
});
calendar.render();
$('a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
calendar.refetchEvents();
});
});
Demo: https://codepen.io/ADyson82/pen/abZZEbM
OK I am fairly new to VueJS, but I am not sure what I am missing here. We have navigation of categories that goes 3 levels deep. I am trying to output the 3rd level of nested navigation and it isnt working as i would expect.
This is the JSON I am using to test with, The data I am trying to use is under children then child.
return {
navList: [
{ id: 1, type: 'Item', url: "#", name: "About Us", target: '_blank' },
{ id: 2, type: 'Item',url: "#", name: "Story", target: '_blank' },
{ id: 3, type: 'Item',url: "#", name: "Price", target: '_blank' },
{
id: 4,
type: 'Item',
url: "#",
name: "Services",
target: '_blank',
children: [
{
url: "https://twitter.com/",
name: "Twitter",
target: "_blank",
child: [
{
url: "https://twitter.com/",
name: "Twitter",
target: "_blank",
},
{
url: "https://dribbble.com/",
name: "Dribbble",
target: "_blank"
},
{
url: "https://www.behance.net/",
name: "Behance",
target: "_blank"
},
],
},
{
url: "https://dribbble.com/",
name: "Dribbble",
target: "_blank"
},
]
},
]
};
},
And here is the code for my navigation.
I am trying to loop through using item.children.child but for some reason it is outputting "Service" see screen shot below.
<template>
<nav class="navbar navbar-light navbar-expand-lg mainmenu">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbar" aria-controls="navbar" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbar">
<ul class="navbar-nav mr-auto">
<li v-for="item in navList" :key="item.id" class="dropdown">
<template v-if="item.children">
<a class="dropdown-toggle" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"
:id="item.name"
:href="item.url"
:title="item.name"
#click="show = !show">{{ item.name }}
</a>
<ul class="dropdown-menu"
:class="{ show }"
:aria-labelledby="item.name">
<li class="dropdown-item" v-for="{ url, name, index, target } in item.children" :key="index" >
<a class="dropdown-toggle" role="button" aria-haspopup="true" aria-expanded="false"
:href="url"
:title="name"
:target="target"
:data-toggle="name">
{{ name }}
</a>
<ul class="dropdown-menu"
:aria-labelledby="name">
<template v-if="item.children.child">
<li class="dropdown-item" v-for="{ url, name, index, target } in item.children.child" :key="index" >
<a class="dropdown-toggle" role="button" aria-haspopup="true" aria-expanded="false"
:href="url"
:title="name"
:target="target"
:data-toggle="name">
{{ name }}
</a>
</li>
</template>
<template v-else>
<a class="nav-link"
:href="item.url"
:title="item.name"
:target="item.target"
>{{ item.name }}</a>
</template>
</ul>
</li>
</ul>
</template>
<template v-else>
<a class="nav-link"
:href="item.url"
:title="item.name"
:target="item.target"
>{{ item.name }}</a>
</template>
</li>
</ul>
</div>
</nav>
</template>
The problem will be the v-for="{ url, name, index, target } in item.children". With v-for, you can either use v-for="item in items" or v-for="(item, index) in items" syntax (talking about arrays). You actually are using the first one here and this means you are trying to destructure { url, name, index, target } properties from your items. This causes the index to be undefined as your items do not have such property on them, and because of that your list items no longer have unique :key property. Try instead this:
v-for="({ url, name, target }, index) in item.children"
For More Info: https://v2.vuejs.org/v2/guide/list.html
In Vue.js how do you target/detect the clicked element to perform a basic toggle class?
I've written this which toggles successfully but when you click an a the class is applied to to all li's
HTML
<ul id="app" class="projects">
<li v-bind:class="dyClass">Project A</li>
<li v-bind:class="dyClass">Project B</li>
<li v-bind:class="dyClass">Project C</li>
<li v-bind:class="dyClass">Project D</li> </ul>
JS
new Vue({
el: '#app',
data: {
show: false,
},
computed: {
dyClass: function() {
return {
show: this.show
}
}
}
})
I'm new to Vue.
EDIT.
I managed to get it working with a mix of help from below, but I dont seem to be able to get the toggle effect.
<ul id="app" class="projects">
<li :class="{show:selected == 1}">
<a href="" #click.prevent.stop="selected = 1" >Exposure</a>
</li>
<li :class="{show:selected == 2}">
<a href="" #click.prevent.stop="selected = 2" >Exposure</a>
</li>
<li :class="{show:selected == 3}">
<a href="" #click.prevent.stop="selected = 3" >Exposure</a>
</li>
</ul>
and
new Vue({
el: '#app',
data: {
selected: false,
}
});
You can pass element to function ($event):
:click=dyClass($event) Then in computed:
dyClass: function(event) {
event.target.toggleClass('whatever')
}
As i understand you have some li items and you want to add an active class when a specific li gets clicked.
Solution:
the "html" part:
<div id="app">
<ul class="projects">
<li v-for="project in projects"
:key="project.id"
:class="{ active: project.id === activeProjectId }"
#click="activeProjectId = project.id"
>
{{ project.name }}
</li>
</ul>
</div>
The "vue" part
new Vue({
el: "#app",
data: {
projects: [
{ id: 1, name: 'Project A' },
{ id: 2, name: 'Project B' },
{ id: 3, name: 'Project C' },
{ id: 4, name: 'Project D' },
],
activeProjectId: 1
},
})
Then add some css to the 'active' class.
For more, See the fiddle
I have the following controller:
app.controller('MainController', ['$scope', function($scope) {
$scope.taskCategories = {
categories: [
'work',
'chores',
'learning'
]
};
$scope.tasklist = {
tasks: [{
title: 'Email Gregory',
category: 'work'
}, {
title: 'Clean the Kitchen',
category: 'chores'
}, {
title: 'AngularJS',
category: 'learning'
}, {
title: 'Hose Car',
category: 'chores'
}, {
title: 'Email Jethro',
category: 'work'
}
]
};
}]);
And am pulling the information through so far like this:
<div>
<li data-toggle="collapse" data-target="#work" class="nav_head workcat collapsed">
Work <span class="arrow"></span>
</li>
<ul class="sub-menu collapse" id="work">
<li ng-repeat="tasks in tasklist.tasks | orderBy:'title' | filter: {category: 'work'}">
{{ tasks.title }}
</li>
<li class="addwork">
<a href="">
<span class="fa-stack"> <i class="fa fa-2x fa-stack-2x fa-circle"></i><i class="fa fa-2x fa-stack-2x fa-plus-circle"></i>
</a>
</span>
</li>
</ul>
This would work fine doing a few times, one for each category, but I am looking to be able to add categories dynamically, and so I am looking for some way to go through the following steps:
So, I’ll need to loop all in categories.
During that loop, I’ll loop through the tasks and print out any task that matches the string of categories.index(1)
Then add 1 to category index and run again, till category.length runs out
I'm unfamiliar with looping inside a loop, and more unfamiliar again with doing it in angular. Anyone have any suggestions?
You could do an outer loop (ng-repeat) on the categories:
<ul class="sub-menu collapse" id="work" ng-repeat="cat in taskCategories.categories">
<li ng-repeat="tasks in tasklist.tasks | orderBy:'title' | filter: {category: cat}">
{{ tasks.title }}
</li>
<li class="addwork">
<a href="">
<span class="fa-stack"> <i class="fa fa-2x fa-stack-2x fa-circle"></i><i class="fa fa-2x fa-stack-2x fa-plus-circle"></i></span>
</a>
</li>
</ul>
Fiddle
Please refer below code snippet
angular.module('app',[]);
angular.module('app').controller('myController',function($scope){
$scope.taskCategories = {
categories: [
'work',
'chores',
'learning'
]
};
$scope.tasklist = {
tasks: [{
title: 'Email Gregory',
category: 'work'
}, {
title: 'Clean the Kitchen',
category: 'chores'
}, {
title: 'AngularJS',
category: 'learning'
}, {
title: 'Hose Car',
category: 'chores'
}, {
title: 'Email Jethro',
category: 'work'
}
]
};
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/js/bootstrap.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<body ng-app="app" ng-controller="myController">
<ul>
<li data-toggle="collapse" data-target=#{{c}} class="nav_head workcat" ng-repeat="c in taskCategories.categories">
<span class="arrow"> {{c}}</span>
<ul class="sub-menu collapse" id={{c}}>
<li ng-repeat="tasks in tasklist.tasks | orderBy:'title' | filter: {category: c}">
{{ tasks.title }}
</li>
</ul>
</li>
</ul>
</body>
Hope this helps!
How can I toggle active class on element if I have the following code?
<div class="searchandfilter">
<span ng-repeat="taxonomy in taxonomies" class="tab-controller" ng-class="{'active': $index == 0}">
<ul>
<li class="tab" ng-click="onClickTab(taxonomy)">{{taxonomy.name}}</li>
</ul>
<span class="tab-content">
<span ng-repeat="child in taxonomy.children">
<input type="checkbox" checked="child.value" />{{child.name}}
</span>
</span>
</span>
On load I need to set the first tab-conroller span to active, which is now correct but I can't toggle the active class onclick. The number of tabs is dynamic, so it can be 1 or 10. Currently it generates the tabs like this:
<span class="tab-controller ng-scope active" ng-class="{'active': $index == 0}" ng-repeat="taxonomy in taxonomies">
<ul>
<li class="tab ng-binding" ng-click="onClickTab(taxonomy)">Tab 1</li>
</ul>
</span>
<span class="tab-controller ng-scope" ng-class="{'active': $index == 0}" ng-repeat="taxonomy in taxonomies">
<ul>
<li class="tab ng-binding" ng-click="onClickTab(taxonomy)">Tab2</li>
</ul>
</span>
You can do this by passing the index and setting a scope variable.
var app = angular.module('app', []);
app.controller('myController', function($scope) {
$scope.taxonomies = [
{name: 'a', children: [{name: 'a', value: false}]},
{name: 'b', children: [{name: 'a', value: true},
{name: 'b', value: false}]}
];
$scope.onClickTab = function(idx) {
$scope.selectedIndex = idx;
};
$scope.selectedIndex = 0;
});
.active {
color: green;
font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app='app' ng-controller='myController'>
<div class="searchandfilter">
<span ng-repeat="taxonomy in taxonomies" class="tab-controller" ng-class="{'active': $index == selectedIndex}">
<ul>
<li class="tab" ng-click="onClickTab($index)">{{taxonomy.name}}</li>
</ul>
<span class="tab-content">
<span ng-repeat="child in taxonomy.children">
<input type="checkbox" ng-model="child.value">{{child.name}}
</span>
</span>
</span>
</div>
</div>
The problem with that approach is if the taxonomies change, the selectedIndex may no longer match up with selected tab so instead of tracking index, you can just track the entire object:
var app = angular.module('app', []);
app.controller('myController', function($scope) {
$scope.taxonomies = [
{name: 'a', children: [{name: 'a', value: false}]},
{name: 'b', children: [{name: 'a', value: true},
{name: 'b', value: false}]}
];
$scope.onClickTab = function(selected) {
$scope.selected = selected;
};
$scope.selected = $scope.taxonomies[0];
});
.active {
color: green;
font-weight: bold;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
<div ng-app='app' ng-controller='myController'>
<div class="searchandfilter">
<span ng-repeat="taxonomy in taxonomies" class="tab-controller" ng-class="{'active': taxonomy === selected}">
<ul>
<li class="tab" ng-click="onClickTab(taxonomy)">{{taxonomy.name}}</li>
</ul>
<span class="tab-content">
<span ng-repeat="child in taxonomy.children">
<input type="checkbox" ng-model="child.value">{{child.name}}
</span>
</span>
</span>
</div>
</div>
You need to have some property in your tabs to be able to compare against the $index in the ng-repeat.
For example:
<div class="tab-controller" ng-class="{'active': $index == currentTab}" ng-repeat="taxonomy in taxonomies">
<ul>
<li class="tab" ng-click="onClickTab(taxonomy.tab)">{{ taxonomy.name }}</li>
</ul>
</div>
And taxonomies should be an array of objects, something like:
var taxonomies = [
{ id: 0, name: 'Tab 1', tab: 'whatever you need here'},
{ id: 1, name: 'Tab 2', tab: 'whatever you need here'},
{ id: 2, name: 'Tab 3', tab: 'whatever you need here'}
];
And when you call your function onClickTab it should set the variable scope.currentTab to the id of the clicked tab.
Hope it helps.
sorry if am wrong,try this
http://plnkr.co/edit/FdueM4rAvd4k6hClK1HR?p=preview
your html will be
<html>
<head>
<script data-require="angular.js#*" data-semver="1.4.0-beta.6" src="https://code.angularjs.org/1.4.0-beta.6/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body ng-app="app">
<div class="searchandfilter" ng-controller="tab-controller">
<span ng-repeat="taxonomy in taxonomies">
<ul ng-class="{'active': $index == selectedIndex}">
<li class="tab" ng-click="onClickTab(taxonomy.id)">{{taxonomy.name}}
<br/>
<span class="tab-content">
<span ng-repeat="child in taxonomy.children">
<input type="checkbox" ng-model="child.value" />{{child.name}}
</span>
</span>
</li>
</ul>
</span>
</div>
</body>
</html>
angular js code will be
var app = angular.module("app",[]);
app.controller('tab-controller',['$scope',function($scope){
$scope.taxonomies = [
{ id: 0, name: 'hello' , children:[{name:"test1",value:true},{name:"test2",value:false}]},
{ id: 1, name: 'how' , children:[{name:"test5", value: false}]},
{ id: 2, name: 'are you',children:[{name:"test4",value: true}]}
];
$scope.onClickTab= function(x){
$scope.selectedIndex= x;
};
}]);
css code will be
.active{
background-color:green;
}
body {
background-color: yellow;
}