Conditional Styling in Svelte Loop - javascript

Has anyone used Svelte in their projects? I just have a small question. Let's say you are looping through an array and displaying the data in the array. And there are 4 objects in the array. If I only want to style the first iteration (bluma). How do I do it?
let items = [
{ icon: 'book', title: 'bulma', tags: ['public', 'sources'] },
{ icon: 'book', title: 'marksheet', tags: ['private'] },
{ icon: 'book', title: 'minireset.css', tags: ['public', 'sources'] },
{ icon: 'code-branch', title: 'daniellowtw/infboard', tags: ['public', 'forks'] },
{ icon: 'code-branch', title: 'mojs', tags: ['private'] }
]
{#each filteredItems as item}
<a class="panel-block {item.}">
<span class="panel-icon">
{#if item.icon === "code-branch"}
<i class="fas fa-code-branch" aria-hidden="true"></i>
{:else if item.icon ==="book"}
<i class="fas fa-book" aria-hidden="true"></i>
{/if}

Whenever a pure CSS approach is available, I would rather use that. Here you could make use of the :first-child selector:
<div class="panel-items">
{#each filteredItems as item}
<a class="panel-block">
<span class="panel-icon">
{#if item.icon === "code-branch"}
<i class="fas fa-code-branch" aria-hidden="true"></i>
{:else if item.icon ==="book"}
<i class="fas fa-book" aria-hidden="true"></i>
{/if}
</span>
</a>
{/each}
</div>
<style>
.panel-block {
/* general panel block styling */
}
.panel-block:first-child {
/* first panel block style overrides */
}
</style>
Note that the entire loop is held within its own container div in order to make sure the first item in the loop is indeed the first child of its parent container.

This can be done by using the index provided as a second argument of the #each block:
{#each filteredItems as item, i}
<span style="color:{i === 0 ? 'green' : 'red'}">
{item.title}
</span>
{/each}
Reference: Each block in svelte tutorial.

Related

How to assign v-on dinamically with v-for

I have a code in Vue that creates the elements of a menu using a v-for, and each element must have a different method when it's clicked.
So far I have this:
<span v-for="(menuItem, index) in menuItems" :key="index">
<li>
<a id="listItem">
<i class="bx" :class="menuItem.icon || 'bx-square-rounded'" />
<span class="links_name" v-on:click=menuItem.click>{{ menuItem.name }}</span>
</a>
<span class="tooltip">{{
menuItem.tooltip || menuItem.name
}}</span>
</li>
</span>
How can I assign different funcions on the v-on?
You can make the listener function as a node in the object list.
Sample Implementation
const app = new Vue({
el: '#app',
data() {
return {
list: [{
name: 'lg',
age: 27,
onClick: function() {
console.log("First Item Clicked");
}
}, {
name: 'camile',
age: 27,
onClick: function() {
console.log("Second Item Clicked");
}
}]
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.4.0/vue.js"></script>
<body>
<div id="app">
<ul>
<li v-for="(item, index) in list" :key="item.name">
{{item.name}} - {{item.age}}
<button #click="item.onClick()">
Click Me
</button>
</li>
</ul>
<input type="text" v-model="list[0].name">
</div>
</body>

how to render the correct component in routes NextJs

I have a problem when I change routes. Between pages it renders me fine. But when I need a dynamic route it does not render me.
In routes I have the folder uw and inside [table].js
When I put the manual routes uw/first and I want to go to uw/second, the first one does render well and then the second one sticks to the style of the first one and it does not bring me the correct data for that view
const menuItems = [
{
href: '/dashboard',
title: 'Inicio',
icon: 'fluent:home-16-filled',
},
{
href: '/uw/primera' ,
title: 'Cartera',
icon: 'bxs:user',
},
{
href: '/uw/segunda',
title: 'Cartera',
icon: 'bxs:user',
},
];
and then return the routes
<div>
<aside className="main-aside">
<div className="main-aside-image">
<Image
src="/logo-castor.png"
alt=""
width={198}
height={32}/>
</div>
<nav>
<ul className="main-aside-items">
<div className="main-aside-categories">
{menuItems.map(({ href, title, icon }) => (
<li className="main-aside-item-categories" key={title}>
<Link href={href}>
<a
className={`flex p-2 bg-fuchsia-200 rounded hover:bg-fuchsia-400 cursor-pointer ${
router.asPath === href && 'bg-fuchsia-600 text-white'
}`}
>
{title}
</a>
</Link>
</li>
))}
</div>
</ul>
</nav>
</aside>
</div>
You're using the title as the key inside the map, since the title is the same between uw/primera and uw/segunda it won't update the component.
Changing the key to the href could solve that.
<li className="main-aside-item-categories" key={title}>
to
<li className="main-aside-item-categories" key={href}>

I want to show only one input clicked (on vue.js)

I would like to show an input on the click, but being in a for loop I would like to show only the clicked one
<div v-for="(todo, n) in todos">
<i class="fas fa-minus ml-2"></i>
<li class="mt-2 todo">
{{ todo }}
</li>
<li class="button-container">
<button class="ml-1 btn btn-primary rounded-circle btn-sm" v-if="isHidden" v-on:click="isHidden = false"><i
class="THIS-CLICK"></i></button>
<input class="ml-5 border border-primary rounded" v-if="!isHidden" v-model="todo">
<button class="ml-1 btn btn-success rounded-circle btn-sm" v-if="!isHidden" v-on:click="isHidden = true"
#click="modifyTodo(n, todo)"><i class="far fa-save"></i></button>
</li>
</div>
I would like that on clicking on THIS-CLICK, only one input (that of the button clicked) is visible, but being in a for loop I don't know if it can be done
I would suggest to change the structure a bit in your app. You can clean up your code a lot by using v-if inside the button instead of two different buttons.
Also, moving as much javascript out from the markup as possible is a good practice.
I have an example below where this is done.
Regarding your question, you would have to add the key to each todo item.
new Vue({
el: "#app",
data() {
return {
todos: [{
name: 'wash hands',
isHidden: true
},
{
name: 'Stay home',
isHidden: true
}
],
};
},
methods: {
toggleTodo(n, todo) {
const hidden = todo.isHidden;
if (hidden) {
this.modifyTodo(n, todo);
todo.isHidden = false;
} else {
todo.isHidden = true;
}
},
modifyTodo(n, todo) {
//Some logic...
}
},
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<div id="app">
<div v-for="(todo, n) in todos">
<i class="fas fa-minus ml-2"></i>
<li class="mt-2 todo">
{{ todo.name }}
</li>
<li class="button-container">
<input class="ml-5 border border-primary rounded" v-if="!todo.isHidden" v-model="todo.name">
<button #click="toggleTodo(n, todo)">
<i v-if="todo.isHidden" class="THIS-CLICK">click-this</i>
<i v-else class="far fa-save">save</i>
</button>
</li>
</div>
</div>
If you cannot do this, you could go with adding a new key to data like: hiddenTodos that would be an array of ids/a unique identifier to the todo you selected to hide.
in the template, it would be something like this:
<button #click="hiddenTodos.push(todo)">
...
<div v-if="hiddenTodos.includes(todo)"

how to toggle 3 or more font-awesome icons dynamically in vue.js

i am creating a rock-paper-scissors mini game with vue and i try to find a way to toggle classes like variables. for example:
<template>
<div id="human">
<div class="text-center">
<div class="h2 mb-5">Human</div>
<!-- PLEASE CHECK BELOW HERE -->
<i class="play-hand far fa-hand-{{ iconName }}"></i>
<!-- OR -->
<i class="play-hand far {{ icon }}"></i>
<div class="h3 mt-4">{{ activeHand }}</div>
<div class="row select-hand mt-4">
<div class="col-md-4">
<i class="far fa-hand-rock" #click="setHand(hands[0])"></i>
</div>
<div class="col-md-4">
<i class="far fa-hand-paper" #click="setHand(hands[1])"></i>
</div>
<div class="col-md-4">
<i class="far fa-hand-scissors" #click="setHand(hands[2])"></i>
</div>
</div>
</div>
</div>
</template>
i marked with a commentary. I am pretty sure you get what i want to do.
I don't want to use document.querySelector() for this.
<script>
export default {
data: () => {
return {
activeHand: 'Choose a Hand',
hands: [
{
name: 'Rock',
strength: 'scissor',
weakness: 'paper',
icon: 'fa-hand-rock'
},
{
name: 'Paper',
strength: 'rock',
weakness: 'scissor',
icon: 'fa-hand-paper'
},
{
name: 'Scissor',
strength: 'paper',
weakness: 'rock',
icon: 'fa-hand-scissors'
}
]
}
},
methods: {
setHand (hand) {
console.log(hand.name)
this.activeHand = hand.name
console.log(hand.icon)
let playHandSelector = document.querySelector('.play-hand')
playHandSelector.classList.remove(this.activeHand.includes(hand))
playHandSelector.classList.add(hand.icon)
}
}
}
</script>
<style lang="scss">
#human .far {
transform: rotate(90deg);
}
</style>
There must be a vue way to toggle a class dynamically by name. maybe without a true/false toggeling?
You have to use Vue's v-bind directive for class bindings and put any variable usage into that markup. Take a look at the documentation here.
Eventually your code could look like this.
<i class="play-hand far" :class="icon"></i>
Keep in mind to use proper class binding syntax in either using objects or arrays.

Append element in DOM from array

I have:
<div *ngFor="let item of items">
<h2>Hello {{item.name}}</h2>
</div>
My items:
items = [
{
name: 'David',
star: 5
},
{
name: 'George',
star: 2
},
{
name: 'Michael',
star: 0
},
{
name: 'Tim',
star: 1
},
]
They render:
Hello Tim
etc.
How to add:
<i class="fa fa-star"></i>
above h2
when in array:
star: 1
etc?
Something like this:
if (this.items.star == 2) {
<i class="fa fa-star"></i>
<i class="fa fa-star"></i>
}
(It's just an example "if statement" to understand what's going on)
My PLUNKER:
https://plnkr.co/edit/lfZT6FwenhYkQf1MUx9E?p=preview
You can use the *ngIf template decorator this way:
<div *ngFor="let item of items">
<i class="fa fa-star" *ngIf="item.star === 1></i>
<h2>Hello {{item.name}}</h2>
</div>
See more examples and read more about it here
*ngIf: Conditionally includes a template based on the value of an expression.

Categories