Vue: Check form input is changed by user - javascript

I am new to Vue and want to achieve below result.
I have a form of data and a save button, before the page loads, it will fetch database and fill the form data. Because all the form data are filled, the save button is disabled and the user can not click unless the user change some data, then it knows the form data has changed, the save button will no longer be disabled and can be saved.
I know that should use watch property, but actually how I can implement this?
Thank you guys!
The form data is like this
data(){
return {
form: {
firstName: "",
lastName: ""
}
}
}

You can do something as below by having the two different objects actual and modified.
Here I have used underscore js for deep clone or isEqual, so don't forget to import.
computed: {
// Use is property for the save button to enable or disable
isDataChanged: function() {
return _.isEqual(this.actualForm, this.modifiedForm);
}
},
data() {
return {
actualForm: {
firstName: "",
lastName: ""
},
modifiedForm: {
firstName: "",
lastName: ""
}
}
},
methods: {
fetchData: function() {
// get data and assign it to actual form
this.actualForm = responseData;
this.modifiedForm = _.cloneDeep(this.actualForm) // this will create the new instance
}
}

You can use a watch on form like this below. You can also use deep:true if you need to watch nested property within form.
watch: {
form: {
deep: true,
handler(val) {
// Enable save button here. You can also evaluate any other condition to enable
}
}
}

Related

Sequelize custom validation - unable to access all fields in entity

I attempted to create a model in sequelize (say has 3 attributes, attrA, B, and C) with some custom validation logic. This tutorial helped me get most of it set up:
const Model = Sequelize.define('model', {
attrA: { type: Sequelize.STRING },
attrB: { type: Sequelize.STRING },
attrC: { type: Sequelize.STRING },
}, {
validate: {
someValidationLogic() {
// Do something with attrA,B,C
// if (this.attrA ... this.attrB ... this.attrC) throw new Error..
}
}
})
In the application logic however, only say, 2 out of the 3 attributes (A and B) need to be updated:
Model.update(
{
attrA: 'foo',
attrB: 'bar'
}, {
where: {
id: 1,
},
returning: true,
})
This results in that when the custom validation logic being called, in the this object accessed in the function, only attrA and attrB are defined in this, and attrC remained undefined. This causes the validation logic to fail because attrC cannot be read. Is there any way I can get the object visible from someValidationLogic() to have all attributes populated? Or should this "validation" shouldn't have been validation logic at all and should've been done on the application level?
Your validation logic could take in account the possibility of attrC not being defined :
validate: {
someValidationLogic() {
if (this.attrA !== 'undefined' && this.attrA === 'forbidden value' ) {
// throw new Error
}
}
}
But if your validation includes checking the provided values against current database values, then you would better handle this in the application layer : first recover the current database record, manipulate it as needed, then save it to database.

How to hold data without change in vue js

I have a user info object like this
data: function(){
return {
userinfo: {
name:'',
username:'',
imagePath:''
},
previousUserInfo:{}
}
}
and somewhere else i display this user infos:
<template>
<div> user name: {{userinfo.name}}</div>
<div> username: {{userinfo.username}}</div>
....
in some situation current user changes and i should save previous user data in previousUserInfo object:
this.$set(this, 'previousUserInfo', this.userinfo);
but when user fills new data in userinfo, previousUserInfo data also changes.
i also tried to user another variable to hold data but reuslts is the same :
var previousUserInfo = this.userinfo;
this.$set(this, 'previousUserInfo', previousUserInfo);
what's the problem?
this.userinfo and this.previousUserInfo are pointing to same object.
You can try doing deep copy value of this.userinfo
this.$set(this, 'previousUserInfo', JSON.parse(JSON.stringify(this.userinfo));

Update form data based on a method in VueJS

I am using VueJS and I have a form with two fields. The user is required to enter the first field, and I want the value of second field to be calculated using the value from first field and passing it through a method.
HTML
<div id="app">
<input type="text" v-model="value.label">
<input type="text" v-model="value.slug">
<!-- Slug value to display here -->
<br /><br />
{{value}}
</div>
Javascript
new Vue({
el:'#app',
data:{
value:{
label: '',
slug: '' // This value is calculated by passing label to santiize()
}
},
computed: {
},
methods: {
sanitize (label) {
return label+'something'
}
}
});
The user enters the first field which updates value.label
We need to pass value.label through sanitize() method and update value.slug . This should also immediately show up in the form field.I don't know how to do it. So, if the user types nothing in the form field it will have an automatic value returned as described.
Along with that it would have been awesome, if we allow the user to bypass what the santize function returns, if the user decides to type the slug value himself in the form field. So, if the user decides to type, the typed value will be set.
I created this fiddle for it - https://jsfiddle.net/9z61hvx0/8/
I was able to solve the problem by changing the data structure a bit and adding a watcher to 'label...
new Vue({
el:'#app',
data:{
label:'',
slug: ''
},
computed: {
computedSlug () {
return this.value.label+'Manish'
}
},
watch: {
label: function () {
this.slug = this.sanitize(this.label)
}
},
methods: {
sanitize (label) {
return label+'something'
}
}
});
Any other more sophesticated answers are most welcome :)

A datatable as the full-featured form element

The idea I'm trying to achieve is to embed the datatable into the form.
For now, the form acts as a container. So far there are no any issues, but the name property for the datatable if ignored. The datatable not belongs to the form elements. AFAICS the following configuration is pretty common:
{
view:"form",
elements:[
{ view:"text", name:"inp1", value:"Test input" },
{ view:"datatable", name:"formDT", autoConfig:true, data:grid_data }
]
}
http://webix.com/snippet/7b7a8f2e
But if in the dataForm.elements I see only inputs.
Ideally, I want to get and set the datatable selection through the form's setValues and getValues methods. Or do I need to write my own method to gather the data from the inputs and the datatable separately? Has anyone faced such task before? TIA.
Here a custom component draft inherit datatable but support getValue setValue in order to act as a form input :
webix.protoUI({
name: "datatableInput",
defaults: {
},
$init: function(config) {
},
// Define component value (used by form setValues)
setValue: function(value) {
console.log('setValue');
this.clearSelection();
if (value) this.select(value);
},
// Get component value (used by form getValues)
getValue: function() {
console.log('getValue');
var item = this.getSelectedItem();
if (item) return item.id;
}
}, webix.ui.datatable);
Updated snippet :
http://webix.com/snippet/f952f35e

How to add additional fields to user documents (not in profile)?

I know that the classic way to add data to user collection is in profile array, but according to this document, it is not the best way to store data.
Is there an alternative to that, for example to create a field in the root of user collection at the same level with default fields (_id, username, etc.)?
There is nothing wrong per-se with the profile field, other than the fact that a users can (currently) directly update their own profile by default.
I don't find this behavior desired, as a user could store arbitrary data in the profile.
This may become a real security risk if the developer uses that field as a source of authority; for example, stores the user's groups or roles in it.
In this case, users could set their own permissions and roles.
This is caused by this code:
users.allow({
// clients can modify the profile field of their own document, and
// nothing else.
update: function (userId, user, fields, modifier) {
// make sure it is our record
if (user._id !== userId)
return false;
// user can only modify the 'profile' field. sets to multiple
// sub-keys (eg profile.foo and profile.bar) are merged into entry
// in the fields list.
if (fields.length !== 1 || fields[0] !== 'profile')
return false;
return true;
}
});
The first thing to do is to restrict writes to it:
Meteor.users.deny({
update() {
return true;
}
});
It could then be updated using methods and other authorized code.
If you add your own fields and want to publish them to the currently logged-in user, you can do so by using an automatic publication:
Meteor.publish(null, function () {
if (this.userId) {
return Meteor.users.find({
_id: this.userId
}, {
fields: {
yourCustomField1: 1,
yourCustomField2: 1
}
});
} else {
return this.ready();
}
});
Meteor.users is just a normal Mongo.Collection, so modifying it is done just like any other Collection. There is also the creation hook, Accounts.onCreateUser which allows you to add custom data to the user object when it is first created, as mentioned in #MatthiasEckhart's answer.
You could add extra fields to user documents via the accountsServer.onCreateUser(func) function.
For example:
if (Meteor.isServer) {
Accounts.onCreateUser(function(options, user) {
_.extend(user, {
myValue: "value",
myArray: [],
myObject: {
key: "value"
}
});
});
}
Please note: By default, the following Meteor.users fields are published to the client username, emails and profile. As a consequence, you need to publish any additional fields.
For instance:
if (Meteor.isServer) {
Meteor.publish("user", function() {
if (this.userId) return Meteor.users.find({
_id: this.userId
}, {
fields: {
'myValue': 1,
'myArray': 1,
'myObject': 1
}
});
else this.ready();
});
}
if (Meteor.isClient) {
Meteor.subscribe("user");
}

Categories