I am trying to change the gallery items by matching value, default I want to show All items if click on the Photos i want to show photos. I tried with switch statement its working fine but I am trying to know any other shortest way.
public items = [{
value: 'All',
name: 'All Items'
},
{
value: 'Photos',
name: 'Photo Items'
},
{
value: 'Video',
name: 'Video Items'
},
];
}
.gallery {
margin-top: 30px;
}
.card {
background: whitesmoke;
margin-top: 30px;
}
.data {
display: inline-block;
font-size: 22px;
margin-top: 10px;
margin-left: 30px;
}
<div *ngFor="let item of items" class="nav-li">
<ul>
<li class="value" [value]="item.value">{{item.value}}</li>
</ul>
</div>
<div class="gallery">
<div *ngFor="let item of items" class="card">
<div class="data">{{item.name}}</div>
</div>
</div>
<!--Declare 'displayOption' in your ts file-->
<div *ngFor="let item of items" class="nav-li">
<ul>
<li class="value" [value]="item.value">
<a href="" (click)="displayOption = item.value">
{{item.value}}</a>
</li>
</ul>
</div>
<div class="gallery">
<div *ngFor="let item of items" class="card">
<div class="data" *ngIf="displayOption === item.value || displayOption === 'All'>
{{item.name}}
</div>
</div>
You can filter items by its values
app.component.ts
public items = [{
value: 'All',
name: 'All Items'
},
{
value: 'Photos',
name: 'Photo Items'
},
{
value: 'Video',
name: 'Video Items'
}];
itemsFiltered = this.items;
filterItems(filterBy) {
if (filterBy == 'All') {
this.itemsFiltered = this.items;
} else {
this.itemsFiltered = this.items.filter(m => m.value === filterBy)
}
}
app.component.html
<div *ngFor="let item of items" class="nav-li">
<ul>
<li class="value" [value]="item.value">
{{item.value}}
</li>
</ul>
</div>
<div class="gallery">
<div *ngFor="let items of itemsFiltered" class="card">
<div class="data">{{items.name}}</div>
</div>
</div>
Related
I'm building a Nuxt app and am having trouble with conditional styling. What I'm trying to do is apply a different background color to the active link depending on what page it is. I know I can use .nuxt-link-exact-active to style the active link, but I'm stuck on how to make that different on each page.
I have the links in a component that gets rendered on each page. I've tried using .nuxt-link-exact-active at the page level, but it doesn't get picked up.
Here's what I've got so far, which does change the styling depending on the page, but it does it for all the links, and I only want it on the active link. Please let me know if I can clarify anything. Thanks!
<template>
<nav class="flex-container flex-column mt-1">
<NuxtLink to="/about" class="link" :class="classObject">about</NuxtLink>
<div class="mt-1 flex-container">
<NuxtLink to="/projects" class="link" :class="classObject"
>projects</NuxtLink
>
</div>
<div class="mt-1 flex-container">
<NuxtLink to="/contact" class="link" :class="classObject"
>contact</NuxtLink
>
</div>
</nav>
</template>
<script>
export default {
// apply current route name as a class to the matching div
computed: {
classObject() {
return {
about: this.$route.name === 'about',
projects: this.$route.name === 'projects',
contact: this.$route.name === 'contact',
}
},
},
}
</script>
<style lang="scss" scoped>
.about {
background-color: $near-white;
}
.projects {
background-color: $blue;
}
.contact {
background-color: $yellow;
}
</style>
illustration of what I'm trying to do
Instead of changing .nuxt-link-exact-active at the page level, change it in the layout.
So for example, in layouts/default.vue:
<style>
.nuxt-link-exact-active {
background: red;
}
</style>
I came up with a solution— not sure if it's the best way, but it works. Each link is now preceded by a div that only gets rendered on the corresponding page, otherwise a link is rendered.
<template>
<nav class="flex-container flex-column mt-1">
<div v-if="currentPageName === 'about'" class="box about">
<h2>about</h2>
</div>
<div v-else>
<NuxtLink to="/about" class="link">about</NuxtLink>
</div>
<div v-if="currentPageName === 'projects'" class="box projects">
<h2>projects</h2>
</div>
<div v-else>
<NuxtLink to="/projects" class="link">projects</NuxtLink>
</div>
<div v-if="currentPageName === 'contact'" class="box contact">
<h2>contact</h2>
</div>
<div v-else>
<NuxtLink to="/contact" class="link">contact</NuxtLink>
</div>
</nav>
</template>
<script>
export default {
computed: {
currentPageName() {
return this.$route.name
},
},
}
</script>
<style lang="scss" scoped>
.box {
width: 150px;
height: 150px;
}
.about {
background-color: $near-white;
}
.projects {
background-color: $blue;
}
.contact {
background-color: $yellow;
}
</style>
I think the easiest way to check if the path is active or not is $nuxt.$route.path.
<template>
<ul>
<li>
<nuxt-link :to="links[0].path" :class="{'bg-black text-white': links[0].path == path }">{{ links[0].name }}</nuxt-link>
<nuxt-link :to="links[1].path" :class="{secondStyle: links[1].path == path }">{{ links[1].name }}</nuxt-link>
</li>
</ul>
</template>
<script>
export default {
name: "Header",
data() {
return {
path: null,
links: [
{path: "/link1", name: "Link 1"},
{path: "/link2", name: "Link 2"}
],
};
},
mounted() {
this.path = $nuxt.$route.path;
},
};
</script>
home.vue
<template>
<app-navbar>
<logo title="navbar"></logo>
<div class="navbar-collapse">
<link href="#first" title="first link"></link>
<link href="#second" title="second link"></link>
<link href="#third" title="third link"></link>
</div>
</app-navbar>
</template>
<script>
export default {
name: "Home",
components: {
AppNavbar: () => import('#/components/navbar.vue')
}
}
</script>
navbar.vue
<script>
export default {
name: "AppNavbar",
props: {
title: {
type: String,
default: "navbarDemo"
},
href: {
type: String,
default: "#"
}
},
template: `
<div class="navbar-container">
<component :is="logo">
<div class="navbar-brand">{{ title }}</div>
</component>
<ul>
<component :is="link">
<li class="item">
<a :href="href" class="link">{{ title }}</a>
</li>
</component
</ul>
</div>
</div>
`
};
</script>
I WANT THIS
<div class="navbar-container">
<div class="navbar-brand">navbar</div>
<div class="navbar-collapse">
<ul>
<li class="item">
first link
</li>
<li class="item">
second link
</li>
<li class="item">
third link
</li>
</ul>
</div>
</div>
What am I doing wrong? Is component used differently? I want to use a component and have another component in it in one file (I don't want to have 20 files here just for navbar). Then compose the structure in this way. Possible?
I'm trying a similar HTML structure as here: link
Here is what you need:
home.vue
<app-navbar :links="links">
<template #logo>
<img src=""/>
</template>
</app-navbar>
data() {
return {
links: [
{ href: '#first", title: 'first link' },
{ href: '#second", title: 'secondlink' },
{ href: '#third", title: 'thirdlink' },
]
}
}
navbar.vue
<template>
<div class="navbar-container">
<div class="navbar-brand">
<slot name="logo" />
</div>
<div class="navbar-collapse">
<ul>
<li v-for="link in links" :key="link.href">
<a :href="link.href">{{ link.title }}</a>
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: {
links: Array
}
}
</script>
The logo element is passed through a slot (https://fr.vuejs.org/v2/guide/components-slots.html).
You understood <component> wrongly :p <component> do not declare a component, it's only a way to use a component when its name might change.
Instead of writing
<comp1 v-if="test" /> <comp2 v-else /> you could write <component :is="test ? 'comp1" : 'comp2' />. But comp1 and comp2 components still need to be declared somewhere and imported.
Did you check https://v2.vuejs.org/v2/guide/components.html#Dynamic-Components ?
EDIT: If you want to customize links with scoped-slots:
home.vue
<app-navbar :links="links">
<template #logo>
<img src=""/>
</template>
<template #link="{ href, title }">
<a :href="href">{{ title }}</a>
</template>
</app-navbar>
data() {
return {
links: [
{ href: '#first", title: 'first link' },
{ href: '#second", title: 'secondlink' },
{ href: '#third", title: 'thirdlink' },
]
}
}
navbar.vue
<template>
<div class="navbar-container">
<div class="navbar-brand">
<slot name="logo" />
</div>
<div class="navbar-collapse">
<ul>
<li v-for="link in links" :key="link.href">
<slot name="link" :href="link.href" :title="link.title" />
</li>
</ul>
</div>
</div>
</template>
<script>
export default {
props: {
links: Array
}
}
</script>
So the looped links are passed through the slot so the parent is handling the rendering
I've used list rendering to create a menu with items from an array. I'm now trying to create a new data property which holds the index of the array item when the item of the menu is mouse-overed but I'm not sure of how to do it. Here's what I've tried:
HTML:
<header>
<nav class="pure-menu pure-menu-horizontal">
<ul id="topmenu" class="pure-menu-list">
<li v-for="item in topmenu" class="pure-menu-item">
<a v-bind:href="item.url" v-on:mouseover="mouseOver" class="pure-menu-link">{{ item.title }}</a></li>
<li v-for="item in topmenu.submenus" class="pure-menu-item">
<a v-bind:href="item.url" class="pure-menu-link">{{ item.title }}</a></li>
</ul>
<div class="pure-menu">
<ul id="submenu" class="pure-menu-list">
</ul>
</div>
</nav>
</header>
JS:
var vueinst = new Vue({
el: '#vuemain',
data: {
topmenuitem : 0,
topmenuhover : false,
topmenu: [
{ title:'Home', url:'/', submenus: [] },
{ title:'About', url:'/about',
submenus: [
{ title:'Who we are', url:'/about#us' },
{ title:'What we do', url:'/about#store' },
{ title:'Our range', url:'/about#range' }
]
},
{ title:'Contact Us', url:'/contact',
submenus: [
{ title:'Information', url:'/contact#info' },
{ title:'Returns', url:'/contact#return' },
{ title:'Locate Us', url:'/contact#locate' }
]
}
]
},
methods: {
mouseOver: function(){
this.topmenuitem = this.topmenu.index;
}
}
});
I'm pretty new to web developing, please help me with this. Thank you!
In your html pass the index of the current item to the mouseOver function like the following:
<header>
<nav class="pure-menu pure-menu-horizontal">
<ul id="topmenu" class="pure-menu-list">
<li v-for="item in topmenu" :key="item.index" class="pure-menu-item">
<a v-bind:href="item.url" v-on:mouseover="mouseOver(item.index)" class="pure-menu-link">{{ item.title }}</a></li>
<li v-for="item in topmenu.submenus" class="pure-menu-item">
<a v-bind:href="item.url" class="pure-menu-link">{{ item.title }}</a></li>
</ul>
<div class="pure-menu">
<ul id="submenu" class="pure-menu-list">
</ul>
</div>
</nav>
</header>
And you should bind key in the v-for like :key="item.index". And then in your mouseOver function accept the index of the item as a parameter and push the element on that index into your new array ass follows.
mouseOver: function(index){
this.topmenuitem.push(index);
}
This way you could get the index of all items hovered on.
What i am trying to do is add a row div after every 3 colum divs
Example Output need:
<div class="row">
<div class="col-md-6"></div>
<div class="col-md-6"></div>
<div class="col-md-6"></div>
</div>
I have an array of products i am iltrating like this
<div class="row" *ngFor="let p of relatedProperties;let i = index">
<div class="col-md-6" *ngIf="relatedProperties[i].title !== undefined">{{ relatedProperties[i].title }}</div>
<div class="col-md-6" *ngIf="relatedProperties[i].title !== undefined">{{ relatedProperties[i].title }}</div>
<div class="col-md-6" *ngIf="relatedProperties[i].title !== undefined">{{ relatedProperties[i].title }}</div>
</div>
But the problem is that my every row prints same title on one iltration and second on next iltration
Current output
<div class="row">
<div class="col-md-6">Title1</div>
<div class="col-md-6">Title1</div>
<div class="col-md-6">Title1</div>
</div>
<div class="row">
<div class="col-md-6">Title2</div>
<div class="col-md-6">Title2</div>
<div class="col-md-6">Title2</div>
</div>
<div class="row">
<div class="col-md-6">Title3</div>
<div class="col-md-6">Title3</div>
<div class="col-md-6">Title3</div>
</div>
Desired Output
<div class="row">
<div class="col-md-6">Title1</div>
<div class="col-md-6">Title2</div>
<div class="col-md-6">Title3</div>
</div>
<div class="row">
<div class="col-md-6">Title4</div>
<div class="col-md-6">Title5</div>
<div class="col-md-6">Title6</div>
</div>
<div class="row">
<div class="col-md-6">Title7</div>
<div class="col-md-6">Title8</div>
<div class="col-md-6">Title9</div>
</div>
If you split your Array into subarrays with always 3 titel's then you can easy loop through this Array in your template.
https://ng-run.com/edit/zZsztdvTOTpzbUC5Buuj?open=app%2Fapp.component.ts
component html
<div class="row" *ngFor="let row of newTitleArr; let i = index">
<div class="col" *ngFor="let col of newTitleArr[i]">{{ col.title }}</div>
</div>
component ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
titleArr = [
{ title: 'title1' },
{ title: 'title2' },
{ title: 'title3' },
{ title: 'title4' },
{ title: 'title5' },
{ title: 'title6' },
{ title: 'title7' },
{ title: 'title8' },
{ title: 'title9' },
{ title: 'title10' },
{ title: 'title11' },
{ title: 'title12' },
{ title: 'title13' },
];
newTitleArr:any[];
ngOnInit() {
this.newTitleArr = this.splitArr(this.titleArr, 3)
}
splitArr(arr, size) {
let newArr = [];
for(let i = 0; i< arr.length; i += size) {
newArr.push(arr.slice(i, i+size));
}
return newArr;
}
}
Maybe this works, but Im unsure
<ng-container *ngFor="let p of relatedProperties; let i = index">
<div class="row" *ngIf="(i + 1) / 3 === 1">
<div class="col-md-6" *ngIf="relatedProperties[i - 2].title != null">{{ relatedProperties[i].title }}</div>
<div class="col-md-6" *ngIf="relatedProperties[i - 1].title != null">{{ relatedProperties[i].title }}</div>
<div class="col-md-6" *ngIf="relatedProperties[i].title != null">{{ relatedProperties[i].title }}</div>
</div>
</ng-container>
Also, I gotta say this feels pretty hacky, but if this is what you request, this should work
edit:
Note that strict null (a == null) is better than checking for undefined (a === undefined), as it will check for both undefined or null. In your case title != null.
Also, you could build an iterable that holds the structure you want in a cleaner way.
instead of having [title1, title2, title3, title4, title5, title6...] you should try to have [[title1, title2, title3], [title4, title5, title6], ...] which is way cleaner and allows you to simply have two *ngFors inside your template
<element1 *ngFor="let innerArray of myArray; let i = index">
<element2 *ngFor="let title of innerAray; let j = index">
</element2>
</element1>
And finally, I suggest you avoid calling a variable 'p', that's bad practice.
You can use this to add a row after every 3 columns.
<ng-container *ngFor="let p of relatedProperties; let i = index">
<div class="row" *ngIf="(i%3)==0">
<div class="col-md-6" *ngFor="let p of relatedProperties.slice(i, i+3)>
<span *ngIf="relatedProperties[i].title !== undefined"> {{ relatedProperties[i].title }} </span>
</div>
</div>
</ng-container>
I have a JSON file which has this structure:
{ "short_title":"HB_START_SHORT_TITLE",
"tips{"1":"HB_START_TIPS_1_1","2":"HB_START_TIPS_1_2","3":"HB_START_TIPS_1_3","4":"HB_START_TIPS_1_4"},
},
I would like to print the nested item "tips" as a slider with previous-next buttons.
Therefore I wrote this code in my HTML below:
<ul class="sb-parentlist">
<div data-ng-repeat="parts in data track by $index">
<li>
<div class="sb-open" ng-show="showDetails">
{{parts.short_text|translate}}
<br>
<li><span class="sb-text-title" href="#" ng-click="OpenTips = ! OpenTips"><b>Tips</b></span>
<span ng-show="OpenTips" class="sb-open">
<br>
<div ng-repeat="data in parts.tips track by $index" ng-class="{'tips-hide': $index > $index + 1}">
{{data|translate}}
<br>
<div class="keys">
<button type="button" class="btn btn-pre" ng-click="$index = $index > 1 ? $index - 1 : 1">Previous</button>
<button type="button" class="btn btn-next" ng-click="$index = $index < data.length ? $index + 1 : data.length">Next</button>
</div>
</div>
</span>
</li>
</ul>
</div>
</li>
</div>
</ul>
and the tips-hide class in CSS:
.tips-hide {
left: -100px !important;
opacity: 0 !important;
}
.sb-open {
display: block;
height: auto;
opacity: 1;
transition:all 0.6s ease;
li {
display: block;
}
}
But what I am getting is every element in the list one after the other, with the buttons on the bottom of each one of them.
ScreenShot below:
ng-repeat on object can't be tracked by index (at least not in that way)
I've changed few parts on code to simulate on code snippet, see if it helps.
var app = angular.module('app', []);
app.controller('DemoCtrl', function($scope) {
this.openTips = true;
$scope.tipsIndex = 1;
this.info = [{ "short_title":"HB_START_SHORT_TITLE",
"tips" : {"1":"HB_START_TIPS_1_1","2":"HB_START_TIPS_1_2","3":"HB_START_TIPS_1_3","4":"HB_START_TIPS_1_4"}
}];
$scope.decrement = function() {
if($scope.tipsIndex > 1){
$scope.tipsIndex = $scope.tipsIndex - 1;
}
};
$scope.increment = function(partsIndex) {
if($scope.tipsIndex < partsIndex){
$scope.tipsIndex = $scope.tipsIndex + 1;
}
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="app">
<div ng-controller="DemoCtrl as demo">
<ul class="sb-parentlist">
<ul class="sb-parentlist">
<div data-ng-repeat="parts in demo.info track by $index">
<li>
<div class="sb-open">
{{parts.short_title}}
<br>
<li><span href="#" ng-click="demo.openTips = !demo.openTips"><b>Tips</b></span>
<span ng-show="demo.openTips" class="sb-open">
<br>
<div ng-repeat="(key, value) in parts.tips" ng-show="key == tipsIndex">
{{key}}
{{value}}
<br>
<div class="keys">
{{Object.size(parts.tips)}}
</div>
</div>
<button ng-click='decrement()'>Previous</button>
<button type="button" class="btn btn-next" ng-click="increment(3)">Next</button>
</span>
</li>
</div>
</ul>
</li>
</div>
</ul>
</ul>
</div>
</body>