make a method globally available in Vue.js - vue.js

In several Vue files this computed property checks if this.data is not an empty object:
computed: {
isLoaded() {
return !(this.data && Object.keys(this.data).length === 0 && this.data.constructor === Object); // checks if this.data is not empty
}
}
Then isLoaded is used to conditionally display content in the browser.
I'd like to refactor the code and create a global method somehow that can check if an object is empty so all the files that use this method can get it from a central spot.
Even after doing some reading on Vue mixins and plugins I'm not clear which one best fits this use case. Which one should be used for this? Or is there an altogether different approach that would be better to create a global method?

There are several ways to do it and it and approach depends on particular case. For your case I'd suggest you to create a separate folder for utils functions, where you could have smth like common.js. There you can just export your functions e.g.
export const emptyObj = (obj: any): any => Object.keys(obj).length === 0;
and import it in your component:
import { emptyObj } from "src/utils/common";
In this case it easier to organize your shared functions, easier to test them and have typescript support.

Related

mobx computed always update that computed doesn't work

import {makeAutoObservable} from "mobx";
class Test {
id = 0
constructor() {
makeAutoObservable(this)
}
get total() {
console.log('enss')
return 2;
}
}
const store = new Test();
export default store;
call:
import {isComputed, isComputedProp} from "mobx";
console.log(isComputedProp(Test, 'total'),Test.total,Test.total, Test.total, isComputedProp(Test, 'total'))
console output:
enss
enss
enss
true 2 2 2 true
the computed did not work and does not serve as a cache.
i using mobx 6.6 version in react 18.
Thank you very much for your answer!
This is explained in the docs here
It sometimes confuses people new to MobX, perhaps used to a library like Reselect, that if you create a computed property but don't use it anywhere in a reaction, it is not memoized and appears to be recomputed more often than necessary. For example, if we extended the above example with calling console.log(order.total) twice, after we called stop(), the value would be recomputed twice.
Basically it won't be cached if you use it outside of reactive context.
You can use computed({ keepAlive: true }) option to change this behaviour

TypeScript safe route names?

Consider the following code:
const router = useRouter()
await router.push({
name: 'NonExistingRoute', // no typescript error ):
})
A non existing route name was given, but no TypeScript error happens. Instead the issue will only be noticed on runtime. Any way to get a compile-time error on this?
Perhaps you could wrap this in a utility function that only accepts typed route strings
const router = useRouter()
export type NamedRoute = "login" | "logout" | "user-profile";
export async function goToNamedRoute(name: NamedRoute): Promise<void> {
return router.push({name});
}
In short no.
For a compile error to exist there would need to be something explicitly wrong with the code, referencing an non-existent file, syntax error, etc.
It does sound like you are trying to solve some other issue here...i.e. why do you have the names of non-existing routes in your app?
In any case, perhaps you can avoid your errors programmatically, e.g.
let r = router.resolve({name: 'NonExistingRoute'});
if (r.resolved.matched.length > 0){
// exists
} else {
// doesn't exist
}
If you want to rely on Typescript for detecting wrong routes you might just use enums or closed types maybe?, although that will surely require some composition. Probably one way to go could be:
enum Cities {
NY,
London
}
function routeCreator(city: Cities, restOfPath?: string){
//combine paths somehow, e.g.
if(!restOfPath) return `/${Cities[city]}/`;
return `/${Cities[city]}/${restOfPath}`
}

Typing keys when using with t useTranslation hook

I'm trying to bring type safety to usage of the t function, from the useTranslation hook. I've seen the following thread which expands on the Resources interface but I think it's not exactly what I'm trying to do.
https://github.com/i18next/react-i18next/issues/1280
What I would like to do is the following:
// namespaces - A, B, both have key "hello"
import { useTranslation, TranslationKeys } from 'react-i18next';
export function Blah() {
const { t } = useTranslation();
return <div>{t(TranslationKeys.hello)}</div>;
}
I don't want us as developers to be aware of different namespaces, just to deal with a single merged set of keys. Any help would be really appreciated.
As per: https://react.i18next.com/latest/typescript#create-a-declaration-file
We have 3 namespaces - sport, common and stuff in order of important to least important.
For the TS typings we just merged the contents into the sport namespace which is also the default and this has done fine.
declare module 'react-i18next' {
interface Resources {
'sport': typeof sport & typeof common & typeof stuff;
}
}

vue2 observable mapGetters updated issue

I have a problem with iterating over mapGetters results.
My code looks like :
...mapGetters({
'shop' : 'getShops'
})
After that, when I iterate over the shops and change anything, it changes my parameters in state and it has impact on all of my app state. I need to change parameters on 'copy' of this getters but it also should be observable.
I've tried to assign mapGetters result to a computed variable but it also updated state
How can I achieve this?
here is a typical store getter:
const state = {
obj: {count:1}
}
const getters = {
obj: (state) => {
return state.obj
}
}
if you call a store by either mapGetters or directly through $store.state.obj, you are getting the object itself passed. The object javascritp provides is not immutable, and the nature of objects in js is such that if you make a change to the object when it's passed to a component, it will update in the store too.
There are two ways you can prevent objects not updating through the passed getter.
do not make changes to it EVER, just reference or copy values as needed when changes are needed.
return a copy of the object in the getter
I've personally only used approach 1, but if you need to return a copy for changing (2), you can use any one of these to create a copy
using ES6 spread operator (not a deep copy)
objCopy: (state) => {
return {...state.obj};
}
also a good option for ES6 (not a deep copy):
objCopy: (state) => {
return Object.assign({}, state.obj});
}
or the ES5 way, which creates a deep copy (so the children, grandchildren, etc don't succumb to same issue)
objCopy: (state) => {
return JSON.parse(JSON.stringify(state.obj));
}

How to override dojo's domReady

I want to override dijit._CssStateMixin's domReady() method.
Is there any way to override that instead of changing the listener mechanism in Dojo.
I tried overriding _cssMouseEvent() method in simple javascript, but it still does invoke dijit's _cssMouseEvent() from domReady().
I have tried following approach:
dojoConfig = {
map: {
'dijit/_CssStateMixin': {
'dojo/domReady': 'app/noop'
}
}
};
I have added 'app' folder and then 'noop.js' inside that.
noop.js has nothing in it:
define([], function () {
return function () {};
});
Even after this I can see that dijit.js's _CssStateMaxin domReady() getting called from listener.apply (code snippet pasted below)
var addStopImmediate = function(listener){
return function(event){
if(!event.immediatelyStopped){// check to make sure it hasn't been stopped immediately
event.stopImmediatePropagation = stopImmediatePropagation;
return listener.apply(this, arguments);
}
};
}
If your ultimate goal is to prevent the domReady callback in dijit/_CssStateMixin from running, your simplest bet is likely to re-map dojo/domReady to a different module that doesn't call the callback at all, when loaded via dijit/_CssStateMixin.
NOTE: Stripping out these handlers might have adverse visual effects on Dijit widgets which inherit _CssStateMixin, since it may hinder the application of Dijit CSS classes related to hover and focus. But if your concern is that _CssStateMixin is hampering performance, it may at least be worth a try to confirm or deny your suspicion.
First we have to create a simple module that returns a function that does nothing, which we will later substitute for dojo/domReady when loaded by dijit/_CssStateMixin, so that it can still call domReady but it won't execute the callback it passes.
For simplicity's sake I'll assume you already have a custom package that you can easily add a module to; for this example I'll assume it's called app. Let's create app/noop:
define([], function () {
return function () {};
});
Now let's configure the loader to map app/noop in place of dojo/domReady specifically when loaded by dijit/_CssStateMixin:
var dojoConfig = {
...,
map: {
'dijit/_CssStateMixin': {
'dojo/domReady': 'app/noop'
}
},
...
};
Now the offending domReady callback should no longer be run.
If you're curious about map, you can read more about it in this SitePen FAQ.