Make computed property available globally - javascript

I'm using Vue 2 and in one of my components I've defined a simple computed property to filter through an array of objects:
computed: {
filteredPlans: {
get() {
let res = [];
if (this.query.length > 1) {
this.plans.forEach(p => {
if (JSON.stringify(p).includes(this.query)) res.push(p);
});
return res;
} else return this.plans;
},
set() {
return this.plans;
}
}
},
I want to using the same logic in 5 other components as well. So, my question is should I just duplicate the code on other compoents or make it available globaly, also how do i do that?

You can try creating a Mixins file and add the computed property in it.
Mixin named test-mixin
export default {
computed: {
filteredPlans: {
get() {
let res = [];
if (this.query.length > 1) {
this.plans.forEach(p => {
if (JSON.stringify(p).includes(this.query)) res.push(p);
});
return res;
} else return this.plans;
},
set() {
return this.plans;
}
}
},
}
This can be reused in any component by importing the mixin file like follows
import testMixin from 'test-mixin';
export default {
mixins: [testMixin]
}

Related

Passing a variable between plugins in Rollup

How can I pass a variable between plugins in Rollup?
What I've tried:
// plugin-a.js
const pluginA = () => {
return {
name: 'pluginA',
async options(options) {
options.define = options.define || {};
options.define['foo'] = 'bar';
}
}
}
// plugin-b.js
const pluginB = (options = {}) => {
return {
name: 'pluginB',
buildStart: async (options) => {
console.log(options)
}
}
}
I'm getting a warning:
(!) You have passed an unrecognized option
Unknown input options: define. Allowed options: acorn, acornInjectPlugins, cache, context, experimentalCacheExpiry, external, inlineDynamicImports, input, makeAbsoluteExternalsRelative, manualChunks, maxParallelFileOps, maxParallelFileReads, moduleContext, onwarn, perf, plugins, preserveEntrySignatures, preserveModules, preserveSymlinks, shimMissingExports, strictDeprecations, treeshake, watch
It seems passing data should be done by what Rollup refers to as Direct plugin communication. This is working for me. I feel this is very hard coupled though.
function parentPlugin() {
return {
name: 'parent',
api: {
//...methods and properties exposed for other plugins
doSomething(...args) {
// do something interesting
}
}
// ...plugin hooks
};
}
function dependentPlugin() {
let parentApi;
return {
name: 'dependent',
buildStart({ plugins }) {
const parentName = 'parent';
const parentPlugin = plugins.find(plugin => plugin.name === parentName);
if (!parentPlugin) {
// or handle this silently if it is optional
throw new Error(`This plugin depends on the "${parentName}" plugin.`);
}
// now you can access the API methods in subsequent hooks
parentApi = parentPlugin.api;
},
transform(code, id) {
if (thereIsAReasonToDoSomething(id)) {
parentApi.doSomething(id);
}
}
};
}
There's also Custom module meta-data, however when I read the meta I always get null.

Local functions not working in VueUse useWebWorkerFn

I'm trying to filter an array of objects using useWebWorkerFn
The following is my code to do the same
import { useWebWorkerFn } from '#vueuse/core'
import { doLowerCase } from './filtering.js'
async function asyncDataSearch(data,searchWords) {
const { workerFn } = useWebWorkerFn(dataSearch, {
dependencies: [
'https://cdn.jsdelivr.net/npm/lodash-es#4.17.21/every.js',
'https://cdn.jsdelivr.net/npm/lodash-es#4.17.21/includes.js'
],
})
const filteredData = await workerFn(data, searchWords)
return filteredData
}
async function dataSearch(data, searchWords) {
return data.filter((e) => {
let isTrueName = true;
if (searchWords.length > 0) {
const myBigStr = doLowerCase(
.trim(
`${e.fname}${e.lname} ${e.cname}`
);
isTrueName = _.every(searchWords, (el) => _.includes(myBigStr, el));
}
return isTrueName;
});
}
And the below is the doLowerCase function in filtering.js file.
export function doLowerCase(myText = "") {
if (myText) {
return myText.toLowerCase();
} else {
return "";
}
}
Now the problem is the lodash functions works when I add the lodash.min.js cdn url but I don't want to import the whole lodash package, when I try to add dependencies of each function as stated here. It shows an error that it failed to import the scripts. Also in the above code doLowerCase is an function present in another file, the function is not working as it is not accessible, how do I import and use the function as expected. Fore more info visit VueUse

set name of properties dynamically JavaScript [duplicate]

Is there a way in typescript to set a property name from a variable?
Something like this
export function objectFactory(prop: string) {
return {
prop: {
valid: false
}
};
}
You are looking for computed properties, this is an ES6 feature and not specific to TypeScript.
export function objectFactory(prop: string) {
return {
[prop]: {
valid: false
}
};
}
You can do it like this:
export function objectFactory(prop: string) {
let data: any = {};
data[prop] = {};
data[prop].valid = false;
return data;
}

How to get data value in regular js file from vue component?

I have component MyComponent.vue where I have data value that constantly changes. I want to pass this value to javascript file(js file should know about changes of value everytime)
Why do I do that? Because my regular js file is a service layer for axios methods. I can import this file in many other components. The file contains axios methods and urls are dynamic.
I want those urls depend on data variable. This data variable comes from MyComponent.js
So the main goal is to make dynamic urls of axios that depend on data variable
I tried some code but it doesn't work, because js file(CategoryService.js) know nothing about this.categoryNumber.
MyComponent.vue:
<script>
export default {
data() {
return {
categoryNumber: 1
}
}
}
</script>
CategoryService.js
import http from "../../../http-common";
let category = "category1";
if (this.categoryNumber === 1) {
category = "category1";
} if (this.categoryNumber === 2) {
category = "category2";
}
class CategoryService {
get(id) {
return http.get(`/${category}/${id}`);
}
update(id, data) {
return http.put(`/${category}/${id}`, data);
}
create(data) {
return http.post(`/${category}`, data);
}
delete(id) {
return http.delete(`/${category}/${id}`);
}
getAll() {
return http.get(`/${category}/all`);
}
}
export default new CategoryService();
So with a bit of refactoring, you could easily get this working.
First of all, I would put the if/else logic of your class into it.
For convenience and scalability, I would use a Vuex store that will keep track of your categoryNumber and share it accross all your components.
Then I would bind my service to my Vue instance so I can easily access it in all my components as well as the store and I would pass the latter to my class as a parameter.
For the last part, I don't know the logic in the http-common file so the code I will show you is a bit nasty. But depending on wether or not you bound 'http' to axios, you could make use of axios interceptors to call the getCategoryNumber() method in every request.
Here's an idea of the implementation I would go for:
const CategoryService = class CategoryService {
constructor(store) {
this._store = store;
this.category = "category1";
}
getCategoryNumber() {
if (this._store.state.categoryNumber === 1) {
this.category = "category1";
}
if (this._store.state.categoryNumber === 2) {
this.category = "category2";
}
console.log(this.category); // for demo puprose
}
get(id) {
this.getCategoryNumber(); // We could use axios request interceptor instead of calling that in every route, but that works !
return http.get(`/${this.category}/${id}`);
}
update(id, data) {
this.getCategoryNumber();
return http.put(`/${this.category}/${id}`, data);
}
create(data) {
this.getCategoryNumber();
return http.post(`/${this.category}`, data);
}
delete(id) {
this.getCategoryNumber();
return http.delete(`/${this.category}/${id}`);
}
getAll() {
this.getCategoryNumber();
return http.get(`/${this.category}/all`);
}
}
const store = new Vuex.Store({
state: {
categoryNumber: 1
},
mutations: {
setCategoryNumber(state, payload) {
state.categoryNumber = payload;
}
}
});
// Bind your service to the Vue prototype so you can easily use it in any component with 'this.$service'
// pass it the store instance as parameter
Vue.prototype.$service = new CategoryService(store);
new Vue({
el: "#app",
store, // dont forget to bind your store to your Vue instance
methods: {
updateCategoryNumber() {
// Put here any logic to update the number
this.categoryNumber = this.categoryNumber === 1 ? 2 : 1;
this.checkServiceCategoryValue();
},
checkServiceCategoryValue() {
// for demonstration purpose
this.$service.getCategoryNumber();
}
},
computed: {
// Look for the store value and update it
categoryNumber: {
get() {
return this.$store.state.categoryNumber;
},
set(value) {
this.$store.commit("setCategoryNumber", value);
}
}
}
});
<div id="app">
<h2>number: {{ categoryNumber }}</h2>
<button type="button" #click="updateCategoryNumber()">
updateCategoryNumber
</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vuex#2.0.0"></script>
Thanks to #Solar
I just added one more parameter for all urls and put the number of category to it
CategoryService.js:
class CategoryOneService {
get(id, category) {
return http.get(`/${category}/${id}`);
}
getAll(category) {
return http.get(`/${category}/all`);
}
}
functions.js:
let catNum = "";
function getQuestion() {
if (this.categoryNumber === 1) {
catNum = "category1";
}
if (this.categoryNumber === 2) {
catNum = "category2";
}
let questionId = this.questionNumber;
CategoryOneService.get(questionId, catNum)
.then(response => {
this.question = response.data.question;
this.answer = response.data.answer;
})
.catch(error => {
console.log(error);
});
}

In Vue JS, call a filter from a method inside the vue instance but $options is undefined

I've already seen this answer which fits my question : In Vue JS, call a filter from a method inside the vue instance
Now with that out of the way, when doing
console.log(this.$options)
I get undefined so I can't call filters on it..
This is my code:
methods:{
style:(input)=>{
return {
backgroundColor:this.$options.filters.color(input),
}
}
},
filters: {
color: function (value) {
console.log(color(value));
if (!value) return ''
return `rgb(${value},${value},${value})`
}
}
Error in render: "TypeError: Cannot read property 'filters' of undefined"
You are using the arrow function for style method. It should be:
style(input) {
return {
backgroundColor:this.$options.filters.color(input),
}
}
And if you are not using this within your filter then you can extract it outside like:
function color (value) {
console.log(color(value));
if (!value) return ''
return `rgb(${value},${value},${value})`
}
methods: {
style(input) {
return {
backgroundColor: color(input),
}
}
},
filters: { color }
you can write this function in methods
methods:{
style:(input)=>{
return {
backgroundColor:this.color(input),
}
},
color: (value) {
console.log(color(value));
if (!value) return ''
return `rgb(${value},${value},${value})`
}
}

Categories

Resources