access global script function vue - javascript

How
<script>
const fakeApiRequest = (id) => {
return id;
};
export default {
data() {
return {
ids: [1, 2, 3, 4, 5, 6],
};
},
methods: {
newValues(id) {
this.ids.forEach((el) => el.fakeApiRequest(id));
}
},
};
</script>
How can I access global script function - const fakeApiRequest ? Meanwhile using Window object (alike window.fakeApiRequest ) is useless also.

You can try something like this:
<script>
export default {
data() {
return {
ids: [1, 2, 3, 4, 5, 6],
};
},
methods: {
fakeApiRequest(id){
return id
},
newValues(id) {
this.ids.forEach((element) => {
console.log(this.fakeApiRequest(element))
});
}
},
};
</script>
<template>
<div>
{{newValues(5)}}
</div>
</template>

Welcome to stackoverflow,
the first thing that came to my mind was if it is really needed to do that many api requests. Just a side note: wouldn’t it be better to receive the data for multiple ids at the same time with only one API call?
I think in your example, that you posted into the codesandbox the problem is, that you don’t set the new array. The call to [].forEach is not setting anything. As you call an api, you need to make sure, all requests are resolved.
As some of the requests might be rejected, you could await Promise.allSettled and filter the results by the status:
const fakeApiRequest = async (id) => {
// await some api call...
return id;
};
export default {
methods: {
async newSuccessIds() {
const results = await Promise.allSettled(
// the fakeApiRequest can be called directly
// as it is part of the closure context.
this.ids.map(fakeApiRequest)
);
return results
.filter(({ status }) => status === 'fulfilled')
.map(({ value }) => value)
}
},
};

Related

Pinia|Vue3 I can't access the property of the object that returned from the Pinia action

first of all I am using the Mockjs to simulate the backend data:
{
url: "/mockApi/system",
method: "get",
timeout: 500,
statusCode: 200,
response: { //
status: 200,
message: 'ok',
data: {
'onlineStatus|3': [{
'statusId': '#integer(1,3)',
'onlineStatusText': '#ctitle(3)',
'onlineStatusIcon': Random.image('20*20'),
'createTime': '#datetime'
}],
'websiteInfo': [{
'id|+1': 1,
}]
}
}
}
the data structure would be: https://imgur.com/a/7FqvVTK
and I retrieve this mock data in Pinia store:
import axios from "axios"
import { defineStore } from "pinia"
export const useSystem = defineStore('System', {
state: () => {
return {
systemConfig: {
onlineStatus: [],
},
}
},
actions: {
getSystemConfig() {
const axiosInstance = axios.interceptors.request.use(function (config) {
// Do something before request is sent
config.baseURL = '/mockApi'
return config
}, function (error) {
// Do something with request error
return Promise.reject(error);
})
axios.get('/system/').then(res => {
this.systemConfig.onlineStatus = res.data.data.onlineStatus
})
// console.log(res.data.data.onlineStatus)
axios.interceptors.request.eject(axiosInstance)
}
}
})
I use this store in the parent component Profile.vue:
export default {
setup() {
const systemConfigStore = useSystem()
systemConfigStore.getSystemConfig()
const { systemConfig } = storeToRefs(systemConfigStore)
return {
systemConfig,
}
},
computed: {
getUserOnlineStatusIndex() {
return this.userData.onlineStatus//this would be 1-3 int.
},
getUserOnlineStatus() {
return this.systemConfig.onlineStatus
},
showUserOnlineStatusText() {
return this.getUserOnlineStatus[this.getUserOnlineStatusIndex - 1]
},
},
components: {UserOnlineStatus }
}
template in Profile.vue I import the child component userOnlineStatus.vue
<UserOnlineStatus :userCurrentOnlineStatus="userData.onlineStatus">
{{ showUserOnlineStatusText }}
</UserOnlineStatus>
here is what I have got https://imgur.com/fq33uL8
but I only want to get the onlineStatusText property of the returned object, so I change the computed code in the parent component Profile.vue:
export default {
setup() {
const systemConfigStore = useSystem()
systemConfigStore.getSystemConfig()
const { systemConfig } = storeToRefs(systemConfigStore)
return {
systemConfig,
}
},
computed: {
getUserOnlineStatusIndex() {
return this.userData.onlineStatus//this would be 1-3 int.
},
getUserOnlineStatus() {
return this.systemConfig.onlineStatus
},
showUserOnlineStatusText() {
return this.getUserOnlineStatus[this.getUserOnlineStatusIndex - 1]['onlineStatusText']//👀I chage it here!
},
},
components: {UserOnlineStatus }
}
but I will get the error in the console and it doesn't work:
https://imgur.com/Gb68Slk
what should I do if I just want to display the specific propery of the retrived data?
I am out of my wits...
I have tried move the store function to the child components, but get the same result.
and I google this issue for two days, nothing found.
Maybe it's because of I was trying to read the value that the Profile.vue hasn't retrieved yet?
in this case, how could I make sure that I have got all the value ready before the page rendered in vue3? Or can I watch this specific property changed, then go on rendering the page?
every UX that has data is coming from remote source (async data) should has spinner or skeleton.
you can use the optional chaining for safe access (if no time to await):
return this.getUserOnlineStatus?.[this.getUserOnlineStatusIndex - 1]?.['onlineStatusText']

Unable to implement pagination in DynamoDB DocumentClient

I'm using a React/DynamoDB stack for a project. I'm trying to get pagination to work using the scan method in DynamoDB DocumentClient. Here's the function I'm using:
async function getItems(lastItem?) {
try {
const params = {
TableName: "posts",
Limit: 1,
};
if (lastItem) {
params.ExclusiveStartKey = { item_id: lastItem };
}
const response = await docClient.scan(params).promise();
console.log(response)
return {
items: response.Items,
lastItem: response.LastEvaluatedKey,
};
} catch (error) {
throw error;
}
}
I use this component to console.log this response:
import { getItems } from "../../atoms/functions/AWS";
function Test() {
return (
<div>
<button onClick={() => getItems()}>get item</button>
</div>
);
}
However, with each click I'm getting the same result:
Object { Items: (1) […], Count: 1, ScannedCount: 1, LastEvaluatedKey: {…}, … }
"$response": Object { retryCount: 0, redirectCount: 0, maxRetries: 10, … }
​Count: 1
​Items: Array [ {…} ]
​LastEvaluatedKey: Object { postId: "2" }
ScannedCount: 1
I'm using a mock DynamoDB table with 5 posts - postId: "1", postId: "2", and so on.
Am I implementing the getItems function incorrectly? How can I modify the above code to paginate through all the posts?
EDIT:
I updated my component in line with Mark B's suggestion:
function Test() {
const [item, setItem] = useState();
useEffect(() => {
getItems().then((resp) => setItem(resp));
}, []);
return (
<div>
<button onClick={() => getItems(item)}>get item</button>
</div>
);
}
And replaced return {items: response.Items, lastItem: response.LastEvaluatedKey}; with return response.LastEvaluatedKey;.
I thought that this would finally work. However, I'm getting the following error:
Uncaught (in promise) ValidationException: The provided starting key is invalid: The provided key element does not match the schema

How to make sure the function is executed in VueJS

I'm trying to execute 3 functions, and after than console.log the values that they change. I think there should be better approach for this kind of problems, but I'm not sure what it is. What I've done is I went old school, and added loading flag. Basically, loading = 3, when function is loaded, loading--
I'd like to demonstrate my current code (well actually it's not the same, but it will work for demo purposes), so you can get the feeling:
data:() => ({
loading: 3,
first: null,
second: null,
third: null
}),
methods: {
first() {
this.$route.get('/data/for/first').then(response => {
this.first = response.data;
this.loading--;
})
},
second() {
this.$route.get('/data/for/second').then(response => {
this.second = response.data;
this.loading--;
})
},
third() {
this.$route.get('/data/for/third/a').then(responseA => {
let thirdA = responseA.data;
this.$route.get('/data/for/third/b').then(responseB => {
let thirdB = responseB.data;
if (thirdA === thirdB) {
this.third = true;
}
this.loading--;
})
})
},
fireFunctions() {
this.first();
this.second();
this.third();
}
},
watch: {
loading: function() {
if (this.loading === 0) {
console.log(this.first, this.second, this.third)
}
}
}
The output looks like this:
dataForFirst, dataForSecond, dataForThird;
But, if I don't use the watcher, and load this.fireFunctions() in mounted() i get:
dataForFirst, dataForSecond, undefined;
Now, as I understand, this is happening because this.third() needs more time to process the data. As you can see in the code, I added loading flag. So, fire functions will only execute when all of the functions are loaded.
I don't think this is the best approach, so I'd like to hear your opinion on this one.
How would you handle it?
Use Promise.all to wait on all your async functions to return and then run whatever code you need to afterward, example:
methods: {
async all() {
let [first, second, third] = await Promise.all([
this.$route.get('/data/for/first'),
this.$route.get('/data/for/second'),
this.$route.get('/data/for/third')
]);
this.first = first;
this.second = second;
this.third = third;
console.log(first, second, third);
}
}

Vue.js swap array items

In my vue.js application I'm trying to swap 2 forum rows like this:
export default {
data() {
return {
forums: []
}
},
methods: {
increment(forum, index) {
ForumService.increment(forum)
.then(() => {
let b = this.forums[index];
this.forums[index] = this.forums[index++];
this.forums[index++] = b;
});
}
}
}
But nothing happens? What am I doing wrong here?
While #dfsq is correct about the use of index++ Vue doesn't recognize native mutations of arrays due to the inability to observe them. you have to use a mutation method to change them.
try this:
.then(() => {
let rows = [this.forums[index], this.forums[index + 1]];
this.forums.splice(index, 2, rows[1], rows[0] );
});
I haven't tested it and I'll edit when I can.

normalizr v3 and JSON api

I want to normalise the responses I receive from an API. A typical response could look something like this:
// Get all projects
{data:[
{
id: 1
...
team:{
data: {
id:15
...
}
}
},
{
id:2,
....
},
{
id:3,
...
}
]}
How do I write my schemas so that it removes the 'data' container?
Currently, my schema looks like:
export const project = new schema.Entity('projects', {
team: team, // team omitted
},
{
processStrategy: (value, parent, key) => parent.data
}
)
export const arrayOfProjects = new schema.Array(project)
And I am using it like:
const normalizedProjects = normalize(jsonResponse, arrayOfProjects)
normalizedProjects then looks like this:
{
entities:{
projects:{
undefined:{
0:{
team:{
data:{
id:15,
...
}
}
},
1:{...},
2:{...}.
...
50:{...},
}
}
},
result:[] // length is 0
}
I'm not sure why the list of projects is contained in 'undefined', either?
I also use json_api schema.
How about like this?
const projectsSchema = new schema.Entity('projects', {}, {
processStrategy: processStrategy
});
export const processStrategy = (value, parent, key) => {
const attr = value.attributes;
delete value.attributes;
return { ...value, ...attr };
};
export const fetchProjectsSchema = {
data: [projectsSchema]
}
Each of your entity schema that you want to have the data omitted (or anything else fundamentalyl changed) needs to include a processStrategy that you write to remove or change any data. (see more examples in the tests)

Categories

Resources