Why won't my click event in Vue.js fire? - vue.js

I'm trying to use Vue's on-click directive on a div but it does not fire as intended. When I click the .demo class nothing happens; I should get a 'test clicked' in the console. I don't see any errors in the console, so I don't know what am I doing wrong.
var app = new Vue({
el: '#app',
data: {
title: 'This is the first vue app',
name: 'ALRAZY',
link: 'http://google.com',
attachRed: false
},
methods: {
changeLink: function() {
this.link = 'http://apple.com'
}
}
})
body {
font-family: 'Trykker', 'Spectral SC', serif;
}
h1,h2,h3,h4,h5,h6 {
font-family: 'Spectral SC', serif;
}
p {
font-family: 'Trykker', serif;
}
.demo {
width: 100px;
height: 100px;
background-color: grey;
display: inline-block;
margin: 10px;
}
.red {
background: red;
}
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" rel="stylesheet"/>
<link href="https://fonts.googleapis.com/css?family=Spectral+SC:400,400i,500,500i,600|Trykker" rel="stylesheet" >
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div class="container">
<div class="row">
<div id="app">
<h1>{{ title }} </h1>
<input type="text" v-model="name" name="">
<p> {{ name }}</p>
<button onclick="changeLink" class="btn btn-danger btn-lg">click to change</button>
<a :href="link" target="_blank">Link</a>
<!-- style-vue -->
<div class="demo" onclick="attachRed = !attachRed" :class="{red: attachRed}"></div>
<p v-if="show">You can see me!!!</p>
<p v-else>Do You see me??</p>
</div>
</div>
</div>

You're using the standard onclick attribute which is not going to trigger vue methods. Try using v-on:click="changeLink()" or #click="changeLink()" (I'm not entirely sure if the second is the correct syntax). That should resolve your problem.
Similarly, you can do #click="attachRed = !attachRed".

Related

How to pass props dynamically in vue

I am trying to pass props to a router-link which is used to take me to the update or delete page. In order for me to update the right element, I need to pass the item's id as a prop to the component(dropdown menu) to dynamically render the update and delete pages.
Here is my dropdown component:
<template>
<div class="dropdown">
<button #click="toggleMenu">
<fa class="dropdown_icon" icon="fa-solid fa-arrow-down" />
</button>
<div v-if="showMenu" class="menu">
<div class="menu-item" #click="itemClicked">
<router-link :to="`/updateList/${id}`" class="list__link"
>Update</router-link
>
<br />
<router-link :to="`/deleteList/${id}`" class="list__link"
>Delete</router-link
>
</div>
</div>
</div>
</template>
<script>
export default {
name: 'DropdownList',
props: ['id'],
data() {
return {
showMenu: false,
};
},
methods: {
toggleMenu() {
this.showMenu = !this.showMenu;
},
itemClicked() {
this.toggleMenu();
},
},
};
</script>
<style scoped>
.dropdown_icon {
padding: 0.2rem;
color: #ffd700;
background: black;
margin-top: 15px;
transition: var(--transition);
border-radius: 0.2rem;
height: 17px;
}
.dropdown_icon:hover {
background: white;
color: black;
height: 17px;
}
.menu {
background: white;
padding-left: 2rem;
padding-right: 2rem;
border-radius: 1rem;
}
.list_plus {
padding: 0.5rem;
border: 1px solid gray;
border-radius: 1rem;
transition: var(--transition);
}
.list_plus:hover {
background: black;
color: #ffd700;
}
.createList {
text-decoration: none;
}
.list__link {
text-decoration: none;
color: black;
}
</style>
Here is my code for the part in which I am sending the element's id as a prop to the component:
div class="all__lists" v-for="(item, index) in items" :key="index">
<div class="list">
<div class="title">
<div class="title__options">
<h1 class="list_name">{{ item[0].list_name }}</h1>
<Dropdown :v-bind:id="`${item[0].list_id}`" />
<!-- V-menu -->
<!--menu ends-->
</div>
</div>
</div>
</div>
The Items object looks like:
But when I Try to access the update or delete page, the router redirects me to /updateList/undefined instead of /updateList/1 or something. Can anybody help me in fixing this?
Your problem is that you mixed the v-bind directive with its shorthand :.
You wrote :v-bind:id instead of v-bind:id (or :id).
With your code, you should be able to get the id by defining the props v-bind:id in the child. It will work since :v-bind:id will be converted as v-bind:v-bind:id.

Vue multiple scoped style tags

I have a component that I want to re-use but with a completely different style for each usage.
The idea is to keep the template and script but have a different look based on some condition, hence avoid duplicating the component.
e.g.
<template>
<div class="some-class">
...
</div>
</template>
<script>
...
</script>
<style scoped>
.some-class {
color: red;
}
</style>
<style scoped>
.some-class {
color: blue;
}
</style>
Is this possible?
Instead of creating two different scoped style. you can use :class to dynamically bind the styles based on the condition.
Demo :
new Vue({
el: '#app',
data:{
lookA: false,
lookB: false
}
});
.lookA{
background: yellow;
color: black;
}
.lookB {
background: green;
color: #eee;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<label for="a">Change color for look A : </label><input type="checkbox" v-model="lookA" id="a"><br>
<label for="b">Change colors for look B : </label><input type="checkbox" v-model="lookB" id="b">
<br><br>
<div v-bind:class="{'lookA': lookA, 'lookB': lookB}">
Welcome!
</div>
</div>

Transform Based Animation using Vue Transition Wrapper

I'm trying to port some animation implemented mostly through css and little javascript to a Vue component. The animation is simple - user clicks a button and a little panel opens from the bottom of his browser and slides upwards.
I have a working Vue component implemented using the same css and no javascript.
Now, I'm aware of the transition wrapper that Vue provides. But I'm unable to figure out how to get similar functionality using the transition wrapper (if at all).
Can someone help me out here?
// register modal component
Vue.component('modal', {
template: '#modal-template',
props: ['show']
})
// start app
new Vue({
el: '#app',
data: {
showModal: false
}
})
.drawer-wrapper {
position: fixed;
top: 100%;
left: 0;
right: 0;
height: 50%;
z-index: 9998;
transition: transform .3s ease-out;
}
.drawer-wrapper.open {
transform: translateY(-100%);
}
.drawer-container {
height: 100%;
width: 100%;
background-color: white;
}
.drawer-header h3 {
margin-top: 0;
color: #42b983;
}
.drawer-body {
margin: 20px 0;
}
.drawer-default-button {
float: right;
}
<script src="https://unpkg.com/vue#latest/dist/vue.js"></script>
<!-- template for the modal component -->
<script type="text/x-template" id="modal-template">
<div class="drawer-wrapper" :class="{ open: show }">
<div class="drawer-container">
<div class="drawer-header">
<slot name="header">
default header
</slot>
</div>
<div class="drawer-body">
<slot name="body">
default body
</slot>
</div>
<div class="drawer-footer">
<slot name="footer">
default footer
<button class="drawer-default-button" #click="$emit('close')">
OK
</button>
</slot>
</div>
</div>
</div>
</script>
<!-- app -->
<div id="app">
<button id="show-modal" #click="showModal = true">Show Modal</button>
<!-- use the modal component, pass in the prop -->
<modal #close="showModal = false" :show="showModal">
<!--
you can use custom content here to overwrite
default content
-->
<h3 slot="header">custom header</h3>
</modal>
</div>
I got this to work using a transition wrapper, but the code isn't as elegant as I'd expected. Particularly the use of the following attributes in the drawer-wrapper class:
top: 100%;
transform: translateY(-100%);
Fiddle is here
If anyone can simplify the code further, I'd really appreciate it.

polymer 2 dom-repeat does not reflect when item is removed

I have a very simple application in Polymer 2. I have a static list of items which is displayed with dom-repeat.
I have a button for delete, on click i could see the item is removed from the list. But the dom-repeat is not refreshed. Its still the old code.
Can someone help how to reflect the changes on the screen:
code snippet is below:
<link rel="import" href="../../bower_components/polymer/polymer-element.html">
<link rel="import" href="../../bower_components/iron-list/iron-list.html">
<link rel="import" href="../../bower_components/iron-icons/iron-icons.html">
<link rel="import" href="../../bower_components/app-storage/app-localstorage/app-localstorage-document.html">
<link rel="import" href="../../bower_components/polymer/lib/elements/dom-repeat.html">
<dom-module id="todo-list">
<template>
<style>
:host {
display: block;
}
.ibtn {
float: right;
}
.item {
width: 500px;
}
paper-icon-button {
color: grey;
}
.list-todo {
height: 700px;
text-align: left;
-webkit-text-fill-color: brown;
}
.list-todo ul li {
width: 500px;
font-family: sans-serif;
font-size: 20px;
}
.list-todo .btn-set {
float: right;
}
</style>
<!-- <app-localstorage-document key="app-store" data="{{todos}}"></app-localstorage-document> -->
<div class="list-todo">
<template is="dom-repeat" items="{{todos}}">
<ul>
<li>
<iron-icon icon="icons:arrow-forward"></iron-icon>
{{item}}
<span class="btn-set">
<paper-icon-button icon="create"></paper-icon-button>
<paper-icon-button icon="delete" on-tap="deleteTodo"></paper-icon-button>
<paper-icon-button icon="star"></paper-icon-button>
<span>
</li>
</ul>
</template>
</div>
</template>
<script>
/**
* #customElement
* #polymer
*/
class TodoList extends Polymer.Element {
static get is() { return 'todo-list'; }
static get properties() {
return {
todos: {
type: Object,
value: ["Build the code", "Check Sonar Issues", "Release the APP", "Deploy in Production", "Get Feedback"],
notify: true
}
};
}
populateTodoList() {
return this.todos;
}
deleteTodo(item) {
this.todos.splice(item.model.index, 1);
this.todos.flush;
}
}
window.customElements.define(TodoList.is, TodoList);
</script>
</dom-module>
Javascript splice removes the item from the array, but it does not mean the change is reflected in polymer shadowRoot.
To do this you have to use polymer array mutation methods. See this.
In your case will be:
this.splice('todos', item.model.index, 1);
Also, this.todos.flush; is not needed.
Another thing I detected (not related with this), are you sure you want to have <ul> inside the repeat? This created a bunch of list with just one item inside each list.
I suggest you to do this
<div class="list-todo">
<ul>
<template is="dom-repeat" items="{{todos}}">
<li>
<iron-icon icon="icons:arrow-forward"></iron-icon>
{{item}}
<span class="btn-set">
<paper-icon-button icon="create">create</paper-icon-button>
<paper-icon-button icon="crystal-icons:lens" on-tap="deleteTodo">delete</paper-icon-button>
<paper-icon-button icon="star">star</paper-icon-button>
<span>
</li>
</template>
</ul>
</div>
This way you just create one list.

Create sliding left effect using Vuejs animation

I've read this official document about Vuejs animation. But using it css hooks, I can only make element appear/disappear with fade and different duration.
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="fade">
<p v-if="show">hello</p>
</transition>
</div>
.fade-enter-active, .fade-leave-active {
transition: opacity .5s
}
.fade-enter, .fade-leave-to /* .fade-leave-active in <2.1.8 */ {
opacity: 0
}
How to use Vuejs Animation to create a sliding effect? Like the one here. Is it possible? Please provide some sample code.
You can absolutely do this with VueJS.
Have a look at the example under. You can see two examples, one is the adopted code for your case(to make it slide). And other is a simple image slider, that loops through array of images in 3 seconds interval.
Important thing to note here, is that we wrap the image element in for loop to force the element to be destroyed, because otherwise your elements will not be removed from DOM and will not transition (virtual DOM).
For better understanding of transitions in VueJS in recommend you to check out getting started guide - transition section.
new Vue({
el: '#demo',
data: {
message: 'Click for slide',
show: true,
imgList: [
'http://via.placeholder.com/350x150',
'http://via.placeholder.com/350x151',
'http://via.placeholder.com/350x152'
],
currentImg: 0
},
mounted() {
setInterval(() => {
this.currentImg = this.currentImg + 1;
}, 3000);
}
})
#demo {
overflow: hidden;
}
.slide-leave-active,
.slide-enter-active {
transition: 1s;
}
.slide-enter {
transform: translate(100%, 0);
}
.slide-leave-to {
transform: translate(-100%, 0);
}
.img-slider{
overflow: hidden;
position: relative;
height: 200px;
width: 400px;
}
.img-slider img {
position: absolute;
top: 0;
left: 0;
bottom: 0;
right:0;
}
<!DOCTYPE html>
<html>
<head>
<title>VueJS 2.0 - image slider</title>
<link rel="stylesheet" href="style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
</head>
<body>
<div id="demo">
<button v-on:click="show = !show">
Toggle
</button>
<transition name="slide">
<p v-if="show">{{message}}</p>
</transition>
<h3>
Img slider
</h3>
<transition-group tag="div" class="img-slider" name="slide">
<div v-for="number in [currentImg]" v-bind:key="number" >
<img :src="imgList[Math.abs(currentImg) % imgList.length]"/>
</div>
</transition-group>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script src="script.js"></script>
</body>
</html>
Thanks for the answer above it helped me a lot!
Since the original example had buttons to slide in both directions,
I improved it somewhat by adding "Next" and "Previous" buttons. I swap the animation to have it go the oposite way when pressing "Previous":
new Vue({
el: '#demo',
data: {
back: false,
currentIndex: 0
},
methods: {
next(){
this.back = false;
this.currentIndex++;
},
prev(){
this.back = true;
this.currentIndex--;
}
},
})
#demo {
overflow: hidden;
}
.slide-leave-active,
.slide-enter-active {
transition: 1s;
}
.slide-enter {
transform: translate(100%, 0);
}
.slide-leave-to {
transform: translate(-100%, 0);
}
.slideback-leave-active,
.slideback-enter-active {
transition: 1s;
}
.slideback-enter {
transform: translate(-100%, 0);
}
.slideback-leave-to {
transform: translate(100%, 0);
}
.div-slider{
overflow: hidden;
position: relative;
height: 100px;
width: 90%;
}
.div-slider .card {
position: absolute;
height: 100px;
width: 90%;
background-color: #60adff;
}
<!DOCTYPE html>
<html>
<head>
<title>VueJS 2.0 - image slider</title>
<link rel="stylesheet" href="style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
</head>
<body>
<div id="demo">
<h3>
div slider
</h3>
<transition-group tag="div" class="div-slider" :name="back? 'slideback' : 'slide'">
<div v-if="currentIndex === 0" key="1">
<div class="card">
DIV 1
</div>
</div>
<div v-if="currentIndex === 1" key="2" >
<div class="card">
DIV 2
</div>
</div>
<div v-if="currentIndex === 2" key="3" >
<div class="card">
DIV 1
</div>
</div>
</transition-group>
<button #click="prev()" >prev</button>
<button #click="next()">next</button>
</div>
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
</body>
</html>