function call on object with delay - javascript

I am trying to make this code return each employees name.
var company = {
employees: [
{
name: "doug"
},
{
name: "AJ"
}
],
getName: function(employee){
return employee.name
},
getNames: function(){
return this.employees.map(this.getName)
},
delayedGetNames: function(){
setTimeout(this.getNames,500)
}
}
console.log(company.delayedGetNames());
However, when I run the code I get "TypeError: Cannot read property 'map' of undefined"
I have tried doing
setTimeout(this.getNames.bind(this),500)
I just get undefined returned to me.
Can anyone help me out?

You need to add a callback to your function in order to get the names.
var company = {
employees: [
{
name: "doug"
},
{
name: "AJ"
}
],
getName: function(employee){
return employee.name
},
getNames: function(){
return this.employees.map(this.getName)
},
delayedGetNames: function(cb){
setTimeout(()=>cb(this.getNames()),500)
}
}
company.delayedGetNames(names => console.log(names))

Or, using Promise, you could write something like this:
var company = {
employees: [
{
name: "doug"
},
{
name: "AJ"
}
],
getName: function(employee){
return employee.name
},
getNames: function(){
return this.employees.map(this.getName)
},
delayedGetNames: function() {
return new Promise(resolve => setTimeout(() => resolve(this.getNames()), 1000));
}
}
company.delayedGetNames().then(console.log);

With few tricks and getters
var company = {
employees: [
{
name: "doug"
},
{
name: "AJ"
}
],
getName: function(employee){
return employee.name
},
get getNames(){
console.log(this.employees.map(x => this.getName(x)));
},
get delayedGetNames(){
setTimeout(this.getNames,500)
}
}
console.log(company.delayedGetNames);

Related

Filter an array of objects using multiple values from the object

So I have an array of objects that looks like this :
let medicines = [
{
id:3340,
name:nutraplus,
description:"some medicine",
ingredients: [{
ingredient:"glycerol"
},
{
ingredient:"Morphine"
}
]
},
{
id:3320,
name:Panadol,
description:"tablet",
ingredients: [{
ingredient:"Paracetamol"
},
{
ingredient:"Some stuff"
}
]
}
]
I want to to be able to filter by name and by ingredient name I have acheived the former by doing this :
computed: {
medicines() {
return this.$store.state.medicines.filter(med => {
//this.search is the what comes after typing in search bar
return med.name.toLowerCase().includes(this.search.toLowerCase())
})
},
}
Its vue.js so the computed() stuff anyways this works perfectly when searching by name however i also want to be able to search by ingredients from the same search bar. I tried something like this :
edicines() {
return this.$store.state.medicines.filter(med => {
return med.name.toLowerCase().includes(this.search.toLowerCase()) || med.ingredients.map(ing=>{
ing.ingredient.name.toLowerCase().includes(this.search.toLower)
})
})
}
But it didn't work. Any ideas on how to get this working? Thank you for your time.
Haven't used vue in the example, you just need to extract the logic behind the filtering that I have done (Simple JS filtering)
As example -
Try searching for 'Para' - It must return the entries with name/ingredient containing Para
Try searching for 'stuff' - It should return two entries (since both medicine in that array consist of 'some stuff' as ingredient)
let medicines = [{
id: 3340,
name: 'nutraplus',
description: "some medicine",
ingredients: [{
ingredient: "glycerol"
},
{
ingredient: "Morphine"
},
{
ingredient: "Some stuff"
}
]
},
{
id: 3320,
name: 'Panadol',
description: "tablet",
ingredients: [{
ingredient: "Paracetamol"
},
{
ingredient: "Some stuff"
}
]
},
{
id: 3311,
name: 'Amazin',
description: "tablet"
}
];
const form = document.querySelector('form')
form.addEventListener('submit', (e) => {
e.preventDefault();
const searchValue = form.searchText.value.toLowerCase();
const matchValue = medicines.filter(medicine => {
return medicine.name.toLowerCase().includes(searchValue) || (medicine.ingredients ? medicine.ingredients.filter(ingredientObj => {
return ingredientObj.ingredient.toLowerCase().includes(searchValue);
}).length > 0 : false);
});
document.querySelector('.result').textContent = JSON.stringify(matchValue, null, 4);
});
pre {
background: #c5c5c5;
}
<form>
<label for="searchText"></label>
<input type="text" id="searchText" name="searchText">
<button>Search</button>
</form>
<pre class='result'></pre>
This should work.
let medicines = [
{
id:3340,
name:"nutraplus",
description:"some medicine",
ingredients: [{
ingredient:"glycerol"
},
{
ingredient:"Morphine"
}
]
},
{
id:3320,
name:"Panadol",
description:"tablet",
ingredients: [{
ingredient:"Paracetamol"
},
{
ingredient:"Some stuff"
}
]
}
];
const searchPhrase = "Paracetamol";
const filteredByName = medicines.filter((medicine) => {
return medicine.name.toLowerCase() === searchPhrase.toLowerCase();
});
const filteredByIngredient = medicines.filter((medicine) => {
return medicine.ingredients.some((item) => item.ingredient.toLowerCase() === searchPhrase.toLowerCase());
})
const result = [...filteredByName, ...filteredByIngredient];
console.log(result)

Convert multiple json object into array of object

My data is currently stored in this format:
{
"Site1":{
"week":[
{
"access":1
},
{
"access":8
}
]
},
"Site2":{
"week":[
{
"access":16
}
]
},
"Site3":{
"week":[
{
"access":2
},
{
"access":6
},
{
"access":2
}
]
}
}
And I need to convert it into this format:
[
{
"id":"Site1",
"access":[1,8]
},
{
"id":"Site2",
"access":[16]
},
{
"id":"Site3",
"access":[2,6,2]
}
]
As you can see, I also need to take the keys (site name) and make them the "id" values.
Any ideas on how I can do this in JavaScript (I'm using angular v9)? I'm not very good at restructuring that type of data.
You can first take entries and then map it:
var data={ "Site1":{ "week":[ { "access":1 }, { "access":8 } ] }, "Site2":{ "week":[ { "access":16 } ] }, "Site3":{ "week":[ { "access":2 }, { "access":6 }, { "access":2 } ] }};
var result = Object.entries(data).map(([k,v])=>({id:k, access: v.week.map(p=>p.access)}));
console.log(result);
Object.keys()
map()
const data = {
Site1: {
week: [
{
access: 1,
},
{
access: 8,
},
],
},
Site2: {
week: [
{
access: 16,
},
],
},
Site3: {
week: [
{
access: 2,
},
{
access: 6,
},
{
access: 2,
},
],
},
};
const result = Object.keys(data).map(key => ({
id: key,
access: data[key].week.map(w => w.access),
}));
console.log(result);
you can simply use this code for your desired result.
Object.keys(data).map(key => (
{
id: key,
access: data[key].week.map(obj => obj.access),
}
))
Let me know if you face any issue.

JS filter some part from an array of objects

I've this array.
const routes = [
{
path:'/dashboard',
text: "Dashboard"
},
{
path:'/disputes',
text: "Disputes"
},
{
children: [
{
text: "Create Suburb",
path: "/create-suburb"
},
{
text: "View and Update Suburb",
path: "/view-suburb"
}
]
},
{
children: [
{
text: "Create user",
path: "/create-user"
},
{
text: "View and Update users",
path: "/view-users"
}
]
}
]
and I've this array
const permissions = ['/dashboard','/view-suburb'];
What I want is filter out objects from the array where there is not in the permissions array.
My expected out put is this
const routes = [
{
path:'/dashboard',
text: "Dashboard"
},
{
children: [
{
text: "View and Update Suburb",
path: "/view-suburb"
}
]
},
]
Note that two objects are completely removed and some part of the third object also removed. How do I achieve this using JS?
What I've done upto now is this
items.filter(e=>{
if(e.path){
return permissions.includes(e.path)
}else{
}
})
Hope my question is clear to you.
You could do it with a reduce - filter alone won't work here as you're actually transforming child arrays rather than purely filtering the top level array items
routes.reduce((result, route) => {
const { path, children } = route;
if (children) {
const filteredChildren = children.filter(child => permissions.includes(child.path));
// case where some child routes match permissions
if (filteredChildren.length !== 0) {
return [ ...result, { ...route, children: filteredChildren }];
}
}
// case where path is present and permissions includes path
if (path && permissions.includes(path)) {
return [ ...result, route ];
}
// case where there's no match between path and permissions
return result;
}, []);
Try this!!
const routes = [
{
path:'/dashboard',
text: "Dashboard"
},
{
path:'/disputes',
text: "Disputes"
},
{
children: [
{
text: "Create Suburb",
path: "/create-suburb"
},
{
text: "View and Update Suburb",
path: "/view-suburb"
}
]
},
{
children: [
{
text: "Create user",
path: "/create-user"
},
{
text: "View and Update users",
path: "/view-users"
}
]
}
]
const permissions = ['/dashboard','/view-suburb'];
let result = [];
permissions.map(permission=>{
routes.map(route=>{
if(route.hasOwnProperty('children')){
route.children.map((r,i)=>{
if(r.path == permission){
route.children = route.children.splice(i);
route.children = route.children.slice(-1);
result.push(route)
}
});
}else{
if(route.path == permission){
result.push(route)
}
}
});
})
console.log(result)
This one also worked for me.
var newData = [];
$.each(routes, function (key, value) {
debugger
var data = this;
if (data.path) {
if (permissions.includes(data.path)) {
newData.push(data);
}
}
else {
var data2 = data;
$.each(data2, function (key, value1) {
$.each(value1, function (key, value) {
var data = value;
if (data.path) {
if (permissions.includes(data.path)) {
newData.push(data);
}
}
});
});
}
})
Ideally, you should check the access to the route inside the canActivate guard and navigate the user further to the appropriate route.

filter returns an empty array while looping an object's property (array of objects)

I can't understand why do filter returns an empty array when I try to loop through the object's array property.
Though, When I try to do console.log(this.users) inside the getFilteredUsers method, I can see the filter method inside its proto...
var userService = {
currentFilter: "active",
users: [
{ name: "Alex", status: "active" },
{ name: "Nick", status: "deleted" }
],
getFilteredUsers: function() {
// console.log(this.users);
return this.users.filter(function(user) {
return user.status === this.currentFilter;
});
}
};
console.log(userService.getFilteredUsers()); // []
It is because of value of
this
in filter callback. Use arrow function to get correct value for this
var userService = {
currentFilter: "active",
users: [
{ name: "Alex", status: "active" },
{ name: "Nick", status: "deleted" }
],
getFilteredUsers: function() {
// console.log(this.users);
return this.users.filter((user)=> {
return user.status === this.currentFilter;
});
}
};
console.log(userService.getFilteredUsers()); // []
The problem is with the scope of this object. It changes inside the callback function of filter(). There are two ways you can try:
Create a new filter variable in your function before filter callback function, something like:
var userService = {
currentFilter: "active",
users: [{
name: "Alex",
status: "active"
},
{
name: "Nick",
status: "deleted"
}
],
getFilteredUsers: function() {
const currentStatus = this.currentFilter;
return this.users.filter(function(user) {
return user.status === currentStatus;
});
}
};
console.log(userService.getFilteredUsers()); //[ { name: 'Alex', status: 'active' } ]
Use es6 arrow function:
var userService = {
currentFilter: "active",
users: [{
name: "Alex",
status: "active"
},
{
name: "Nick",
status: "deleted"
}
],
getFilteredUsers: function() {
return this.users.filter(({
status
}) => status === this.currentFilter);
}
};
console.log(userService.getFilteredUsers()); // [ { name: 'Alex', status: 'active' } ]
Hope this helps :)

Recursive Function Causing Overflow

I am trying to write a recursive function in JavaScript. My function needs to search a tree of items. I have created a JSFiddle. When I run the JavaScript in Chrome, I get an error that says:
RangeError: Maximum call stack size exceeded
I assume this means that I'm not returning my value at the correct time. However, I continue to review the function and it looks correct to me. What am I doing wrong?
var sitemap = [
{
name: 'dashboards', children: [
{ name: 'dashboard 1', route: '/dashboards/dashboard1', html: '' }
]
},
{
name: 'objects', children: [
{ name: 'players', route: '/objects/players', html: '/objects/players.html' },
{ name: 'teams', route: '/objects/teams', html: '/objects/teams.html' },
{ name: 'coaches', route: '/objects/coaches', html: '/objects/coaches.html' },
{ name: 'cities', children: [
{ name: 'Chicago', route: '/cities/chicago',
html: '/objects/cities/chicago.html' },
{ name: 'Philadelphia', route: '/cities/philadelphia', html: '/objects/cities/philadelphia.html' }
]},
]
}
];
var getFromSitemap = function (path, entries) {
var sitemapItem = null;
if (entries) {
angular.forEach(sitemap, function (entry, key) {
if (entry.hasOwnProperty("children")) {
sitemapItem = getFromSitemap(path, entry.children);
} else if (entry.route === path) {
sitemapItem = entry;
}
});
}
return sitemapItem;
};
var getItem = function() {
var item = getFromSitemap('/cities/chicago', sitemap);
console.log(item);
}
Thank you!
You are calling foreach on the same object (sitemap) everytime:
angular.forEach(sitemap, function ...
It seems like you want to be calling it on entries recursively
angular.forEach(entries, function ....

Categories