How to hide part of input value in v-text-field? - vue.js

The Problem-
The purpose of this v-text-field is, to allow users manually type in and change their name on the website. But for security, I hope to hide all the parts of the input value except the last char of the username.
Since the Vuetify text field is two-way binding, it's cumbersome to set up. I didn't find the proper npm extension to serve this request as well.
My Code-
<template>
<ValidationProvider>
<v-text-field
hide-details="auto"
v-model="YourName"
label="username"
placeholder="type your name" />
</ValidationProvider>
</template>
<script>
export default {
data() {
return {
YourName: ''
}
}
}
</script>
Expectation
(1) User type name as "Allen Walker" in the text field.
(2) v-model receives the user name "Allen Walker" to Database. If he buys products from the website, the username will automatically be put as "Allen Walker" in the step of Checkout.
(3) What I want to achieve-
In the User-Profile, the username will be displayed and the user can edit it but before clicking on the text field, the displayed name should look like "**********r".

There could be more methods to do this but that relies on your UX as well like how you want to show the hidden characters and when to show the full name, etc.
I can think about the subsequent technique-
On the user profile page's mounted hook, replace the desired characters with the special symbol (*), and make your text field read-only, so it won't update.
When focusing on the text field, show the full name inside it and make it editable.
When focusing out from the text field, save the updated name to your DB, replace the desired characters with the special symbol (*), and make the text field read-only again.
Here is the functioning demo-
<!DOCTYPE html>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
</head>
<body>
<div id="app">
<v-app>
<v-text-field
label="username"
:readonly="readonly"
v-model="updatedName"
#focus="onFocus"
#blur="onBlur"
></v-text-field>
</v-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>
<script>
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
readonly: true, // initial state
username: "nehasoni", // this should come from API
updatedName: null, // for v-model use
}
},
mounted() {
this.hideName()
},
methods: {
hideName() {
// replace all characters except first with a *
this.updatedName = this.username.replace(/.(?=.{1,}$)/g, '*');
},
onFocus() {
// make text field editable
this.readonly = false;
// show full name
this.updatedName = this.username;
},
onBlur() {
/**
* save your name to database and assign response to the username, like this-
* this.username = api_response
* For now, I am using updatedName as API response
*/
this.username = this.updatedName;
// make text field read only again
this.readonly = true;
// Hide the name again.
this.hideName();
}
}
})
</script>
</body>
</html>

Related

Without using v-model, how to set default value of v-combobox?

I'm creating a form with a v-combobox component.
The :items are being retrieved from a table in my DB and I am using v-model to enter whatever is selected into a different table in the DB, so I'm using v-model to link to the new DB table.
I know that I can use v-model to set a default value (meaning that that item is automatically selected), however is there an alternative way to do this since I'm currently using v-model for connecting to the DB?
Form:
<v-combobox
outlined
:items="allTypes"
v-model="plates[plates.findIndex(obj => obj.id === 1)].value"
:search-input="search"
>
</v-combobox>
If I'm following what you are trying to accomplish here...
You want to have a default value set on your combo box that is not the true value of the data it is binded to with v-model?
I'm not sure that is a great idea. Because if the user wants the default value they will leave it, thinking "it's already set to what I want" but it's not actually an accurate reflection of the value they would be setting?
Either way, it sounds like you probably want to move the logic from your current v-model prop to a computed property, so you can separate the logic of getting and setting.
UPDATED With Code Snippet
new Vue({
el: '#app',
vuetify: new Vuetify(),
data() {
return {
// the set value, initially false to use as a 'has a value been set' flag
setValue: false,
// the default value shown before selection has happened
defaultValue: "Pick a value (default)",
// the options to select from
allTypes: [
'dogs',
'cats',
'hamsters',
'something else',
],
// your table data
table: {
value: "null (initially)"
}
}
},
computed: {
// the value the we are binding the combo box to
comboBoxValue: {
// the value to output
get() {
// if a value has not been set
if (!this.setValue) {
// return the default
return this.defaultValue;
} else {
// else return whatever you would like
return this.setValue;
/* plates[plates.findIndex(obj => obj.id === 1)].value */
}
},
// the function that happens when the combo box is set
set(val) {
// val is the value the combox HAS been set to, not something you define here
console.log(val);
// update your table, pass in "val" the combo box value
this.updateTable(val);
// update the set value, combo box no longer show the default value
this.setValue = val;
}
}
},
methods: {
// some method to update your table
updateTable(newValue) {
alert('update table with value: ' + newValue)
this.table.value = newValue;
}
}
})
<link href="https://fonts.googleapis.com/css?family=Roboto:100,300,400,500,700,900" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/#mdi/font#4.x/css/materialdesignicons.min.css" rel="stylesheet">
<link href="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
<div id="app">
<v-app>
<v-content>
<v-container fluid>
<v-row>
<v-col cols="12">
table value: {{table.value}}
</v-col>
<v-col cols="12">
<v-combobox outlined :items="allTypes" v-model="comboBoxValue">
</v-combobox>
</v-col>
</v-row>
</v-container>
</v-content>
</v-app>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue#2.x/dist/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify#2.x/dist/vuetify.js"></script>

Scoping of HTML element id in Vue component

Is there some built-in scoping mechanism for Vue component in the sense that value of id attribute of html element inside Vue component be uniquely defined without programmer's efforts to do it?
In the following code, I create two components and hope each behaves independently to each other. So, ideally if I click on each button, each is required to print out "foo" but actually not because value of ids are duplicated.
<!DOCTYPE html>
<head>
<title></title>
</head>
<body>
<div id="app">
<my-comp></my-comp>
<my-comp></my-comp>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<script src="https://unpkg.com/vue"></script>
<script>
Vue.component('my-comp', {
template: `
<div>
<button id="btn" #click="onClick">Click me</button>
<div id="pid"></div>
</div>
`,
methods: {
onClick(e) {
$('#pid').text("foo");
}
},
});
const vm = new Vue({
el: '#app',
data: () => ({}),
methods: {}
});
</script>
</body>
</html>
Don't use id in vue components unless you are passing a unique value for it using props. You should very rarely ever actually need to get a reference to an element in vue and if you do find you need to then you should be using refs.
In your case you can just use a property and template binding to handle things for you:
Vue.component('my-comp', {
template: `
<div>
<button #click="onClick">Click me</button>
<div>{{ text }}</div>
</div>
`,
data() {
text: ''
},
methods: {
onClick(e) {
this.text = 'foo'
},
},
})
It looks like the vue-uniq-ids package is what you're looking for.
It is a trend to use components. Components are cool, they are small,
obvious, easy to use and modular. Untill it comes to the id property.
Some HTML tag attributes requires using an id property, like
label[for], input[form] and many of aria-* attributes. And the problem
with the id is that it is not modular. If several id properties on the
page will has the same value they can affect each other.
VueUniqIds helps you to get rid of this problem. It provides the set
of id-related directives which value is automatically modified by
adding unique string while keeping the attrbitue easy to read.

How can I display a hint conditionally for a text field, using VueJS and Vuetify?

I am trying to add a hint or error message or some kind of validation (anything is acceptable) to a text field, using Vuetify.js. The hint should only appear if the user clicks on a "Search" button while the search field beside it is empty. I'm stuck trying to find a way to do it. My current code is below:
new Vue({
el: '#app',
data: () => ({
customSearchText: '',
validate: null
}),
computed: {
form() {
return {
validate: this.validate
}
}
},
watch : {
},
methods: {
searchCustomText() {
}
}
})
.v-input.v-text-field.theme--light {
width: 50%;
margin-left: 120px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify/dist/vuetify.js"></script>
<div id="app">
<v-text-field hint="Fill the field to view results" append-icon="search"
v-model="customSearchText" #click:append="searchCustomText">
</v-text-field>
</div>
Link to Codepen : https://codepen.io/anon/pen/jJjZNQ
Hints only show when the text field is focused. So you were on the right track, you just need to focus the text field in the method searchCustomText which is called when the search icon is clicked. You will need to add a ref to the v-text-field so you can reference it in the method.
I also assumed you didn't want the hint when there is something in the text field, so I added an else to set the isFull to true.
Here is the codepen https://codepen.io/anon/pen/GeVQLG

How to save an existing content?

I can't get how to use v-html to save an existing content. For example:
<div ref="content" v-html="content">Hello, World! A lot of divs</div>
How to make to div content was replace only when I will assign a some not null value with content? Or how to make it in another way? Or is the single way to request div content asynchronously?
The next way works, of course, but I lose a data binding.
this.$refs['content'].innerHTML = "New content";
P.S. I am migrating from jQuery and still can't think in Vue.js philosophy clearly.
Actualy, you must read vue documentation.
In your component you must declare content in data, and simply change it in oher places, i.e. in button's click handler or inside component's methods:
new Vue({
el: "#root",
data: function () {
return {
content: 'Hello, World! A <b>lot</b> of divs'
};
},
methods: {
changeText: function() {
this.content = 'This text from component';
}
}
});
<script src="https://cdn.jsdelivr.net/npm/vue"></script>
<div id="root">
<div v-html="content"></div>
<button v-on:click="content = 'This text from button'">Click me</button>
<button v-on:click="changeText">And me</button>
</div>
You could assign a default value to content.
data () {
return {
content: 'Hello, World! A lot of divs'
}
}
When you'll assign a new value to content it will get rendered.
Another way would be to check if content is not null and have 2 different divs using v-if/v-else for conditional rendering.
<div v-if="content" v-html="content"></div>
<div v-else>Hello, World! A lot of divs</div>
and the script
export default {
name: 'customComponent',
data () {
return {
content: null
}
}
}

Vue.js not respecting text input v-bind value, allowing modifications in text input value when it shouldn't (controlled component)

Given the following, simple 'controlled component' in Vue.js, I expected the input value to be fixed, impossible to change, since it's bound (using v-bind) by Vue:
<body>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<div id="app">
<input type="text" v-bind:value="fixedValue">
</div>
<script>
var app = new Vue({
el: '#app',
computed: {
fixedValue: function () {
return 'This should NOT change'
}
}
})
</script>
</body>
But, in reality, the input text only respects this on initial load. I can click on the input field and type anything and it WILL change. Why is that and how to prevent that?
Here's the fiddle: https://jsfiddle.net/6w74yj28/
EDIT:
To compare with React (here's the fiddle: https://jsfiddle.net/ko7duw5x/), if you create a text input and bind it's value, it's impossible to change the text input value by typing inside (which is the behavior I'm trying to achieve with Vue).