What notation/style/something else does a Vue.js documentation use? It looks like this:
It has var vm = new Vue({ before it
While my Vue looks differently something like this:
<template>
<router-link class="element" :to="{name: 'Home', params: {id: id}}">
<div class="icon"></div>
<div class="operation-type">
<span class="access-type">{{accesstype}}</span>
<span>{{name}}</span>
</div>
</router-link>
</template>
<script>
export default {
name: 'WriteElement',
props: {
write: Object,
},
}
</script>
<style>
.element {
display: block;
text-decoration: none;
}
</style>
I installed Vue through Vue CLI (and it comes with bunch of instruments that I have no idea what they do)
Related
I've seen a few 'solutions' online about this but to no avail for us. We're working with the quasar framework and trying to setup a horizontally wrapped set of that are are draggable (for re-ordering). Below is the basic stub of the code we're working with to get this going. However, we're not able to get the cards to layout horizontally everything is stacked in a list. What are we doing wrong?
<template>
<draggable
v-model="items"
group="items"
direction="horizontal"
item-key="id"
#start="drag = true"
#end="drag = false"
>
<template #item="{ element }">
<q-card class="card">
<q-img src="~assets/temp/bb-auto.png" :alt="`Image ${element.name}`">
<div class="absolute-bottom text-subtitle2 text-center">
Image {{ element.name }}
</div>
</q-img>
</q-card>
</template>
</draggable>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import draggable from 'vuedraggable';
const drag = ref(false);
const items = ref([
{ name: 'item1' },
{ name: 'item2' },
{ name: 'item3' },
{ name: 'item4' },
{ name: 'item5' },
]);
</script>
<style scoped>
.card {
max-height: 200px;
max-width: 200px;
display: flex;
}
</style>
Turns out our overall structure was incorrect and once we sorted that out was able to back this into the draggable. We then had to basically treat our as the row.
<template>
<draggable
v-model="items"
group="items"
class="q-pa-md row items-start q-gutter-md"
direction="horizontal"
item-key="name"
#start="drag = true"
#end="drag = false"
>
<template #item="{ element }">
<q-card class="card">
<q-img src="~assets/temp/bb-auto.png" :alt="`Image ${element.name}`">
<div class="absolute-bottom text-subtitle2 text-center">
Image {{ element.name }}
</div>
</q-img>
</q-card>
</template>
</draggable>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import draggable from 'vuedraggable';
const drag = ref(false);
const items = ref([
{ name: 'item1' },
{ name: 'item2' },
{ name: 'item3' },
{ name: 'item4' },
{ name: 'item5' },
]);
</script>
<style scoped>
.card {
width: 100%;
max-height: 200px;
max-width: 200px;
display: flex;
}
</style>
I have the following Vue component called TeamCard:
<template>
<div class="m-8 max-w-sm rounded overflow-hidden shadow-lg">
<!-- removed fro brevety -->
div class="text-gray-900 font-bold text-xl mb-2">{{ name }}</div>
<p class="text-gray-700 text-base"> {{ description }} </p>
<!-- removed fro brevety -->
</div>
</div>
</template>
<script>
export default {
name: "TeamCard",
props: {
name: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
}
};
</script>
<style scoped>
#import "https://unpkg.com/tailwindcss#^2/dist/tailwind.min.css";
</style>
I call the component in an HTML page (Spring boot template) the following way:
<teamCard v-bind:name="'Hawks'" v-bind:description="'Best team'" ></teamCard>
<script src="https://unpkg.com/vue"></script>
<script th:src="#{/TeamCard/TeamCard.umd.min.js}"></script>
<script>
(function() {
new Vue({
components: {
teamCard: TeamCard
}
})
})();
</script>
When I go to the page in the browser that has the second snippet, nothing is shown. There are no errors in the console. What am I doing wrong? How can I make the component be shown?
I've never seen Vue used this way but it looks like there is no mounting element for the app. Try this:
<div id="app">
<team-card v-bind:name="'Hawks'" v-bind:description="'Best team'"></team-card>
</div>
and
(function() {
new Vue({
el: '#app',
components: {
teamCard: TeamCard
}
})
})();
I'm on the path of learning Vue and i have a question that you might find trivial but i struggle to find an answer. First of all, i'm using Vue with Vue Router, in order to build a test blog.
Let's say the h1 of my page is inside the header component, itself included inside the layout.
But then, how can i set the content of this h1 tag for each page, since it belongs to the header, which is only included in the layout? One solution i found was to set meta.h1 on each route declaration, something like that:
{
path: 'articles',
meta: {
h1: 'All the articles'
}
}
Then, inside the header, i can use a method to get the value of this.$route.meta.h1. Something like that:
methods: {
h1() {
return this.$route.meta.h1
}
}
It works, but it seems kind of wrong, since i don't think that's the job of the route file to handle this. To make it simple, what is the best way, the preferred way, to handle this situation? ty :)
[EDIT]
Here is a simple example page from the bootstrap documentation that could well illustrate my question: https://getbootstrap.com/docs/4.0/examples/blog/
Title of a longer featured blog post
is the h1 and would probably be dynamic, changing from page to page. But it's part of the header component, not part of the articles, of the forum, of the comments or any other component... so if i can reformulate my question, that would be "how can i set this h1 title elegantly" ? Don't think of something complicated, this is a very basic question from a beginner looking toward some answers :p
You can pass props via routes like this, but I'm not sure how you would supply that variable.
I'm not sure of the structure of your app, and if the header component is the header for the entire app, or if it's just a header for each article.. If it's a header just for the article, there is no need to emit events.. (see example below).
[CodePen mirror]
const appHeader = {
template: "#app-header",
computed: {
dynamicHeader() {
let r = this.$route.name;
// caps first letter
let f = r.charAt(0).toUpperCase() + r.slice(1);
switch(f){
case "Home": return f + " Page!";
case "Contacts": return "Contact Us!";
case "About": return f + " Us!!"
}
}
}
};
const contactsPage = {
template: "#contacts-page"
};
const aboutPage = {
template: "#about-page"
};
const homePage = {
template: "#home-page"
};
const routes = [
{
path: "/",
name: "home",
components: {
header: appHeader,
content: homePage
}
},
{
path: "/contact",
name: "contacts",
components: {
header: appHeader,
content: contactsPage
}
},
{
path: "/about",
name: "about",
components: {
header: appHeader,
content: aboutPage
}
}
];
const router = new VueRouter({ routes });
new Vue({
router
}).$mount("#app");
nav.mainNav > * {
padding: 0 0.75rem;
text-decoration: none;
}
nav.mainNav > *:nth-last-child(n+2) {
border-right: 1px solid #aaa;
}
#headerContainer {
background-color: yellow;
margin-bottom: -20px;
}
#page {
border: 1px solid black;
margin: 20px 20px 20px 20px;
}
#page > * {
margin: 10px 10px 10px 10px;
text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/3.0.4/vue-router.min.js"></script>
<div id="app">
<div>
<router-view name="header"></router-view>
<router-view id="page" name="content"></router-view>
</div>
</div>
<!-- -------------------- -->
<!-- APP HEADER COMPONENT -->
<!-- -------------------- -->
<script type="text/x-template" id="app-header">
<div>
<div id="headerContainer">
<h1>{{ dynamicHeader }}</h1>
</div>
<nav class="mainNav">
<router-link
:to="{ name: 'home' }"
>Home</router-link>
<router-link
:to="{ name: 'about' }"
>About</router-link>
<router-link
:to="{ name: 'contacts' }"
>Contacts</router-link>
</nav>
</div>
</script>
<!-- -------------------- -->
<!-- ----------------------- -->
<!-- CONTACTS PAGE COMPONENT -->
<!-- ----------------------- -->
<script type="text/x-template" id="contacts-page">
<div style="background-color:blue;">
<h2>this is the contacts page</h2>
</div>
</script>
<!-- ----------------------- -->
<!-- -------------------- -->
<!-- ABOUT PAGE COMPONENT -->
<!-- -------------------- -->
<script type="text/x-template" id="about-page">
<div style="background-color:green;">
<h2>this is the about page</h2>
</div>
</script>
<!-- -------------------- -->
<!-- ------------------- -->
<!-- HOME PAGE COMPONENT -->
<!-- ------------------- -->
<script type="text/x-template" id="home-page">
<div style="background-color:red;">
<h2>this is the home page</h2>
</div>
</script>
I found a solution that seems to better fit what i requested, which is using an event bus as described in this video:
https://www.youtube.com/watch?v=jzh4zQcfB0o
To sum up what the guy says, the idea is to use another instance of Vue as an event bus in order to emit and listen to events between components not related to each other. This way, i can set the h1 title of my page from any components.
In the following code, I'm trying to get selected users from a list of given users (users array) via checkbox input (defined in a child component) in an array selectedUsers (defined in parent).
The problem is when I check/select the user, devtools doesn't update on first reaction. I've to navigate away from the selected component in devtools and then comeback to see the updated array.
app.vue (parent)
<template>
<div class="container">
<div class="row">
<div v-for="(user,idx) in users" class="col-xs-12 col-md-6 col-md-offset-3">
<child :user="user" :userIdx="idx" :selectedUsers="selectedUsers" /> <span>{{user.name }}</span>
</div>
</div>
</div>
</template>
<script>
import child from './child.vue'
export default {
data: function() {
return{
users: [
{id: 1, name: 'Allen'},
{id: 2, name: 'Jack'},
{id: 3, name: 'Obama'},
{id: 4, name: 'Donald'},
{id: 5, name: 'Winston'},
selectedUsers: []
}
},
components: {
child
}
}
</script>
child.vue (child)
<template>
<span>
<input type="checkbox" :value="user.name" #change="onSelectedUser">
</span>
</template>
<script>
export default {
props: ['user', 'userIdx', 'selectedUsers'],
data(){
},
methods: {
onSelectedUser() {
var idx = this.userIdx
if(event.target.checked) {
this.selectedUsers[idx] = event.target.value
}
if(event.target.checked == false) {
this.selectedUsers.splice(idx, 1)
}
}
}
}
</script>
<style scoped>
input[type="checkbox"] {
width: 20px;
height: 20px;
margin-right: 10px;
border: 3px solid red;
}
input[type="checkbox"]:checked {
width: 30px;
height: 30px;
}
</style>
Thanks
In this line of code, this.selectedUsers[idx] = event.target.value, I'm directly setting the value of an Array which vue is not able to pickup these direct modification to the array.
Excerpt from the below linked page
When you modify an Array by directly setting an index (e.g. arr[0] = val) or modifying its length property. Similarly, Vue.js cannot pickup these changes.
More info VueJS common gotchas - why DOM isn't updating
In template scope, are there variable referencing the element itself like a $this or $el?
Instead of,
<template>
<div #click="$emit('xxx')" :class="{active:mode=='xxx'}" something_for_xxx></div>
<div #click="$emit('yyy')" :class="{active:mode=='yyy'}" something_for_yyy></div>
<div #click="$emit('zzz')" :class="{active:mode=='zzz'}" something_for_zzz></div>
</template>
Can we write something like the following, to avoid forgetting to change one of the mode name?
<template>
<div mode="xxx" #click="$emit($this.mode)" :class="{active:mode==$this.mode}" something_for_xxx></div>
<div mode="yyy" #click="$emit($this.mode)" :class="{active:mode==$this.mode}" something_for_yyy></div>
<div mode="zzz" #click="$emit($this.mode)" :class="{active:mode==$this.mode}" something_for_zzz></div>
</template>
Workaround:
<template>
<div v-for"mode_ in ["xxx"] #click="$emit(mode_)" :class="{active:mode==mode_}" something_for_xxx></div>
<div v-for"mode_ in ["yyy"] #click="$emit(mode_)" :class="{active:mode==mode_}" something_for_yyy></div>
<div v-for"mode_ in ["zzz"] #click="$emit(mode_)" :class="{active:mode==mode_}" something_for_zzz></div>
</template>
In the event handlers, you can always access $event.target to access the element (see https://v2.vuejs.org/v2/guide/events.html#Method-Event-Handlers) but for inline binding (like :class) you cannot because the element has not been rendered yet.
I suggest you change how you cycle through each value
<div v-for="elMode in ['xxx', 'yyy', 'zzz']"
#click="$emit('click', elMode)" :class="{active:mode==elMode}"/>
That is the typical situation where you should build your elements in a v-for loop:
Vue.component('my-component', {
template: '#my-component',
props: {
mode: String,
},
data() {
return {
modes: ['xxx', 'yyy', 'zzz'],
};
},
});
new Vue({
el: '#app',
data: {
mode: 'xxx',
},
methods: {
log(event) {
this.mode = event;
console.log(event);
}
},
});
.active {
color: green;
}
.pointer {
cursor: pointer;
}
<script src="https://unpkg.com/vue#2"></script>
<div id="app">
<my-component
:mode='mode'
#click="log($event)"
></my-component>
</div>
<template id="my-component">
<div>
<div
v-for="currentMode of modes"
#click="$emit('click', currentMode)"
:class="{active:mode==currentMode}"
class="pointer"
>{{currentMode}}</div>
</div>
</template>