Font awesome class icons toggling not working Vue - vue.js

So I am working on the signup form using Vue.js and there is this password part that I want the user to view password and toggle back to unseen password I have both font awesome icons (fas fa-eye and fa-solid fa-eye-slash) but the state only remains the same even after toggling see the password. I tried with text options SEE and HIDE and it worked but the icons are not
My Code :
<div class="field">
<div class="textbox">
<div #click="viewPassword()">
<span v-if="showPassword !== true">
<i class="fas fa-eye"></i>
SEE
</span>
<span v-else>
<i class="fa-solid fa-eye-slash"></i>
HIDE
</span>
</div>
<input
:type="showPassword ? 'text' : 'password'"
:placeholder="$t('common.PASSWORD')"
data-cy="walletPassword"
name="walletPassword"
v-model="walletPassword"
autocomplete="off"
/>
</div>
</div>
Functional code
export default class Login extends mixins(Global, Recaptcha) {
// Component properties
walletEmail = '';
walletPassword = '';
showRecovery = false;
logonError = '';
showPassword = false;
viewPassword() {
this.showPassword = !this.showPassword;
}
}

Observations :
Dynamic :type assignment will give compiling template error. Hence, will suggest to use v-if/v-else clause.
Just to make it clean, You can use v-if="!showPassword" instead of v-if="showPassword !== true".
Live Demo :
new Vue({
el: '#app',
data: {
showPassword: false,
walletPassword: null
},
methods: {
viewPassword() {
this.showPassword = !this.showPassword;
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css"/>
<div id="app">
<div #click="viewPassword()">
<span v-if="!showPassword">
<i class="fas fa-eye"></i>
</span>
<span v-else>
<i class="fa-solid fa-eye-slash"></i>
</span>
</div>
<input v-if="showPassword" type="text" name="walletPassword" v-model="walletPassword" autocomplete="off"/>
<input v-else type="password" name="walletPassword" v-model="walletPassword" autocomplete="off"/>
</div>

Related

Nested Scoped Slots Variable Collisions VueJS

I've created a simple scoped slot component that I need to nest, but I'm struggling to figure out how I can avoid naming collisions.
Vue Component nested-fields
<script>
export default {
props: [
"entityName",
"items"
],
data: function() {
return {
formItems: this.items
}
},
methods: {
addItem: function() {
this.items.push({})
},
removeItem: function(index) {
if (this.items[index].id) {
this.$set(this.items[index], '_destroy', true);
} else {
this.items.splice(index, 1);
}
}
}
}
</script>
<template>
<div class="nested-fields">
<div v-show="item._destroy !== true || typeof item._destroy == 'undefined'" class="card nested-fields__field-set mb-2" v-for="(item, index) in formItems" :key="index">
<div class="card-header d-flex justify-content-between">
<span>Add {{entityName}}</span> <span class="fa fa-times" #click="removeItem(index)"></span>
</div>
<div class="card-body">
<slot name='item-fields' v-bind="{item, index}"></slot>
</div>
</div>
<button class="btn btn-primary btn-xs mb-2" type="button" #click="addItem()">Add {{entityName}}</button>
</div>
</template>
HTML
<nested-fields entity-name="Rotap Analysis" :items="[]">
<template #item-fields="{item, index}">
<div class="form-group col-sm-4">
<label>
Amount (g)
<input type="number" min="0" v-model="item.amount_grams" :name="'setup[input_material_attributes][rotap_analysis_attributes]['+index+'][amount_grams]'" class="form-control">
</label>
</div>
<div class="form-group col-sm-4">
</div>
<div class="form-group col-sm-4">
</div>
<nested-fields entity-name="Sieve" :items="[]">
<template #item-fields="{item2, index2}">
<label>
Sieve Size (US Mesh)
<input type="number" min="0" v-model="item2.size_mesh" :name="'setup[input_material_attributes][rotap_analysis_attributes]['+index+'][rotap_sieves]['+index2+'][size_mesh]'" class="form-control">
</label>
</template>
</nested-fields>
</template>
</nested-fields>
I need to rename the variables in the nested template shown here:
<nested-fields entity-name="Sieve" :items="item.rotap_sieves || []">
<!-- this line --><template #item-fields="{item2, index2}">
So I can use them here:
<input type="number" min="0" v-model="item2.size_mesh" :name="'setup[input_material_attributes][rotap_analysis_attributes]['+index+'][rotap_sieves]['+index2+'][size_mesh]'" class="form-control">
... BUT it does not let me rename the destructuring as I have it from "item" and "index" to "item2" and "index2".
For what it's worth, I'm attempting to replace Cocoon rails gem for nesting forms in my Rails app, though that shouldn't really matter.
Question - How can I rename the variables in nested scoped slots to avoid variable collisions?
I figured out it's a simple destructuring syntax solution:
<template #item-fields="{item: item2, index: index2}">
Works perfectly as expected!

VeeValidate with Yup: input type="number" value is converted to string on submit

I use VeeValidate and Yup for form validation and don't know why my input field with type="number" is converted to string on submit.
When I input 78 and submit the form the output of the console.log in the onSubmit(values) function is the following:
values: {
prioritaet: "78"
}
Am I doing something wrong here or is this the normal behavior of VeeValidate and Yup? I would like to have a number instead of a string after submit.
My code looks like this:
<template>
<div class="container m-3">
<div class="row bg-primary align-items-center py-2">
<div class="col">
<h3 class="text-light mb-0">Format {{ this.action }}</h3>
</div>
<div class="col-auto">
<h5 class="text-light mb-0">{{ this.formatTitle }}</h5>
</div>
</div>
<Form #submit="onSubmit" :validation-schema="formatSchema" v-slot="{ errors }" ref="formatForm">
<div class="row mt-4">
<div class="col">
<h5>Formatdaten</h5>
</div>
</div>
<div class="row mb-2">
<div class="col-4">
<label for="prioritaet-input">Priorität: </label>
</div>
<div class="col">
<Field type="number" name="prioritaet" id="prioritaet-input" class="w-100" />
</div>
</div>
<div class="row justify-content-end">
<div class="col-auto me-auto">
<button class="btn btn-outline-primary">Änderungen übernehmen</button>
</div>
<div class="col-auto">
<button class="btn btn-outline-primary">Abbrechen</button>
</div>
<div class="col-auto">
<button type="sumbit" class="btn btn-outline-primary">Speichern</button>
</div>
</div>
<div class="row mt-4">
<template v-if="Object.keys(errors).length">
<span class="text-danger" v-for="(message, field) in errors" :key="field">{{ message }}</span>
</template>
</div>
</Form>
</div>
</template>
<script>
import { Form, Field } from "vee-validate";
import deLocale from "../assets/yup-localization.js";
import * as Yup from "yup";
import { markRaw } from "vue";
import { mapActions, mapState } from "vuex";
Yup.setLocale(deLocale);
export default {
name: "FormatBearbeitungsSchirm",
props: ["material_id"],
data() {
let action = "neu";
let formatTitle = "Format neu";
let formatSchema = markRaw(Yup.object().shape({
prioritaet: Yup.number().min(1).max(100).integer().label("Priorität"),
}));
return { formatSchema, action, formatTitle };
},
created() {
},
components: {
Form,
Field,
},
methods: {
onSubmit(values) {
console.log("values", values);
},
},
};
</script>
It looks like there is currently no support for specifying the .number modifier on the internal field model value of <Field>, so the emitted form values would always contain a string for number-type fields.
One workaround is to convert the value in the template, updating <Form>'s values slot prop in <Field>'s update:modelValue event:
<Form #submit="onSubmit" v-slot="{ values }">
<Field 👆
type="number"
name="prioritaet" 👇
#update:modelValue="values.prioritaet = Number(values.prioritaet)"
/>
<button>Submit</button>
</Form>
demo
Another simple workaround is to convert the property inside onSubmit before using it:
export default {
onSubmit(values) {
values.prioritaet = Number(values.prioritaet)
// use values here...
}
}
You must use the .number modifier.
You can read about it here
If you want user input to be automatically typecast as a Number, you can add the number modifier to your v-model managed inputs:
const app = new Vue({
el: "#app",
data: () => ({
mynumber1: undefined,
mynumber2: undefined
}),
methods: {
submit() {
console.log(typeof this.mynumber1, this.mynumber1)
console.log(typeof this.mynumber2, this.mynumber2)
}
}
})
<script src="https://cdn.jsdelivr.net/npm/vue#2.6.14/dist/vue.js"></script>
<div id="app">
<form>
<!-- number modifier -->
<input type="number" v-model.number="mynumber1" placeholder="Type here" />
<!-- no modifier -->
<input type="number" v-model="mynumber2" placeholder="Type here" />
<input type="button" #click="submit" value="submit" />
</form>
</div>

Creating an Interactice timeline in Vue Js

I am creating an interactive Timeline in Vue.js and have a base code set up. What currently happens is when you select a year, content shows up but to make it disappear you need to click it again.
What I am trying to do is make the content of the previous year disappear when you click another year.
The Codepen I created is linked below:
Vue JS Timeline
As you can see, my Vue JS code has different set ups for showing the data.
var vue = new Vue({
el:"#app",
data: {
nowShowing: false,
nowShowing2: false,
nowShowing3: false,
nowShowing4: false,
isShowing:false,
message: 'test1',
message2: 'test2',
message3: 'test3',
message4: 'test4',
message5: 'test5',
}});
Then going into the HTML you have a button class
<button class="c-History__year" #click="isShowing ^= true">1880</button>
And the div class:
<div v-show="isShowing">
<p class="c-History__summary">
{{message}}
</p>
</div>
Is this possible to complete in Vue with transitioning or would CSS suffice?
I've bundled all the isShowing variables into just one and the divs are now looking for whether the isShowing var has a specific number and when does, the div will be shown and all others will be hidden.
JS:
const vue = new Vue({
el:"#app",
data: {
showing: -1,
message: 'test1',
message2: 'test2',
message3: 'test3',
message4: 'test4',
message5: 'test5',
},})
HTML:
<div id="app">
<div class="o-Container o-Container--padded">
<div class="c-History">
<div class="c-History__timeline">
<div class="c-History__years">
<span class="c-History__line"></span>
<button class="c-History__year" #click="showing = 0">1880</button>
<button class="c-History__year" #click="showing = 1">1938</button>
<button class="c-History__year" #click="showing = 2">1971</button>
<button class="c-History__year" #click="showing = 3">1982</button>
<button class="c-History__year" #click="showing = 4">2007</button>
</div>
</div>
</div>
<transition name="bounce">
<div v-show="showing == 0">
<p class="c-History__summary">
{{message}}
</p>
</div>
</transition>
<transition name="bounce">
<div v-show="showing == 1">
<p class="c-History__summary">
{{message2}}
</p>
</div>
</transition>
<transition name="bounce">
<div v-show="showing == 2">
<p class="c-History__summary">
{{message3}}
</p>
</div>
</transition>
<transition name="bounce">
<div v-show="showing == 3">
<p class="c-History__summary">
{{message4}}
</p>
</div>
</transition>
<transition name="bounce">
<div v-show="showing == 4">
<p class="c-History__summary">
{{message5}}
</p>
</div>
</transition>
</div>
</div>
</div>
You can do it with a different a simpler approach, first you can change your data structure like this:
var vue = new Vue({
el:"#app",
data: {
message: 'test1',
message2: 'test2',
message3: 'test3',
message4: 'test4',
message5: 'test5',
contentToShow: ''
},
methods: {
showContent(messageIndex) {
this.contentToShow = this[messageIndex]
}
}
})
the idea is to have a method where you are going to pass the index of message property, and set only one visible contentToShow
So your component updated will be
<div id="app">
<div class="o-Container o-Container--padded">
<div class="c-History">
<div class="c-History__timeline">
<div class="c-History__years">
<span class="c-History__line"></span>
<button class="c-History__year" #click="showContent('message')">1880</button>
<button class="c-History__year" #click="showContent('message2')">1938</button>
<button class="c-History__year" #click="showContent('message3')">1971</button>
<button class="c-History__year" #click="showContent('message4')">1982</button>
<button class="c-History__year" #click="showContent('message5')">2007</button>
</div>
</div>
</div>
<transition name="bounce">
<div v-show="contentToShow">
<p :key="contentToShow" class="c-History__summary">
{{contentToShow}}
</p>
</div>
</transition>
</div>
</div>
</div>

How to change view after deleting or adding in angular 5+?

I am building weather app and i am using angular 5 as my frontend framework and local storage as my storage.
I am saving city name from a input field to local storage. The main problem here is when i save city name i want to change my view i.e i want to hide input field and show city name which i have saved earlier.
And next function i have is remove city name from the local storage. In this case also i want to change my view i.e i want to hide city name and show input field. Here is my code
settings.component.html
<div class="row">
<div class="col-md-6 col-xl-8 mt-4 col-center">
<div class="card">
<div class="card-body">
<h3 class="text-center pt-2 pb-2">Setttings</h3>
<hr>
<div class="setting-menu">
<span class="setting-items">
<h5>Add Your City</h5>
</span>
<div *ngIf="storedCity" class="localstorage" #cityDiv>
<div class="storedCity">
<span> {{storedCity | uppercase}} </span>
</div>
<div class="remove-city mt-4">
<span class="remove-icon ml-5">
<i class="fa fa-times" aria-hidden="true" (click)="removeCity()" ></i>
</span>
</div>
</div>
<div class="clearfix"></div>
<div *ngIf="!storedCity" class="city-input pt-4" #inputDiv>
<form action="">
<div class="form-group">
<input type="text" [(ngModel)]="cityName" name="cityName" value={{cityName}} id="cityName" class="form-control" placeholder="Add City ......">
</div>
<div class="form-group">
<button class="btn btn-success add-btn" (click)="update()">Add</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
settings.component.ts
import { Component, OnInit, ViewChild } from '#angular/core';
#Component({
selector: 'app-settings',
templateUrl: './settings.component.html',
styleUrls: ['./settings.component.scss']
})
export class SettingsComponent implements OnInit {
#ViewChild('cityDiv') cityDiv;
#ViewChild('inputDiv') inputDiv;
public cityName: string;
public storedCity = localStorage.getItem("City");
constructor() {
this.cityName = '';
}
ngOnInit() {
}
update() {
localStorage.setItem("City", this.cityName);
this.cityName = '';
}
removeCity() {
localStorage.removeItem("City");
}
}
Add an *ngIf to the input hiding it when the value is set
<input *ngIf='!cityName; else citySet' type="text" [(ngModel)]="cityName" name="cityName" value={{cityName}} id="cityName" class="form-control" placeholder="Add City ......">
and else just show the value
<ng-template #citySet>{{cityName}}</ng-template>

How to remove the html element using $http.delete in VueJS

I use $http.delete in a VueJS project to remove the users from a page. When I click on delete icon the user is delete it from the database but on the front end the html for that user is still on page. Will disappear if I refresh the page.
This whole HTML(down) is a user from a list of users, from a database. I tried wrapping the whole HTML with another div and use inside a v-if directive, but in this case will not show me any user.
So how can I remove the html element too, when I delete the user, without refreshing the page?
If there is another way to delete a user from database, beside this $http.delete, fell free to show it to me.
HTML
<template>
<div>
<div class="card visitor-wrapper">
<div class="row">
<div class="col-md-2">
<div class="checkbox checkbox-success">
<input type="checkbox" id="select-1">
<label for="select-1" style="width: 50px;"><img src="../../assets/icons/visitors-icon.svg" alt=""></label>
</div>
<i class="fa fa-user-o fa-2x" aria-hidden="true"></i>
</div>
<div class="col-md-3">
<p class="visitor-name">{{user.firstName}}</p>
<span class="visitor-email">{{user.userType}}</span>
</div>
<div class="col-md-2">
<p class="visitor-other-detail">{{user.rid}}</p>
</div>
<div class="col-md-2">
<p class="visitor-other-detail">{{user.departmentId}}</p>
</div>
<div class="col-md-2">
<p class="visitor-other-detail">{{createdDate(user.createdDate)}}</p>
</div>
<div class="col-md-1 divider-left">
<div class="edit-icon">
<router-link :to="'/users/edit-user/'+user.rid"><a data-toggle="tooltip" data-placement="top" title="Edit Employee"><i class="ti-pencil-alt" aria-hidden="true"></i></a></router-link>
</div>
<div class="trash-icon">
<a data-toggle="tooltip" data-placement="top" title="Delete Employee" #click="removeUser(user.rid)"><i class="ti-trash" aria-hidden="true"></i></a>
</div>
</div>
</div>
</div>
</div>
</template>
JS
export default {
props: ['user'],
methods: {
removeUser(item) {
this.$http.delete('/user/' + item)
.then((response) => {
console.log('response', response);
});
}
}
}
Set a v-if on the element that you want to have removed.
In your data you can have an attribute like; userIsActive or something which defaults to true. If your ajax call is a success you can set it to false which will make the element disappear with the v-if.
removeUser(item) {
this.$http.delete('/user/' + item)
.then((response) => {
this.userIsActive = false;
console.log('response', response);
});
}
Of course there are dozens of variations on how to do this but this might help you out.
you can use v-html for remove html text and only show text..
<p v-html="items"></p>