Accessing index of a v-for loop in a sibling? (VueJS) - vue.js

I'm trying to produce the following (rendering div elements, broken up by a clearfix after every four elements):
<div class="col-md-3 form-group"></div>
<div class="col-md-3 form-group"></div>
<div class="col-md-3 form-group"></div>
<div class="col-md-3 form-group"></div>
<div class="clearfix></div>
....
And wondering if anything as the code below is possible in VueJS or can someone help me out with an alternative?.
<div v-for="(sku, n) in sku_pattern" :key="n" class="col-md-3 form-group"></div>
<div v-if="!((n+1)%4)" class="clearfix"> <!-- I know this won't work outside the scope of the previous element. -->

You can use <template> tag with v-for to render a block of multiple elements:
<template v-for="(sku, n) in sku_pattern">
<div class="col-md-3 form-group">
</div>
<div v-if="!((n+1)%4)" class="clearfix">
</template>
Reference document

Just in the addition of #ittus answer,
The solution to loop through siblings is the use of the template tag.
While, the template cannot be keyed, instead you have to put key on children's elements, like this will solve your problem.
<template v-for="(sku, n) in sku_pattern">
<div class="col-md-3 form-group" :key='n'>
</div>
<div v-if="!((n+1)%4)" class="clearfix" :key='n'>
</template>

Related

Vue JS: How to make two Vue Instances to work together on the same page?

I created a recipe website, you can find it here https://hungry-vegetarian.com/.
The tab on the index page is a vue instance. I'm trying to create a search bar that is also a vue instance.
The problem occurs when I try to display searched recipes on the index page. It just shows the search result on top of the search bar.
Ideally, only searched recipes should appear on the tab just like they are now but without any indications on top of the tab like Breakfast, Salad, Bakery, etc.
I don't know how to make two objects work together. For now, they work separately without communicating with each other.
SEARCH
<div id="search">
<div class="main-search">
<h1 class="search-question">What are you in the mood for?</h1>
<div class="search-box">
<input type="text" v-model="searchQuery" class="input-search" placeholder="Bread">
<button class="btn-search"><i class="fa fa-search"></i></button>
</div>
</div>
<div class="container">
<div class="recipe" v-for="post in filteredList">
<div v-if="searchQuery">
<a v-bind:href="post.url" class="recipe-card__card-link" target="_blank">
<img v-bind:src="post.image" alt="" class="recipe-card__image"/>
<div class="recipe-card__text-wrapper">
<h2 class="recipe-card__title">{{post.name}}</h2>
<div class="recipe-card__details-wrapper">
<p class="recipe-card__excerpt">{{post.body}}</p>
<a v-bind:href="post.url" class="recipe-card__read-more">Read more <i class="fa fa-arrow-right"></i></a>
</div>
</div>
</a>
</div>
</div>
</div>
</div>
</div>
tab
<main id="tab">
<header>
<nav>
<ul>
<div id="arrow">
<span></span>
<span></span>
<span></span>
</div>
<li v-for="(tab, tabName) in tabs" :key="tabName">
<button class="tab" #click="setTabActive(tabName)" :class="{'active': tabName === activeTab}">
<span class="tab-copy">{{ tabName }}</span>
<span class="tab-background">
</span>
</button>
</li>
</ul>
</nav>
</header>
<article>
<div class="container">
<transition name="fade" mode="out-in" appear :duration="500">
<tab-content v-for="(tabContent, t) in tabs" :data="tabContent" :key="'content'+t" v-if="t === activeTab" inline-template>
<div class="content-wrapper">
<div class="recipes" v-for="(recipe, i) in data.recipes" :key="i">
<a v-bind:href="recipe.url" class="recipe-card__card-link"></a>
<img :src="recipe.image" alt="" class="recipe-card__image">
<div class="recipe-card__text-wrapper">
<h2 class="recipe-card__title">{{recipe.name}}</h2>
<div class="recipe-card__details-wrapper">
<p class="recipe-card__excerpt">{{recipe.body}}</p>
<a v-bind:href="recipe.url" class="recipe-card__read-more">Read more <i class="fa fa-arrow-right"></i></a>
</div>
</div>
</div>
</div>
</tab-content>
</transition>
</div>
</article>
</main>
I tried to combine instances search and tab into just one instance tab, but it always gives me a Vue warning:
[Vue warn]: Property or method "searchQuery" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property.
Also, I feel like I can have just the wrong approach to this problem I am trying to solve. Please, any suggestions are welcome. I am stuck.

How to display only one element of an array in Vue.js?

I have the following object with a "multimedia" array:
I only need one of the urls, but no idea how ot get it
<div
class="card mb-3"
style="max-width: 540px;"
v-bind:key="news.artices"
v-for="news in newsList" >
<div class="row no-gutters">
<div class="col-md-8">
<div class="card-body">
//this doesn't work
<p v-for="image in news.multimedia" v-bind:key="image">
{{image[0].url}}
</p>
//this works, but shows all
<p v-for="image in news.multimedia" v-bind:key="image">
{{image.url}}
</p>
<h5 class="card-title">{{news.title}}</h5>
</div>
</div>
</div>
</div>
If you want to display only one element of the multimedia array, then you don't need to use v-for unnecessarily. You can simply use:
<p v-bind:key="image" v-if="news.multimedia && news.multimedia.length">
{{ news.multimedia[0].url }}
</p>
Also, you can use v-if to make sure this div is only rendered if news.multimedia has a valid value and it not an empty array.
It looks like multimedia is an array of objects, so you could do: news.multimedia[0].url.

Alternating v-for DOM elements on same level

I am trying to have two alternating loops after each other on the same level. If I wrap it in a parent element and loop thru it brakes the styles.
Here is an example of what I am trying to do:
<div v-for="category in items" class="cat-name">{{ category.name }}</div>
<div v-for="category in items" class="cat-meta">{{ category.metaData }}</div>
Wanted Result:
<div class="cat-name">name1</div>
<div class="cat-meta">metadata1</div>
<div class="cat-name">name2</div>
<div class="cat-meta">metadata2</div>
<div class="cat-name">name3</div>
<div class="cat-meta">metadata3</div>
and so on...
I really hope that this is possible since it completely breaks the styles when I tried:
<div v-for="category in items">
<div class="cat-name">{{ category.name }}</div>
<div class="cat-meta">{{ category.metaData }}</div>
</div>
Really appreciate any help and input.
Thanks, -J
You could wrap both your elements in a template tag.
Unlike a basic tag, this one will not be rendered in the DOM.
<template v-for="category in items">
<div class="cat-name">{{ category.name }}</div>
<div class="cat-meta">{{ category.metaData }}</div>
</template>

Create a two column layout with skeleton framework?

I am new to Skeleton framework and am trying to build a two column layout for a blog project. So far this is what I have:
<section class="list-posts">
<div class="container">
<div class="row">
<div class="nine columns posts">
[NINE COLUMNS]
</div><!--nine columns-->
<div class="three columns aside">
[ASIDE]
[/ASIDE]
</div>
</div><!--row-->
</div>
but as more columns are added to the .posts class the aside collapses. Your help will be appreciated.
Not sure if I understand your problem, but if you are trying to nest columns you need to put a row div within the nine columns, and end the row(s) for every twelve columns.
If this is not the case, could you please provide a more specific clarification of your problem with a link or image.
Well after waiting for some hours without getting any help, i decided to get my hands dirty, this is what i did
<section class="content">
<div class="container">
<div class="row">
<!--LIST ALL THE POSTS HERE-->
<div class="twelve columns">
<div class='twelve'>
<div class='row single-entry'>
<div class='six columns'>
...
</div>
<div class='six columns'>
...
</div>
</div><!--row-->
</div><!--twelve-->
</div><!--row-->
<!-- ASIDE-->
<div class="four columns aside border-between">
<div class="row ">
<div class="twelve columns">
<div class="twelve">
<h4 class="standing">Recommendations</h4>
</div>
<div class="twelve columns recommended-articles">
<div class="three columns">
<img src="images/footer.png" class="u-max-full-width">
</div>
<div class="nine columns recommended-articles-details">
<h6 class="article-title">4 top SEO trends for 2017</h6>
<p class="author_name">Joel Orok</p>
</div>
</div>
</div>
</div>
</div>
</section>

Nested columns in panel heading

I wanted my panel heading to contain some text and a button, the former being left-aligned and the latter, right-aligned. But as soon as I apply the class row to my panel header, it breaks out of the parent div and takes up what I believe to be the container width.
Here's the code I'm using:
<div class="panel panel-primary">
<div class="panel-heading row">
<h4 class="col-md-11">Manage Your Subscriptions</h4>
<div>
<a href="#" class="btn btn-default col-md-1" >Log out</a>
</div>
</div>
<div class="panel-body">
</div>
</div>
And here's the result:
How can I correct this?
It seems to me like you just need to move the "row" to be inside the "panel-heading" rather than on the same level, as they both have relative CSS positioning properties. I tried the following code:
<div class="panel panel-primary">
<div class="panel-heading">
<div class="row">
<h4 class="col-md-11">Manage Your Subscriptions</h4>
<div class="col-md-1">
<a href="#" class="btn btn-default" >Log out</a>
</div>
</div>
</div>
<div class="panel-body">
Stackoverflow rocks!
</div>
</div>
and it gave me this output (which is what you're looking for, I hope):
I hope that helps
EDIT: I tried using "pull-right" as others have suggested and it seems to create more troubles as it messes the top/bottom margins as well since it makes the display block relative to container (Which I would generally recommend against doing, even if it works for you).
EDIT2: moved the "col-md-1" class into an encapsulating "div" to solve the button's margins' issue.
May be you need something like following?
<div class="panel panel-primary">
<div class="panel-heading">
<div class="row">
<div class="col-md-10 col-sm-10">
<h4>Manage Your Subscriptions</h4>
</div>
<div class="col-md-2 col-sm-2">
<a href="#" class="btn btn-default pull-right" >Log out</a>
</div>
</div>
</div>
<div class="panel-body">
</div>
</div>
Let me know if it works
You can use pull-left and pull-right instead of grid system, so the components will be rendered on single line even on small screen (if there is enough space):
<div class="panel panel-primary">
<div class="panel-heading">
<h4 class="pull-left">Manage Your Subscriptions</h4>
<span class="pull-right">
<a href="#" class="btn btn-default" >Log out</a>
</span>
<div class="clearfix"> </div>
</div>
<div class="panel-body">
</div>
</div>