So I have the following array of objects as shown below:
const default_apps = [
{
'post_title': 'Excel',
}, {
'post_title': 'Word',
}, {
'post_title': 'SharePoint',
}];
console.log(default_apps);
const test = get_array_of_post_objects('application_launcher');
console.log(test);
Here is the console log for both, the top is default_apps and the bottom is test:
Please note: Both array of objects have post_title: "..." defined inside.
Could someone tell me when I call my vue app using the default_apps array of objects, I get a return as shown below:
But if I substitute default_apps.map for test.map, I get an empty array back as shown here:
They're both very similar array of objects, so I'm just a little confused - All help would be appreciated!
new Vue({
name: 'o365-edit-modal-wrapper',
el: '#o365-modal-edit-wrapper',
data: function() {
return {
available_list: [],
selected_list: default_apps.map((name, index) => {
return {
name: name.post_title,
order: index + 1,
fixed: false
};
}),
editable: true,
isDragging: false,
delayedDragging: false,
}
},
});
Here is the get_array_of_objects function if anyone wants to check it out:
function get_array_of_post_objects(slug)
{
let items = [];
wp.api.loadPromise.done(function () {
const Posts = wp.api.models.Post.extend({
url: wpApiSettings.root + 'menus/v1/locations/' + slug,
});
const all_posts = new Posts();
all_posts.fetch().then((posts) => {
items.push(...posts.items);
});
});
return items;
}
get_array_of_post_objects function call is asynchronous call when executed it returns items which is an empty array and then when promise is resolved, no where to return it again, so you need to wait for the promise (resolved) to return the items.
Related
Let's say PackInput is an array input.
What I'd like to do's return a dynamic amount of objects depending on how large the input array PackInput is.
For example: if PackInput is [4,5,6], then I'd like three objects returned for each ItemID.
For example: return {... ItemID: 4 ...}, return {... ItemID: 5 ...}, return {... ItemID: 6 ...}.
My current code below is only grabbing the first item of the array instead of all of them and I'm not sure why. I've turned my wheels on this for so long and now I've hit a wall. What am I doing wrong?
for(let i = 0; i < PackInput.length; i++) {
return {
TimestampUTC: Date.now(),
Payload: {
ItemID : PackInput[i]
}
}
}
Updated:
let array = PackInput.map((items) => ({
TimestampUTC: Date.now(),
Payload: {
ItemID : items
}
})
);
let objects = array.reduce(function(target, key, index) {
target[index] = key;
return target;
})
return objects;
You can use the map method to achieve what you want
return PackInput.map((element) => ({
TimestampUTC: Date.now(),
Payload: {
ItemID : element
}
}))
A return statement ends the execution of a function, and returns control to the calling function/upper scope.
Update on object:
const object = PackInput.reduce(function(previousValue, currentValue, index) {
return {
...previousValue,
[index]: currentValue
}
}, {})
You need to provide an empty object as 2nd argument for the reduce function.
You can return an array/object. The problem is that you can call return only once in a function and as soon as a function reaches return it would be returned to the caller scope. You can use the loop to create the array/object and then return the final value:
let array = [];
for(let i = 0; i < PackInput.length; i++) {
array.push({
TimestampUTC: Date.now(),
Payload: {
ItemID : PackInput[i]
}
});
}
return array;
I'm looking for a semantic way to perform some step on each item in a Javascript array while in the middle of a method chain, since I can't use forEach for whatever reason:
forEach() executes the callback function once for each array element; unlike map() or reduce() it always returns the value undefined and is not chainable. The typical use case is to execute side effects at the end of a chain.
Laravel Collections have each and tap which perform largely the same function.
I can just use map and return the original item at the end I suppose, but I was wondering if there was a more built-in, semantic method to do so.
While this solution is far from perfect, you could simply filter the array and return true on each element.
This will allow you to keep the reference to each element in the array and perform an action for every single one of them.
array.someChainableFunction().filter(item => {
// we do something with each item
// then return true to keep all the items.
return true;
}).someOtherChainableFunction()...
const elements = [
{
value: 1
},
{
value: 2
},
{
value: 3
},
{
value: 4
},
{
value: 5
},
];
const output = elements.map(item => {
item.value++;
return item;
}).filter(item => {
// we do something with each items.
console.log('first map', item);
// and we return true since we don't want to actually filter the array.
return true;
}).map(item => {
item.value++;
return item;
}).forEach(item => {
console.log('second map', item);
});
console.log(output);
I would highly suggest wrapping this in another function, so it's easier to understand and does not confuse other developpers when using it througout your code.
Array.prototype.tap = function (callable) {
return this.filter(item => {
callable(item);
return true;
});
}
array.someChainableFunction().tap(item => {
// we do something with each item
}).someOtherChainableFunction()...
// here, we use an anonymous function rather than an arrow function
// because we need to have access to the `this` context of the Array object.
Array.prototype.tap = function (callable) {
return this.filter(item => {
callable(item);
return true;
});
}
const elements = [
{
value: 1
},
{
value: 2
},
{
value: 3
},
{
value: 4
},
{
value: 5
},
];
const output = elements.map(item => {
item.value++;
return item;
}).tap(item => {
// we use our custom function.
console.log('first map', item);
}).map(item => {
item.value++;
return item;
}).tap(item => {
console.log('second map', item);
});
console.log(output);
I can just use map and return the original item at the end I suppose, but I was wondering if there was a more built-in, semantic method to do so.
A built-in method that does what map does, except that it returns the array unchanged without your code returning each element?
Or a built-in method like forEach, except that it returns the array unchanged?
I don't think that exists.
While map certainly does what you want once you return the item unchanged, you could wrap forEach() in a chainable function that returns the array:
// add a chainable version of forEach() method to array
function addChainableForEach(array) {
const newArr = [...array];
Object.defineProperty(newArr, 'chainableForEach', {
value: function(callback) {
this.forEach(callback);
return this;
},
enumerable: false
});
return newArr;
}
const arr = [1, 2, 3];
const arr2 = addChainableForEach(arr)
.chainableForEach((el) => {
console.log(`el:`, el);
});
console.log(`arr2:`, JSON.stringify(arr2));
async fetch() {
try {
console.log(await this.$api.events.all(-1, false)); // <-- First log statement
const res = await this.$api.events.all(-1, false); // <-- Assignment
console.log(res); // <-- Second log statement
if (!this.events) {
this.events = []
}
res.data.forEach((event, index) => {
const id = event.hashid;
const existingIndex = this.events.findIndex((other) => {
return other.hashid = id;
});
if (existingIndex == -1) {
this.events.push(events);
} else {
this.events[existingIndex] = event;
}
});
for (var i = this.events.length - 1; i >= 0; --i) {
const id = this.events[i].hashid
const wasRemoved =
res.data.findIndex((event) => {
return event.hashid == id
}) == -1
if (wasRemoved) {
this.events.splice(i, 1)
}
}
this.$store.commit('cache/updateEventData', {
updated_at: new Date(Date.now()),
data: this.events
});
} catch (err) {
console.log(err)
}
}
// The other functions, maybe this somehow helps
async function refreshTokenFirstThen(adminApi, func) {
await adminApi.refreshAsync();
return func();
}
all(count = -1, description = true) {
const func = () => {
return $axios.get(`${baseURL}/admin/event`, {
'params': {
'count': count,
'description': description ? 1 : 0
},
'headers': {
'Authorization': `Bearer ${store.state.admin.token}`
}
});
}
if (store.getters["admin/isTokenExpired"]) {
return refreshTokenFirstThen(adminApi, func);
}
return func();
},
Both log statements are giving slightly different results even though the same result is expected. But this only happens when is use the function in this specific component. When using the same function in other components, everything works as expected.
First data output:
[
{
"name": "First Name",
"hashid": "VQW9xg7j",
// some more correct attributes
},
{
"name": "Second name",
"hashid": "zlWvEgxQ",
// some more correct attributes
}
]
While the second console.log gives the following output:
[
{
"name": "First Name",
"hashid": "zlWvEgxQ",
// some more correct attributes, but this time with reactiveGetter and reactiveSetter
<get hashid()>: reactiveGetter()
length: 0
name: "reactiveGetter"
prototype: Object { … }
<prototype>: function ()
<set hashid()>: reactiveSetter(newVal)
length: 1
name: "reactiveSetter"
prototype: Object { … }
<prototype>: function ()
},
{
"name": "Second name",
"hashid": "zlWvEgxQ",
// some more correct attributes and still without reactiveGetter and reactiveSetter
}
]
As it can be seen, somehow the value of my hashid attribute changes, when assigning the response of the function call.
The next weird behavior happening here, is that the first object where the hashid field changes also gets reactiveGetter and reactiveSetter (but the second object in the array does not get these).
So it looks to me like something is happening with the assignment that I don't know about. Another guess would be that this has something to do with the Vuex store, because I do not change the Vuex tore in the other place where I use the same function.
It is verified that the backend always sends the correct data, as this is dummy data, consisting of an array with two objects with some attributes. So no other data except this two objects is expected.
Can someone explain to me why this behavior occurs?
There are few problems...
Do not use console.log with objects. Browsers tend to show "live view" of object - reference
this.events.findIndex((other) => { return other.hashid = id; }); is wrong, you are using assignment operator (=) instead of identity operator (===). That's why the hashid of the first element changes...
I have a very simple application that initiates a search and filter based on the query parameters. When I initiate the query https://example.com/?filter=2134 it initiates the search and shows me the result of schools. This means that the searchSchools() function is being executed and the results are being fetched.
However, then I execute the filterSuggestions() function, it doesn't seem to apply the filter.
However, when I do a console.log(suggestedSchools) within mounted, it returns empty.
const app = new Vue({
el: '#app',
data: {
suggestedSchools : [],
filter : '',
filteredSchools : [],
},
mounted: function () {
// checking some get parameters and conditions and triggering the search
this.searchSchools(); // function that initiates ajax request and store the results into suggestedSchools
this.filter = 2134; // the postcode value comes from the get request
this.filterSuggestions(); // function that applies the postcode filter to the suggestedSchools list and assign the filtered results to filteredSchools.
},
methods: {
searchSchools() {
axios.get('/search-school').then(response => {
this.suggestedSchools = response.data;
this.filteredSchools = response.data;
})
},
filterSuggestions()
{
this.filteredSchools = this.suggestedSchools.filter(school => {
// filtering logic
}
},
},
});
That's because the searchSchools function makes an asynchronous request so when filterSuggestions function is executed it finds the suggestedSchools array empty. I suggest it should be more like this:
const app = new Vue({
el: '#app',
data: {
suggestedSchools : [],
filter : '',
filteredSchools : [],
},
mounted: function () {
// checking some get parameters and conditions and triggering the search
this.searchSchools(); // function that initiates ajax request and store the results into suggestedSchools
this.filter = 2134; // the postcode value comes from the get request
},
methods: {
searchSchools() {
axios.get('/search-school').then(response => {
this.suggestedSchools = response.data;
this.filteredSchools = response.data;
this.filteredSuggestions()
})
},
filterSuggestions()
{
this.filteredSchools = this.suggestedSchools.filter(school => {
// filtering logic
}
},
},
});
var vue_app = new Vue({
el: '#id1',
data: {
v1:[],
},
methods:{
pushUnique: function() {
this.v1.push({'id':1,'name':'josh'});
this.v1.push({'id':1,'name':'josh'}); //this should not work.
},
},
});
In above code the second push should not execute. I would like to keep id unique. How can this be done in Vue.
THanks
I would move to storing data in an object (keyed by id) and use a computed property to produce your v1 array. For example
data: {
v1obj: {}
},
computed: {
v1 () {
return Object.keys(this.v1obj).map(id => ({ id, name: this.v1obj[id] }))
}
}
Then you can use methods like Object.prototype.hasOwnProperty() to check for existing keys...
methods: {
pushUnique () {
let id = 1
let name = 'josh'
if (!this.v1obj.hasOwnProperty(id)) {
this.v1obj[id] = name
}
}
}