Vue | define reactive property in plugin - vue.js

Trying to build my own form validation plugin (it's for learning purposes - so I don't use existing libraries).
So I created the following mixin:
export default {
beforeCreate() {
if (! this.$vnode || /^(keep-alive|transition|transition-group)$/.test(this.$vnode.tag)) {
return;
}
// create
this.$validator = new Instance();
// define computed
if (! this.$options.computed) {
this.$options.computed = {};
}
this.$options.computed['errors'] = function() {
return this.$validator.errors;
};
}
}
And loaded the mixin from the component (cause I don't want to see this anywhere):
export default {
name: "SignIn",
components: {
AppLayout,
TextField,
HelperText,
Button
},
mixins: [ValidateMixin]
}
Anyway, anytime input has changed - there is an event which tests the value and controls my errors bag:
export default class {
constructor() {
this.items = {};
}
first(name) {
if (name in this.items) {
return this.items[name][0];
}
return false;
}
add(name, errors) {
this.items[name] = errors;
}
remove(name) {
delete this.items[name];
}
has(name) {
return name in this.items;
}
all() {
return this.items;
}
}
I've bind HTML element (:invalid="errors.has('email')"), and with the devtools I can see the errors bag changing - but the binding is just doesn't work. The invalid property remains false no matter what I'm doing.
I do understand that in order to create reactive property, I've to handle this with getters/setters, but I'm a bit stuck with it.

Related

Vee-validate: Schema validation with dynamic parames

i wan t to create schema validation, with dynamic params use vee-validate in vue js. but the issue is my methods and computed property be undefined in the schema.
here is my code.
`
export defaults {
data() {
const self = this;
return {
fixedSchema: {
fixed: `required|min_value:0|max_value:${self.subTotal()}`,
}
}
},
methods: {
subTotal() {
return 56;
}
}
}
the idea is to create validation schema with dynamic property.

Returning Apollo useQuery result from inside a function in Vue 3 composition api

I'm having some issues finding a clean way of returning results from inside a method to my template using Apollo v4 and Vue 3 composition API.
Here's my component:
export default {
components: {
AssetCreationForm,
MainLayout,
HeaderLinks,
LoadingButton,
DialogModal
},
setup() {
const showNewAssetModal = ref(false);
const onSubmitAsset = (asset) => {
// how do I access result outside the handler function
const { result } = useQuery(gql`
query getAssets {
assets {
id
name
symbol
slug
logo
}
}
`)
};
}
return {
showNewAssetModal,
onSubmitAsset,
}
},
}
The onSubmitAsset is called when user clicks on a button on the page.
How do I return useQuery result from the setup function to be able to access it in the template? (I don't want to copy the value)
You can move the useQuery() outside of the submit method, as shown in the docs. And if you'd like to defer the query fetching until the submit method is called, you can disable the auto-start by passing enabled:false as an option (3rd argument of useQuery):
export default {
setup() {
const fetchEnabled = ref(false)
const { result } = useQuery(gql`...`, null, { enabled: fetchEnabled })
const onSubmitAsset = (asset) => {
fetchEnabled.value = true
}
return { result, onSubmitAsset }
}
}
demo

Vue3: how to pass an object from provide to index

I've been using vue.js for a few weeks and I would like to understand how to globally inject to child components an object coming from the server.
When I try to inject the object using inject:['user'] to a child component it returns an empty object.
data() {
return {
user: []
}
},
methods: {
getLoggedUserData() {
axios.get('/api/get-user/' + window.auth.id
).then(response => {
this.user = response.data.user;
});
}
},
provide: {
return {
user: this.user
}
},
created() {
this.getLoggedUserData();
}
The provide option should be a function in this case to get access to this.user property:
export default {
provide() {
return {
user: this.user
}
}
}
For descendants to observe any changes to the provided user, the parent must only update user by subproperty assignment (e.g., this.user.foo = true) or by Object.assign() (e.g., Object.assign(this.user, newUserObject)):
export default {
methods: {
async getLoggedUserData() {
const { data: user } = await axios.get('https://jsonplaceholder.typicode.com/users/1')
// ❌ Don't do direct assignment, which would overwrite the provided `user` reference that descendants currently have a hold of:
//this.user = user
Object.assign(this.user, user) ✅
}
}
}
demo

How to set vue-i18n in a component's property reactively

I am trying to display some messages or errors depends on an async function result.
When a response's request doesn't include the message property I should use my own.
The problem is that when I use this.$t("message") inside the someMethod method the response.message (data) it isn't reactive. So it won't change after the locale change.
<v-alert v-if="response.error || response.message"
:type="response.error ? 'error' : 'info'">
{{response.error ? response.error : response.message}}
</v-alert>
export default {
data() {
return {
response: {
message: "",
error: ""
}
};
},
methods: {
async someMethod() {
const apiResponse = await sendRequestToAnApi();
if (apiResponse.message) {
this.response.message = apiResponse.message;
} else {
this.response.message = this.$t("translation")
}
}
}
}
I guess I should use computed property to make it work, but I don't have a clue how to mix response object with possible API response.
Any help will be appreciated
You could have your API return not only a message but also a code, where the message could be a textual string based on user locale settings, and the code a slug that will always be English, like users.added or project.created. You can store this code in response.code and create a computed property checking this code and returning the correct vue-i18n translation.
export default {
data() {
return {
response: {
code: "",
error: ""
}
};
},
methods: {
async someMethod() {
const apiResponse = await sendRequestToAnApi();
if (apiResponse.code) {
this.response.code = apiResponse.code;
} else {
this.response.code = null
}
}
},
computed: {
translatedMessage () {
if (this.response.code === 'users.added') {
return this.$t('translate')
}
return 'unknown code'
}
}
}
Of course you could also make this work with a textual string coming from the API, but personally I like working with a specific code that is independent from language settings.

Onsen + VueJS: Call back from child component (using onsNavigatorProps)

Per documentation here
If page A pushes page B, it can send a function as a prop or data that modifies page A’s context. This way, whenever we want to send anything to page A from page B, the latter just needs to call the function and pass some arguments:
// Page A
this.$emit('push-page', {
extends: pageB,
onsNavigatorProps: {
passDataBack(data) {
this.dataFromPageB = data;
}
}
});
I am following this idea. Doing something similar with this.$store.commit
I want to push AddItemPage and get the returned value copied to this.items
//Parent.vue
pushAddItemPage() {
this.$store.commit('navigator/push', {
extends: AddItemPage,
data() {
return {
toolbarInfo: {
backLabel: this.$t('Page'),
title: this.$t('Add Item')
}
}
},
onsNavigatorProps: {
passDataBack(data) {
this.items = data.splice() //***this*** is undefined here
}
}
})
},
//AddItemPage.vue
...
submitChanges()
{
this.$attrs.passDataBack(this, ['abc', 'xyz']) // passDataBack() is called, no issues.
},
...
Only problem is this is not available inside callback function.
So i can't do this.items = data.splice()
current context is available with arrow operator.
Correct version:
onsNavigatorProps: {
passDataBack: (data) => {
this.items = data.splice()
}
}