VueJs Enter-transition animation not working on click - css

The code is supposed to take a user's entry in the input box, push it to the end of the "tasks" array when "ADD TASK" is clicked which is then displayed using v-for. However, the list-enter-active animation doesn't work. It just snaps into the browser's display instead of easing in. "REMOVE TASK" works like it should though.
<template>
<div class="grid-container">
<div class="content">
<h1>To-Do It</h1>
<transition-group name="list" tag="p">
<div
v-for="(item, index) in tasks"
v-bind:item="item"
v-bind:index="index"
v-bind:key="item.id"
>
{{ item.count }}
</div>
</transition-group>
<input type="text" placeholder="Enter a task" v-model="userinput" />
<div>
<p v-bind:class="{ buttondiv: pshow }" v-on:click="addtask">
ADD TASK
</p>
<p v-bind:class="{ buttondiv: pshow }" v-on:click="removetask">
REMOVE TASK
</p>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Todo",
data: function() {
return {
userinput: "",
tasks: [],
show: true,
pshow: true
};
},
methods: {
addtask: function() {
if (this.userinput != "") {
this.tasks.push({ count: this.userinput });
this.userinput = "";
console.log(this.tasks);
} else {
return "failed";
}
},
removetask: function() {
this.tasks.pop(this.userinput);
}
}
};
</script>
<style>
#import "../assets/Todo.css";
.list-enter-active,
.list-leave-active {
transition: all 1s;
}
.list-enter,
.list-leave-to {
opacity: 0;
transform: translateY(30px);
}
.flip-list-move {
transition: transform 1s;
}
</style>

Related

css3 transtion not working with v-for in vue2

I use transtion in vue2. I added transition in css. Vue template show two box. One way use v-for and array, another way is use variable. btn2 is effective but btn1 not.
<style lang="sass">
.item
width: 120px
height: 120px
background-color: bisque
transition: margin-left 500ms
</style>
<template>
<div>
<div class="item" v-for="item in list" :key="item.index" :style="{marginLeft: item.index + 'px'}">{{ item.value }}</div>
<div class="item" :style="{marginLeft: left + 'px'}">123</div>
<button #click="addone">btn1</button>
<button #click="addtwo">btn2</button>
</div>
</template>
<script>
export default {
name: 'Heap',
data() {
return {
left: 100,
list: [
{
value: 12,
index: 10
}
]
}
},
methods: {
addone() {
this.list[0]['index']+=10
},
addtwo() {
this.left+=10
}
}
}
</script>
You are using the code :key="item.index" on your first div. Your code then updates that same index.
When a key's value changes, the component it is attached to re-renders. You are not seeing the animation occur because instead of dynamically incrementing the CSS, you are effectively just re-rendering the element with the new CSS.
The purpose of a key is to help Vue keep track of the identity of a given node in a list. It lets Vue know which nodes it can keep and patch up and which ones need to be rendered again.
You should use a static, non-changing value as a key where possible. In the following example I have added an id property to your object and used that as the key.
<style lang="sass">
.item
width: 120px
height: 120px
background-color: bisque
transition: margin-left 500ms
</style>
<template>
<div>
<div
v-for="item in list"
:key="item.id"
class="item"
:style="{marginLeft: item.index.toString() + 'px'}"
>
{{ item.value }}
</div>
<div class="item" :style="{marginLeft: left.toString() + 'px'}">123</div>
<button #click="addone">btn1</button>
<button #click="addtwo">btn2</button>
</div>
</template>
<script>
export default {
name: 'Example',
data() {
return {
left: 100,
list: [
{
id: '1',
value: 12,
index: 10,
},
],
};
},
methods: {
addone() {
this.list[0].index += 10;
},
addtwo() {
this.left += 10;
},
},
};
</script>

Angular: animation display card on top of another card

Im using angular animation builder for creating an animation. I have a grid list with a list of cards. When i click on a button ,i want another div to come on top of the initial card (float in from the left to cover the first card
) .As of now,the div comes in with the animation ,but is showing up on side of the initial card.I have made a stackblitz example to show the current progress.Here is my stackblitz:
https://stackblitz.com/edit/angular-ty4rfh
Also pasting the code here:
import { Component,OnInit,ElementRef } from '#angular/core';
import { trigger, state, style, transition, animate, AnimationBuilder, AnimationPlayer } from '#angular/animations';
export class Asset
{
constructor(public name:string,public description:string){};
}
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
assets:Asset[]=[];
cards=[];
private player: AnimationPlayer;
constructor(private animationBuilder:AnimationBuilder,
private elRef:ElementRef
){}
ngOnInit(){
this.setAssets();
this.setswitch();
}
setAssets(){
this.assets.push(new Asset("Asset1","Latest1"));
this.assets.push(new Asset("Asset2","Latest2"));
this.assets.push(new Asset("Asset3","Latest3"));
this.assets.push(new Asset("Asset4","Latest4"));
this.assets.push(new Asset("Asset5","Latest5"));
this.assets.push(new Asset("Asset6","Latest6"));
this.assets.push(new Asset("Asset7","Latest7"));
this.assets.push(new Asset("Asset8","Latest8"));
this.assets.push(new Asset("Asset9","Latest9"));
for(var i=0; i<this.assets.length;i++){
console.log(this.assets[i].name);
}
}
setswitch() {
for (let i = 0; i < this.assets.length; i++) {
let cardshow = {
id: i.toString(),
isShow : false
};
this.cards.push(cardshow);
}
console.log(this.cards);
}
animate(i){
this.cards[i].isShow=true;
let animationFactory;
animationFactory = this.animationBuilder
.build([
style({ width: '0' }),
animate(200, style({ width: 200 }))
]);
let elem:Element = document.getElementById("div"+(i));
console.log("Elament",elem);
console.log("INDEX",i);
this.player = animationFactory.create(elem);
this.player.play();
}
}
html:
<div>
<mat-grid-list cols="3" rowHeight="3:1">
<mat-grid-tile *ngFor="let asset of assets; index as i">
<div class="border">
<p>{{asset.name}} </p>
<p>{{asset.description}} </p>
<button (click)="animate(i)">click</button>
</div>
<div [ngClass]="!cards[i].isShow?'hide':''" id="{{'div'+i}}" class="border" >
<p>{{asset.description}} </p>
<button>click</button>
</div>
</mat-grid-tile>
</mat-grid-list>
</div>
css:
p {
font-family: Lato;
}
.border{
border:1px solid black;
padding-left: 20px;;
padding-right:20px;
}
.hide{
display:none;
}
EDIT: I need the other card to be completely hidden under the incoming card.Also after clicking on the button inside the incoming card, the animation should be undone(The card should retract back). Also what I'm doing now is increasing the width. What i expect is that the new card should come in from the left sort of like as we see in a drawer
check this stackblitz
app.component.css to be:
p {
font-family: Lato;
}
.border{
border:1px solid black;
padding-left: 20px;;
padding-right:20px;
background: #ffe6ea;
}
.hide{
display:none;
}
.borderPopUp{
padding-left: 20px;;
padding-right:20px;
position:absolute;
background:#d3d3d3d4;
animation: openLikeDrawer 800ms ease-in-out;
width:50%;
left:20%;
}
#keyframes openLikeDrawer{
from {left:0px; }
to { left: 20%; }
}
app.component.html to be :
<div>
<mat-grid-list cols="3" rowHeight="3:1">
<mat-grid-tile *ngFor="let asset of assets; index as i">
<div class="border">
<p>{{asset.name}} </p>
<p>{{asset.description}} </p>
<button (click)="asset.isShow = true">click</button>
</div>
<div *ngIf="asset.isShow" class="borderPopUp" >
<p>{{asset.description}} </p>
<button (click)='asset.isShow = false'>click</button>
</div>
</mat-grid-tile>
</mat-grid-list>
</div>
This is my final solution:
import { Component, OnInit } from '#angular/core';
import { LearningContentService } from '../../../service/learningcontent.service';
import { ActivatedRoute } from '#angular/router'
import { trigger, style, transition, animate, keyframes, query, stagger } from '#angular/animations';
export class Asset {
name: string;
description: string;
cardtoggle:boolean=false;
constructor(rawObj: any) {
this.name = rawObj.name;
this.description = rawObj.description;
this.cardtoggle = rawObj.cardtoggle;
}
}
#Component({
selector: 'app-catalogue',
templateUrl: './catalogue.component.html',
styleUrls: ['./catalogue.component.scss'],
animations: [
trigger('listAnimation', [
transition('* => *', [
query(':enter', style({ opacity: 0 }), { optional: true }),
query(':enter', stagger('50ms', [
animate('1s ease-in', keyframes([
style({ opacity: 0, transform: 'translateY(-75%)', offset: 0 }),
style({ opacity: .5, transform: 'translateY(35px)', offset: 0.3 }),
style({ opacity: 1, transform: 'translateY(0)', offset: 1.0 }),
]))]), { optional: true })
])
],
),
]
})
export class CatalogueComponent implements OnInit {
assets: Array<Asset> = [];
constructor(private route: ActivatedRoute,
private learningService: LearningContentService,
) {
}
ngOnInit() {
this.loadAssets();
}
loadAssets() {
this.learningService.assets().subscribe((res: any) => {
const datas: Array<any> = res;
datas.forEach(asset => this.assets.push(new Asset(asset)));
console.log(this.assets);
});
}
animate(asset) {
asset.cardtoggle = true;
}
close(asset) {
asset.cardtoggle = false;
}
}
html:
<div fxLayout="column">
<div fxLayout="row">
<p class="page-heading" fxFlex="80%">Catalogue</p>
<div class="page-content-filter" fxLayoutAlign="end">
<button mat-button class="search-btn"><i class="material-icons"> search </i></button>
<input class="form-filter" matInput placeholder="Search...">
</div>
</div>
<mat-grid-list gutterSize="20px" cols="3" rowHeight="3:1" [#listAnimation]="assets.length">
<mat-grid-tile *ngFor="let asset of assets">
<div class="full-width white">
<div class="padding20px" fxLayout="column" fxLayoutGap="15px">
<div fxLayout="row" fxLayoutGap="15px">
<img fxFlex="10" style="width:50px;height:50px;" src="../../../../assets/images/images.jpeg" mat-card-image>
<b fxFlex="100">{{asset.name}}</b>
<mat-icon fxLayoutAlign="end end" class="small-icon pointer" (click)="animate(asset)">spa</mat-icon>
</div>
<div fxLayout="row" fxLayoutGap="10px">
<mat-icon class="small-icon">person</mat-icon>
<p class="small-heading"> Mohit Harshan</p>
<mat-divider vertical="true"></mat-divider>
<mat-icon class="small-icon">play_arrow</mat-icon>
<p class="small-heading">Video</p>
<mat-divider vertical="true"></mat-divider>
<mat-icon class="small-icon">face</mat-icon>
<p class="small-heading">5 points</p>
</div>
<mat-progress-bar class="progress" mode="determinate" value="40"></mat-progress-bar>
</div>
</div>
<div class="pull-right" [ngClass]="{'show': asset.cardtoggle }" class="card2">
<div class="padding20px" fxLayout="column" fxLayoutGap="15px">
<div fxLayout="row" fxLayoutGap="15px">
<b fxFlex="100" class="small-heading">{{asset.name}}</b>
<mat-icon fxLayoutAlign="end end" class="small-icon pointer" (click)="close(asset)">clear</mat-icon>
</div>
<div fxLayout="row" fxLayoutGap="10px">
<p class="small">{{asset.description}}</p>
</div>
<div fxLayout="row" fxLayoutGap="10px" fxFLex="100" fxLayoutAlign="end end">
<button fxFLex="100" mat-button class="green-button" >View Details</button>
</div>
</div>
</div>
</mat-grid-tile>
</mat-grid-list>
</div>
css:
.card2{
position:absolute;
z-index: 20;
background: white;
padding-left: 0px;
padding-right:0px;
width:100%;
height:100%;
margin-left: 100%;
transition: margin-left .5s ease-in-out;
}
.show {
margin-left: 0%;
}
.green-button{
border:1px solid lightgreen;
border-radius: 10%;
font-size: 10px;
color:green;
}

VueJS change border color of the input if input is already filled in

I need to change the border color of the input if the customer already filled in the field.
How can I do this using VueJS ?
<div class="some-basic-div", '#change' => 'checkForInput'>
<div class="dc-form-group ">
<input type='text' id='first_name' >
</div>
<div class="dc-form-group ">
<input type='text' id='last_name' >
</div>
<div class="dc-form-group ">
<input type='text' id='some_text' >
</div>
</end>
I have tried to use pure JavaScript.
checkForInput: function(e) {
let targetDiv = event.target;
if (targetDiv.value == "") {
targetDiv.classList.remove("mod-group-success");
} else {
targetDiv.classList.add("mod-group-success") ;
}
}
So when I am changing the input I need to change the style of the input which I filled in.
I've wrote this code for handling the issue:
Vue.config.productionTip = false
app = new Vue({
el: "#app",
data: {
testValue: ''
}
},
methods: {
checkForInput: function(e){
let input = event.target
if (input.value != "") {
input.classList.add("mod-group-success") ;
} else {
input.classList.remove("mod-group-success");
}
}
}
})
And putted on front end:
'#change' => 'checkForInput'
Uses Class & Styles binding,
below is one simple demo for class binding.
Vue.config.productionTip = false
app = new Vue({
el: "#app",
data: {
testValue: ''
},
computed: {
computedInputStyleEnable: function () { // or use one method instead of computed property
//apply your own logic at here to determinate if enable input-has-value-style
return this.testValue && this.testValue.length > 0
}
},
methods: {
applyInputStyle: function (targetInput) { // bind with one method and return Array
return [targetInput && targetInput.length > 0 ? 'input-has-value-style' : 'input-no-value-style']
}
}
})
.input-has-value-style {
border: 2px solid green;
background-color:lightgreen;
}
.input-no-value-style {
border: 2px solid red;
background-color:pink;
}
<script src="https://unpkg.com/vue#2.5.16/dist/vue.js"></script>
<div id="app">
<div>
<p>Already filled in {{testValue.length}} characters.</p>
<input type='text' v-model="testValue"
:class="{'input-has-value-style': computedInputStyleEnable}"
/>
</div>
<div>
<p>Already filled in {{testValue.length}} characters.</p>
<input type='text' v-model="testValue"
:class="applyInputStyle(testValue)"
/>
</div>
</div>

ionic login button not working in android

Button is working when run on browser using ionic serve and ionic serve --lab command. I am able to login in web browser and redirected to dashboard.
When I generate .apk file and run on android device....login button is not working.
Not redirected to dashboard by click on login button with username and password.
I have tried this reference: Ionic android button not working
but still not get success...please give me any solution .
Login Template
<li class="item-content">
<div class="item-inner">
<div class="item-input">
<label class="item item-input">
<input class="style login3" type="email" name="email" placeholder="E-mail" ng-model="user.email">
</label>
</div>
</div>
</li>
<li class="item-content">
<div class="item-inner">
<div class="item-input">
<label class="item item-input">
<input class="style login3" type="password" name="password" placeholder="Password" ng-model="user.pwdForLogin">
</label>
</div>
</div>
</li>
</div>
<button ng-click="signIn(user)" >
Sign In
</button>
App.js
// State to represent Login View
.state('login', {
url: "/login",
templateUrl: "templates/login.html",
controller: 'LoginCtrl',
resolve: {
// controller will not be loaded until $waitForAuth resolves
// Auth refers to our $firebaseAuth wrapper in the example above
"currentAuth": ["Auth",
function (Auth) {
// $waitForAuth returns a promise so the resolve waits for it to complete
return Auth.$waitForAuth();
}]
}
})
Please help me....
Here I will show you a working example and you can use it for your code.
MY Custom CSS
.bgLogin{
width: 100%;
background-image: url("http://static.vecteezy.com/system/resources/previews/000/084/251/original/christmas-bokeh-vector-background.jpg");
background-size: 100% 100% !important;
background-position: center center;
background-repeat: no-repeat;
background-attachment: fixed;
}
.login-content
{
margin-top:8%;
padding:0px 10px 0px 10px;
}
.login-content .login-form
{
margin-top:40%;
}
View/HTML
<ion-view class="bgLogin" name="login-view">
<ion-nav-bar>
<ion-nav-back-button></ion-nav-back-button>
</ion-nav-bar>
<ion-content class="login-content">
<div class="login-form">
<label class="item item-input">
<input type="text" placeholder="Username" ng-model="data.username">
</label>
<label class="item item-input">
<input type="password" placeholder="Password" ng-model="data.password">
</label>
</div>
<button class="button button-block login-button" ng-click="login()">Login</button>
</ion-content>
</ion-view>
App.js
Assuming your adding references to controller and service
var appStarter = angular.module('starter', ['ionic', 'starter.controllers', 'starter.services']);
define state
.state('login', {
url: '/login',
templateUrl: 'templates/login.html',
controller: 'LoginCtrl'
})
controller for login
appControllers.controller('LoginCtrl', function($scope, $rootScope, LoginService, $ionicPopup, $state, $ionicHistory) {
$scope.data = {};
$scope.login = function() {
LoginService.loginUser($scope.data.username, $scope.data.password).success(function(data) {
$rootScope.userName = $scope.data.username.toUpperCase();
$ionicHistory.nextViewOptions({
disableBack: true
});
$state.go('app.welcome');
}).error(function(data) {
var alertPopup = $ionicPopup.alert({
title: 'Login failed!',
template: 'Please check your credentials!',
buttons: [
{
text: 'Ok',
type: 'orange-btn'
}
]
});
});
}
});
Service for login
.service('LoginService', function($q) {
return {
loginUser: function(name, pw) {
var deferred = $q.defer();
var promise = deferred.promise;
if (name.toLowerCase() == 'ens' && pw == 'ens' || name.toLowerCase() == 'adam' && pw == 'adam'|| name.toLowerCase() == 'illum' && pw == 'illum'|| name.toLowerCase() == 'test' && pw == 'test') {
deferred.resolve('Welcome ' + name + '!');
} else {
deferred.reject('Wrong credentials.');
}
promise.success = function(fn) {
promise.then(fn);
return promise;
}
promise.error = function(fn) {
promise.then(null, fn);
return promise;
}
return promise;
}
}
});

change element style in method callback

This code is trying to add a class to an element. the class definition is located in meteor_app_root/stylesheets/style.css .wrongInput { color: red; }
This method returns fine but the text inside the input element is not changing to red as I am expecting.
edited
I get browser console print "server returned" but the addClass line is not doing its work.
edited
changing the style from color: Red; to border-color: Red; makes the boarder colour red.
What am I doing wrong? Thanks
Template.footer.events({
'click button': function () {
var doc = {};
$('input').each(function () {
this.value && (doc[this.name]=this.value)
});
Meteor.call('processInputs', doc, function (err, res) {
if (res) {
console.log("res " + res);
$('[name="plate"]').addClass("wrongInput");
}
});
}
});
//server.js
Meteor.methods({
processInputs: function (doc) {
return "server acted";
}
});
<template name="content">
<div class="container">
<div class="row">
<section class="col-xs-12">
<form>
<ul class="list-group">
{{#each this.items}}
<li>
<input class="list-group-item basic-vertical-spacing col-xs-12" type="text"
name={{name}} placeholder={{placeholder}}>
</li>
{{/each}}
</ul>
</form>
</section>
</div>
</div>
</template>
I see what it is, you didn't have the if(err):
Meteor.call('myFunction', function(err, data) {
if (err)
{
$('[name="plate"]').addClass("wrongInput");
}
});

Resources