Vuejs Html tag / attribute in data() - vue.js

I need to do {{item.icon}} pull as a html data not string but ı don't know how to do that, is there are anyway to do that please help me out
I have this code:
<div class="box my-5" v-for="(item, index) in items" :key="index" >
<div class="innerBox">
<router-link to="/ninethPage">
<div class="card Fcard d-flex flex-row justify-content-center align-items-center" style="padding: 1rem 2rem !important">
<span v-html="icon"> </span>
<p>{{item.title}}</p>
</div>
</router-link>
<router-view></router-view>
</div>
</div>
</div>
export default {
el: '#app',
data() {
return {
items: [
{title: 'Android', icon: <i class="fab fa-android mx-3 img-fluid" style="font-size: 1.5rem;" ></i>},
{title: 'IOS', icon: <i class="fab fa-apple mx-3 img-fluid" style="font-size: 1.5rem;" ></i>}
]
}
},
components:{
Header
}
}
`

icon: <i class=... is JSX syntax that creates an element and needs to be used with render function instead of a template. It should be a string, icon: '<i class=...'.
There is no icon property, it should be <span v-html="item.icon">.
It's impractical to specify the whole icon element. If only <i> classes differ, it can be icon: 'fa-android', and be used with:
<i class="class="fab mx-3 img-fluid" style="font-size: 1.5rem" :class="item.icon"/>

Related

Accessing Vuex data within dynamic _id.vue page - Vue/Nuxt

I want to access my user details stored in the state when visiting a dynamic (_id.vue) page. I have set the id of the page like this after using the link to the page:
data() {
return {
selectedTutor: null,
id: this.$route.params.id,
}
},
But now I need to define the selectedTutor by searching the id within the data in the vuex state. I was trying to do something like this:
created() {
this.selectedTutor = this.$store.state.tutors.find((tutor) => tutor.id === this.id)
},
But everything stays undefined. So when id equals to the id within the object, that object needs to be set as selectedTutor so I can access all the necessary data to be displayed on the page.
Here you can see the Vuex state
EDIT
_id.vue page
<template>
<div>
<section>
<div>
<h3>
{{ id }}
</h3>
</div>
</section>
</div>
</template>
<script>
import { mapState } from 'vuex'
export default {
name: 'TutorPage',
/* eslint-disable vue/require-prop-types */
layout: 'app',
props: ['id'],
middleware: 'auth',
data() {
return {
selectedTutor: null,
}
},
computed: {
...mapState(['tutors']),
},
created() {
this.selectedTutor = this.$store.state.tutors.find(
(tutor) => tutor.id === this.id
)
},
}
</script>
MainResult Page
<base-grid>
<ul id="tutors" class="grid grid-cols-2 gap-6">
<tutor-item
v-for="tutor in tutors"
:id="tutor.id"
:key="tutor.id"
:name="tutor.attributes.name"
:rate="student.hourlyRate"
:subject="student.subject"
:description="student.biography"
:profile-image="student.imageUrl"
:image-alt="student.imageAlt"
:age="student.age"
:rating="student.rating"
:total-reviews="student.reviewCount"
class="overflow-hidden bg-white border rounded-lg shadow-md"
>
</tutor-item>
</ul>
</base-grid>
Tutor Item (the resultcard)
<template>
<div>
<li>
<div class="flex">
<div class="w-2/3">
<img
class="flex-shrink-0 object-cover w-full h-64 mx-auto bg-gray-200"
:src="profileImage"
:alt="imageAlt"
/>
</div>
<div class="p-6">
<div
class="text-xs font-semibold leading-snug tracking-wide text-gray-500 uppercase"
>
{{ subject }} • {{ age }} jaar
</div>
<NuxtLink :to="'/tutors/' + id">
<h4 class="text-lg font-semibold leading-5 tracking-wide">
{{ name }}
</h4>
</NuxtLink>
<div class="mt-2">
{{ rate }}€
<span class="text-sm text-gray-600">per uur</span>
</div>
<div class="mt-2">
<span class="font-semibold text-light-blue-800"
>{{ rating }}/5 sterren</span
>
<span class="text-sm text-gray-600 truncate">
(na {{ totalReviews }} reviews)
</span>
</div>
<div class="mt-2">{{ description }}</div>
<div>
<div class="mt-4 text-sm font-semibold text-gray-600">
<span>MA</span>
<span
class="inline-block leading-7 text-center text-gray-100 bg-yellow-400 bg-opacity-50 w-7 h-7 rounded-xl"
>DI</span
>
<span>WO</span>
<span
class="inline-block leading-7 text-center text-gray-100 bg-yellow-400 bg-opacity-50 w-7 h-7 rounded-xl"
>DO</span
>
<span
class="inline-block leading-7 text-center text-gray-100 bg-yellow-400 bg-opacity-50 w-7 h-7 rounded-xl"
>VR</span
>
<span>ZA</span>
<span>ZO</span>
</div>
</div>
</div>
</div>
</li>
</div>
</template>
<script>
export default {
/* eslint-disable vue/require-prop-types */
name: 'TutorItem',
props: [
'id',
'firstName',
'lastName',
'name',
'rate',
'subject',
'age',
'rating',
'totalReviews',
'description',
'profileImage',
'imageAlt',
],
computed: {
fullName() {
return this.firstName + ' ' + this.lastName
},
tutorsDetailsLink() {
return this.$route.path + '/' + this.id
},
},
}
</script>
<style></style>
EDIT
Whoops, what a mistake. It was returning the id as a string but I needed a number. This is why it returned undefined. It is solved now! Thanks

vue-slick sliding arrows are not visible in vuejs component

I am working with vue-slick(v-1.1.15) in vuejs to show some sliding images. Although the images are auto-slidable but I also need arrows to make them slide manually.
The problem is instead of those arrows, two buttons "Next" and "Previous" are being shown.
I have also imported the .css file for vue-slick to get it work, but useful results were found.
Below is my code:
<template>
<div>
<div class="idb-full-block">
<slick ref="slick" :options="slickOptions" v-if="someVar !== null">
<div class="content-wrap" v-for="var in someVar" :key="var.img">
<div class="idb-block-content p-20">
<div class="pp-image mb-20 d-flex justify-content-center align-items-center">
<img :src="var.img" class="img-fluid" alt="pp" width="" height="" />
</div>
<div class="d-flex justify-content-between mb-10">
<h5 class="mb-0">{{var.title}}</h5>
<h5 class="text-danger mb-0 fw-bold">{{var.price}}</h5>
</div>
<div class="pp-ratings">
<i v-for="(stars, index) in 5" :key="index" class="fa fa-star text-warning"></i>
</div>
</div>
<ul class="pp-stats footer-border">
<li class="w-33">
<h4 class="fw-bold">{{var.sales}}</h4>
</li>
<li class="w-33">
<h4 class="fw-bold">{{var.rating}}</h4>
</li>
<li class="w-33">
<h4 class="fw-bold">{{var.comments}}</h4>
</li>
</ul>
</div>
</slick>
</div>
</div>
<script>
import Slick from "vue-slick";
import { someVar } from "./someVar.js";
import `node_modules/slick-carousel/slick/slick.css`;
export default {
components: {
Slick
},
data() {
return {
someVar,
slickOptions: {
slidesToShow: 1,
arrows: true,
infinite: true,
speed: 500,
slidesToShow: 1,
slidesToScroll: 1,
autoplay: true,
},
}
},
};
</script>
Any kind of help would be appreciated.
I Found the answer in other Question
You need to
Making sure you passing arrows props as true
the default color and background is white so you need to change
it first if your website is white.
Using slot {nextArrow, prevArrow }
.slick-prev:before,
.slick-next:before {
color: red !important;
}
<template #prevArrow="arrowOption">
<div class="custom-arrow">
{{ arrowOption.currentSlide }}/{{ arrowOption.slideCount }}
</div>
</template>
<template #nextArrow="arrowOption">
<div class="custom-arrow">
{{ arrowOption.currentSlide }}/{{ arrowOption.slideCount }}
</div>
</template>

VueJS aligning recursive component

I've built a recursive component that is doing what I want. However, I'm struggling to figure out how to programmatically keep the elements in align:
Here is the component in it's entirety:
<template>
<div class="row-creator" ref="row">
<div v-for="(item, index) in row" :key="index" :style="[indent, newWidth]">
<div v-if="typeof(item) === 'string'">
<v-multi-select
:value="properties.filter((prop) => { return prop.target === item; })"
class="mb-3"
track-by="target"
label="target"
placeholder="Choose an attribute"
:options="properties"
:searchable="false"
:allow-empty="false"
:show-labels="false">
<template slot="singleLabel" slot-scope="{ option }"></template>
</v-multi-select>
<i class="fa fa-minus-circle"></i>
<i class="pl-2 fa fa-plus-circle" id="addBtn"></i>
<b-popover target="addBtn" placement="bottomleft" triggers="click">
<b-list-group class="list-group">
<b-list-group-item button><i class="fa fa-plus fa-2x pr-2"></i> Add a field</b-list-group-item>
<b-list-group-item button><i class="fa fa-plus fa-2x pr-2"></i> Add a group</b-list-group-item>
</b-list-group>
</b-popover>
</div>
<div v-else>
<v-multi-select
:value="options[0].key === Object.keys(item)[0] ? options[0] : options[1]"
class="mb-3"
track-by="key"
label="text"
:options="options"
:searchable="false"
:allow-empty="false"
:show-labels="false">
</v-multi-select>
<i class="fa fa-minus-circle"></i>
<i class="pl-2 fa fa-plus-circle" id="addBtn"></i>
<b-popover target="addBtn" placement="bottomleft" triggers="click">
<b-list-group class="list-group">
<b-list-group-item button><i class="fa fa-plus fa-2x pr-2"></i> Add a field</b-list-group-item>
<b-list-group-item button><i class="fa fa-plus fa-2x pr-2"></i> Add a group</b-list-group-item>
</b-list-group>
</b-popover>
<row-creator
:row="item[Object.keys(item)[0]]"
:properties="properties"
:options="options"
:depth="depth + 1">
</row-creator>
</div>
</div>
</div>
</template>
<script>
import vMultiselect from 'vue-multiselect';
export default {
props: [ 'row', 'properties', 'options', 'depth' ],
name: 'row-creator',
components: {
'v-multi-select': vMultiselect
},
computed: {
indent () {
return { transform: `translate(${this.depth * 20}px)` };
},
newWidth () {
// return { width: this.$refs.row.clientWidth - this.depth * 20 + 'px' };
}
}
};
</script>
How can create a computed property to adjust the width of the various rows? This form represents an object. What is the best way to keep the data object in sync? Can I use v-model?
Don't use css transform for this. Use margin-left instead!

Vue 2.x authentication links not hiding until page refresh

I am new to Vue and created a basic authentication application.
AuthService.js
module.exports = {
isLoggedIn: function() {
if (localStorage.getItem("authUser") != null) {
return true;
} else {
return false;
}
},
Logout: function() {
localStorage.removeItem("authUser");
},
}
App.vue
<template>
<div id="app" >
<top-progress ref="topProgress"></top-progress>
<div class="nav is-light is-fixed-top">
<div class="container">
<span class="nav-toggle" v-on:click="toggleNav" v-bind:class="{ 'is-active': isActive }">
<span></span>
<span></span>
<span></span>
</span>
<div class="nav-right nav-menu" v-bind:class="{ 'is-active': isActive }">
<router-link v-ripple to="/" class="nav-item r-item"><i class="fa fa-home"></i>Home</router-link>
<router-link v-ripple to="faq" class="nav-item r-item"><i class="fa fa-file"></i>Features</router-link>
<router-link v-ripple to="dashboard" class="nav-item r-item"><i class="fa fa-dashcube"></i>Dashboard</router-link>
<router-link v-ripple to="faq" class="nav-item r-item"><i class="fa fa-quora"></i>Faq</router-link>
<a class="nav-item r-item" v-if="LoggedIn"><i class="fa fa-sign-out" #click.prevent="Logout"></i>Logout</a>
<div class="nav-item" v-if="!LoggedIn">
<p class="control">
<router-link to="login" class="button is-primary is-outlined">
<span class="icon">
<i class="fa fa-download"></i>
</span>
<span> Join Now</span>
</router-link>
</p>
</div>
</div>
</div>
</div>
<br>
<router-view></router-view>
<footer class="footer is-secondary">
<div class="container">
<div class="columns">
<div class="column">
<p>And this right here is a spiffy footer, where you can put stuff.</p>
</div>
<div class="column has-text-right">
<a class="icon" href="#"><i class="fa fa-facebook"></i></a>
<a class="icon" href="#"><i class="fa fa-twitter"></i></a>
</div>
</div>
</div>
</footer>
</div>
</template>
<script>
import {isLoggedIn,Logout} from "./service"
import miniToastr from 'mini-toastr'
import topProgress from 'vue-top-progress'
export default {
name: 'app',
components:{topProgress},
data:function(){
return {
isActive:false,
LoggedIn:false,
}
},
created(){
this.LoggedIn=isLoggedIn();
},
mounted(){
miniToastr.init()
this.$refs.topProgress.start()
setTimeout(() => {
this.$refs.topProgress.done()
}, 2000)
},
methods:{
Logout:function(){
Logout();
this.$router.push("login");
},
}
}
</script>
<style lang="sass">
..//
</style>
After successful login, I am using this.$router.push("home") to navigate to home component but the Login/Logout button not hiding/showing until I refresh the page.
The problem you are having is the created: hook is only called when App.vue is first created. Since this component holders the router-view it is always there as you move around the app — it's never destroyed, so it never needs to be created again. As a result your this.LoggedIn is only updated when you first load the app (or as you discovered, hit refresh).
You need to find a different way to update this.LoggedIn. One obvious possibility it to set it in the logih/logout methods.
Logout:function(){
Logout();
this.LoggedIn = isLoggedIn(); // or simply this.LoggedIn = false
this.$router.push("login");
},
It looks like users will login in a different component, so you will need to send an event from the child component to App.vue and trigger a method on App.vue to set this.LoggedIn when users login.
There are probably other possibilities that will come to mind now that you see why it isn't working.

Programmatically append existing component to existing v-model in VueJS

Like the title says, Im trying to append a vue-component to an existing v-model
The only thing i found on the internet was the v-for solution to add more elements, but that is not what I want to do since this v-model could have multiple components
chat.vue
The V-model im trying to append to
<template>
<ul class="chat-ul" v-model="messages">
<chat-entry :name="name" :message="text" direction="left"></chat-entry>
</ul>
</template>
Here is where im stuck, how i can add the components
<script>
Vue.component('chat-entry', require('./entry.vue'));
module.exports = {
data: function () {
return {
name: 'Default name',
message: 'Default message',
messages: null,
}
},
mounted: function () {
// This is the what i want to achive
this.messages.append('chat-entry', {direction: 'left', message: 'hello', name: 'HeatON'});
this.$http.get('/etc/yelp.xi').then(response => {
for (let q in response.body.arr) {
this.messages.append('chat-entry', {direction: 'left', message: q.message, name: q.name});
}
});
}
}
entry.vue
<template>
<div v-if="direction == 'left'">
<li>
<div class="message-data">
<span class="message-data-name"><i class="fa fa-circle you"></i> {{ name }}</span>
</div>
<div class="message you-message"> {{ message }} </div>
</li>
</div>
<div v-else>
<li class="clearfix">
<div class="message-data align-right">
<span class="message-data-name">{{ name }}</span> <i class="fa fa-circle me"></i>
</div>
<div class="message me-message float-right"> {{ message }} </div>
</li>
</div>
</li>
Is something like this even possible? if not, what is the proper approach?
Thanks in advance