Return non reactive object from setup function - vue.js

I am using the new Nuxt3 composable useAsyncData to fetch a large csv file.
In the setup function I use the useAsyncData to pull the data ( d3.csv is a sort of fetch function)
const { data } = await useAsyncData(() =>
d3.csv(url)
)
Then I return the data from the setup function. I use it in the other methods of the component (which is written in the traditional Vue options API).
When I observe the data object in the chrome dev tools, it is a ref or a reactive proxy. The thing is that I don't want to have such a large reactive object, because it is not going to change.
How can I return the raw object instead of the reactive version? Is it possible?
Thanks!

Related

vuex-persistedstate not saving class methods

I'd like to preference this by saying my backgrounds in in C# so I like declaring methods within my classes. I've created a user class that contains properties and methods and I've added this to my vuex-persistedstate. One of the methods is a logout() method which clears out the properties. When I tried to invoke this method I got the following error:
TypeError: this.$data.user.logout is not a function
I then reviewed local storage and noted the user did not have reference to the class method. So I went ahead and copied the logic from the method into my vue component and it worked so I'm assuming the issue is vuex-persistedstate does not save references to methods which is why the method call did not work.
I'd like to declare the logout method in one location rather than spreading it out across vue components, what is the best practice for accomplishing this? Is it possible to do this in the class declaration or do I need a user helper file?
Sure Berco! My code is also up on GitHub so you can review it there too, but basically it seems to me that vuex does not store methods. The first file you should review is my user.js file:
https://github.com/Joseph-Anthony-King/SudokuCollective/blob/master/SudokuCollective.WebApi/client/src/models/user.js
In this file I have a method called shallow clone which takes the info received from the API and assigns it to the user:
shallowClone(data) {
if (data !== undefined) {
this.id = data.id;
this.userName = data.userName;
this.firstName = data.firstName;
this.lastName = data.lastName;
this.nickName = data.nickName;
this.fullName = data.fullName;
this.email = data.email;
this.isActive = data.isActive;
this.isAdmin = data.isAdmin
this.isSuperUser = data.isSuperUser;
this.dateCreated = data.dateCreated;
this.dateUpdated = data.dateUpdated;
this.isLoggedIn = data.isLoggedIn;
}
}
You of course don't need to abstract this away but I've found it makes the code easier to maintain.
Then in the mounted() lifecycle hook I assign the user received from the API to the component user via the shallowClone method. Please bear in mind I've done additional work on this project and the login form is now it's own component which receives the user as a prop from the app:
https://github.com/Joseph-Anthony-King/SudokuCollective/blob/master/SudokuCollective.WebApi/client/src/components/LoginForm.vue
mounted() {
let self = this;
window.addEventListener("keyup", function (event) {
if (event.keyCode === 13) {
self.authenticate();
}
});
this.$data.user = new User();
this.$data.user.shallowClone(this.$props.userForAuthentication);
},
The full code can be reviewed here:
https://github.com/Joseph-Anthony-King/SudokuCollective
I found a solution... I'm working on improving it. Basically I use the values pulled from localstorage into vuex to create a new user object in the vue component that has reference to the methods located in my user class declaration. I recalled recommendations that we should create clones of objects pulled from vuex for use within the vue component. I'm still refining the code but that's basic idea.

Where to setup an API in Vue.js

I need to use an API that requires initialization with an API key and some other details within my Vue.js app.
var client = api_name('app_id', 'api_key', ...)
I would need to make several API calls with the client object in multiple components in my app
client.api_function(...)
How can I avoid repeating the initialization step in every component?
I'm thinking about using a global mixin in main.js for that
Vue.mixin({
data: function() {
return {
get client() {
return api_name('app_id', 'api_key');
}
}
}
})
Is this a good approach?
I'd rather move your getter to a service and just import, where you actually need it. It doesn't seem to fit into data section, more like methods. A mixin is a decent approach if you need lots of similar stuff: variables, methods, hooks etc. Creating a mixin for only 1 method looks like overkill to me.
// helper.js
export function getClient () {
// do stuff
}
// MyComponent.vue
import { getClient } from 'helpers/helper`
// Vue instance
methods: {
getClient
}
How about creating a helper file and writing a plugin that exposes your api url's? You can then create prototypes on the vue instance. Here's an example,
const helper = install(Vue){
const VueInstance = vue
VueInstance.prototype.$login = `${baseURL}/login`
}
export default helper
This way you can access url's globally using this.$login. Please note $ is a convention to avoid naming conflicts and easy to remember that it is a plugin.

How to call a shared helper function from within a mutation or action in Vuex

I am trying to separate out some code that is common among many calls in my Vuex mutations. I am getting the feeling that this is discouraged but I don't understand why.
Have a look at an image of some sample code below:
I have added this 'helpers' entry in the Vuex - this obviously doesn't exist but how can I call the shared helper function 'getColumn' from mutations and/or actions?
Or do I have resort to calling a static method on a 'VuexHelper' class? :(
Something like:
Note
I have already looked at the following:
Vue Mixins - yes, something like that could work but is not
supported in Vuex - also, vue methods don't return a value...
I have looked at Modules but these still don't give me what I need, i.e. a simple re-usable function that returns a value.
Thanks
I don't see why you may want to put the helper function within the store. You can just use a plain function.
function getColumn(state, colName) {
// Do your thing.
}
const vstore = new Vuex.Store({
// ....
mutations: {
removeColumn(state, colName) {
var column = getColumns(state, colName);
}
}
};
On the other hand, if you really need that, you can access the raw module and all that's included:
var column = this._modules.root._rawModule.helpers.getColumns(state, colName);
Although this syntax is not documented and can change for later versions.
You can implement your Vuex getter as a method-style getter. This lets you pass in the specific column as an argument:
getters: {
getColumn: state => colName => {
return state.columns[colName] || null
}
}
Then getColumn can be used within the store like so:
let column = getters.getColumn('colNameString')
vuex docs > getters > method style access

Accessing json document keys in adapter procedure (IBM worklight)

I have a local jsonstore linked to a remote sql database through an adapter. I am trying to push local data to the remote database like this :
submit_data = function () {
accessor.getPushRequired().then(function (result) { alert(result.length);
accessor.push();
});
Let us say I only added documents (no replace/remove).
I want my add procedure to look like this:
function addGegegr(document) {
//WL.Logger.warn(document[56]);
return WL.Server.invokeSQLStoredProcedure({
procedure : "DBO.USP_TIM_add_sp",
parameters : [document.key1,document.key2,document.key3,...]
});
}
And same for the replace/remove procedure, they should be calling other stored procedures with the same parameters.
However, I get errors because it seems the variable "document" worklight is passing to the add function after push is called is just a string and not a json object.
So my question is : how do I access the json attributes from the adapter procedure? If not possible, can I pass those attributes to the push function?
P.S.: passing each of the n documents to add as parameter of push() does not work and causes add to be called n*n times instead of n...
Try using JSON.parse to turn the string into a JavaScript object.
function addGegegr(document) {
var doc = JSON.parse(document);
//... use doc as a regular JavaScript object
}
If JSON.parse is not available there, you can add it by including this code in the adapter implementation file.

Remove all documents in a JSONStore collection (without using removeCollection() )

I am working on IBM Worklight and have question about JSONStore. How can I write a function that remove all documents in a JSONStore collection keeping the reference of the collection?
In other words I want to remove the documents without removing the collection. I can't use removeCollection() in my application because I can't quit the application and call wlCommonInit() again (that calls get and init on JSONStore).
Thanks so much for your help
Andrea
At the moment there is no API to easily achieve this. Your options are:
1.Call remove collection then init for the specific collection you want to clear and re-use. No need to call wlCommonInit again. Some pseudocode:
var collections = {
people : {...},
orders: {...},
greetings: {...}
};
var options = {...};
WL.JSONStore.get('greetings').removeCollection()
.then(function () {
return WL.JSONStore.init({greetings: collections.greetings}, options);
})
.then(function () {
//re-use the collection here
});
2.Use the find API to locate documents and the remove API to remove them. There's an example here.
You can open a feature request here.
assuming access is an accessor to your collection, you can do this :
access.findAll()
.then(function(result){
if(result.length>0)
{
access.remove(result,{push:false})
}
})
.fail(function(error_msg){
alert(error_msg);
});
but keep in mind this will not reset the ids (silly jsonstore !), so they will get shifted by the length of the collection every time you do that.
P.S.: From my experience, the removeCollection API should be avoided in case of encrypted collections because of the time it takes to init an encrypted collection on a low-performance mobile device...