I made a component like below in Vuejs.
But my goal is I want to get the value inside of filterdShoes of watch.
data():{
coor: [
{ "name": '',
"shoes": '' },
{ "name": '',
"shoes": '' }
]
},
computed {
filteredAny(){
return this.coor.filter(it=>['shoes','name'].includes(it));
},
filteredShoes(){
return this.coor.filter(it=>it === 'shoes');
},
filteredName(){
return this.coor.filter(it=>it === 'name');
}
}
watch {
filteredShoes(){
console.log('The shoes are changed');
}
}
So I tried like below.But it says val is undefined.
I hope that 'val' is defined as 'coor' of data.
How can I fix this code? Thank you so much for reading this.
watch {
filteredShoes(val){
for(let i=0; i < val.length; i+=1){}
}
}
Since this.coor is an array of objects, it will be an object. Thus it != 'shoes', and your filter will return an empty array.
Assuming you are using computed filteredShoes() like this:
<div v-for="shoe in filteredShoes"> ... </div>
Then you can just use the computed property, no need for the watcher. Everytime elements are added to/removed from the array, the computed prop will run. The computed property will not run if the properties of an object in the array are changed.
Also, I'm not quite sure why your this.coor has such a structure, so I'm using this:
coor: [
{ "name": 'Model 1', "shoes": 'Nike' },
{ "name": 'Model 2', "shoes": 'Reebok' }
]
...
computed {
filteredShoes(){
let shoes = this.coor.filter(item => item.shoes === 'Nike');
for(let i = 0; i < shoes.length; i++){ ... } // assuming you're modifying each object here
return shoes; // return an array to be looped in HTML
},
}
If you're trying to filter by type, I would recommend changing your coor to the following structure:
coor: [
{ "name": 'Model 1', "type": 'shoe' },
{ "name": 'Model 2', "type": 'shoe' }
]
...
computed {
filteredShoes(){
let shoes = this.coor.filter(item => item.type === 'shoe');
...
return shoes; // return an array to be looped in HTML
},
}
If you need to deep computed in array, as bellow
computed: {
computedArray: {
cache: false,
get() {
return this.sourceArray;
},
},
},
Related
I already found out, how to get the last elements of a deep nested object.
See here for working example: How to get the last children in a deeply nested array with objects
Now I dont want to log the names like in the example with console.log(subObj.name), instead I want to save them in an array, which shouldnt be global. I just want a function return this array.
Is this somehow possible without declaring a global array for this ?
This is my code:
function childrenNames (obj) {
var lastChildren = [];
obj.forEach((subObj) => {
if (subObj.hasOwnProperty('specification') && subObj.specification instanceof Array && subObj.specification.length > 0) {
childrenNames(subObj.specification);
} else {
if (subObj.hasOwnProperty('name')) {
lastChildren.push(subObj.name)
}
}
})
console.log(lastChildren);
return lastChildren
}
But its just returning 4 different arrays instead of 1 containing all last children.
I am not sure whether this is a valid answer and I do not understand it but I am leaving it for now because it does appear, superficially at least, to answer the question. It does not require a global array to be declared as far as I can tell?
var obj = [
{
name: 'something',
children: [
{
name: 'something',
children: [
{
name: 'no child'
},
{
name: 'something empty',
children: [ ]
}
]
}
]
},
{
name: 'something',
children: [
{
name: 'something',
children: [
{
name: 'no child'
}
]
}
]
},
{
name: "children isn't an array",
children: 42
}
]
function childrenNames (obj) {
var lastChildren = [];
obj.forEach((subObj) => {
if (subObj.hasOwnProperty('specification') && subObj.specification instanceof Array && subObj.specification.length > 0) {
childrenNames(subObj.specification);
} else {
if (subObj.hasOwnProperty('name')) {
lastChildren.push(subObj.name)
}
}
})
// console.log(lastChildren);
return lastChildren
}
const res = childrenNames(obj);
console.log('res', res);
I have a nested JSON that I'd like to search through using lodash. How can I get the root object from data if a search term I'm looking for is within certain keys, and with one of the keys being dynamic?
For example, if I have:
"data": [
{
"name": "Bob's concourse"
"activities": [
{
"day": "Monday",
"routines":
{
"Biking":
{
"details": "won 3 trophies"
"type": "road"
},
"Kayaking":
{
"details": "participated in 3 races"
"type": "rhythm"
}
}
}
}
]
},
{..other_data_etc...},
]
activities can be []; it's not guaranteed that it contains any data.
routines keys are dynamic. ie, Biking, Kayaking are dynamic strings. It can be anything.
If I want to search for an races (case insensitive), I want to search specifically in:
data.name
data.activities.routines.* (the dynamic keys)
data.activities.routines.*.details
If any one of those matches, then it will return the root object: { "name": "Bob", ..... }
I was able to get the name to return:
function searchText(collection, searchterm) {
return _.filter(collection, function(o) {
return _.includes(o.name.toLowerCase(), searchterm)
} );
};
But I'm still new to lodash, and I was unable to get any of the nested searches to return correctly, especially with the dynamic keys part.
Could anyone help explain a solution?
Expanding on your existing attempt with lodash:
const obj = {
data: [{
name: 'Bob\'s concourse',
activities: [{
day: 'Monday',
routines: {
Biking: {
details: 'won 3 trophies',
type: 'road'
},
Kayaking: {
details: 'participated in 3 races',
type: 'rhythm'
}
}
}]
}]
};
function search(str, data) {
const searchStr = str.toLowerCase();
// Only return the entries that contain a matched value
return _.filter(data, (datum) => {
// Check if name matches
return _.includes(datum.name, searchStr)
|| _.some(datum.activities, (activity) => {
return _.entries(activity.routines).some(([routine, {details}]) => {
// Check if dynamic routine matches or details
return _.includes(routine, searchStr) || _.includes(details, searchStr);
});
});
});
}
console.log(search('foobar', obj.data));
console.log(search('races', obj.data));
<script src="https://cdn.jsdelivr.net/npm/lodash#4.17.10/lodash.min.js"></script>
You can also accomplish this with plain JavaScript. Using some newish syntax such as destructuring assignment and newish native methods such as Object.entries essentially follows the same pattern as using lodash:
const obj = {
data: [{
name: 'Bob\'s concourse',
activities: [{
day: 'Monday',
routines: {
Biking: {
details: 'won 3 trophies',
type: 'road'
},
Kayaking: {
details: 'participated in 3 races',
type: 'rhythm'
}
}
}]
}]
};
function search(str, data) {
const regex = RegExp(str, 'i');
// Only return the entries that contain a matched value
return data.filter((datum) => {
// Check if name matches
return regex.test(datum.name)
|| datum.activities.some((activity) => {
return Object.entries(activity.routines).some(([routine, {details}]) => {
// Check if dynamic routine matches or details
return regex.test(routine) || regex.test(details);
});
});
});
}
console.log(search('foobar', obj.data));
console.log(search('races', obj.data));
I have an array of objects and I want to return array containing only the names of the happy people and return all names when everybody is happy.
The thing I fail to get is to get all names when everybody is happy. Any ideas?
EDIT: This is the object.
[
{ name: 'Don', disposition: 'Happy' },
{ name: 'Trev', disposition: 'Happy' },
]
function findHappyPeople(people) {
var happyPeople = Object.keys(people).filter(function(key) {
if(people[key] === 'Happy') {
return people[name]
}
});
return happyPeople;
}
You have an array of objects, so Object.keys() wouldn't be needed here.
You can use a .map() operation after the filter to end up with an array of names.
Your people[name] code isn't going to work because you have no name variable, except the global one if you're in a browser, which isn't what you want. Your data has a .name property, so use that.
const data = [
{ name: 'Don', disposition: 'Happy' },
{ name: 'Trev', disposition: 'Happy' },
]
console.log(findHappyPeople(data));
function findHappyPeople(people) {
return people
.filter(function(p) { return p.disposition === "Happy" })
.map(function(p) { return p.name });
}
Or with arrow function syntax:
const data = [
{ name: 'Don', disposition: 'Happy' },
{ name: 'Trev', disposition: 'Happy' },
]
console.log(findHappyPeople(data));
function findHappyPeople(people) {
return people
.filter(p => p.disposition === "Happy")
.map(p => p.name);
}
I have few JS objects. They can have any structure:
{
name: "first",
_ref_id: 1234,
spec: {
_ref_id: 2345,
data: "lots of data"
}
}
{
name: 'second',
_ref_id: 5678,
container: {
_ref_id: 6789,
children: [
{_ref_id: 3214, name: 'Bob'}
{_ref_id: 1111, name: 'Mark'}
{_ref_id: 2222, name: 'Frank'}
]
}
}
Problem:
I need to make a copies of this object but with a different _ref_ids.
Creation of the 'first' object my look like this:
first = {
name: "first",
_ref_id: uuid.v4(),
spec: {
_ref_id: uuid.v4(),
data: "lots of data"
}
}
So I know the structure of the object when I am creating it but further down the chain in a place where I am trying to make a copy of this object I don't have access and I don't know what is the structure of this object all I have is the object it self. So after coping 'first' I would like to have:
{
name: "first",
_ref_id: 8888,
spec: {
_ref_id: 9999,
data: "lots of data"
}
}
I tried instead of defining the _ref_id a simple value a sort of memoized function during the object creation:
refId(memoized = true){
var memo = {}
return () => {
if(!memoized) memo = {}
if(memo['_ref_id'])
return memo._ref_id
else {
memo._ref_id = uuid.v4()
return memo._ref_id
}
}
}
So I can create it:
first = {
name: "first",
_ref_id: refId(),
spec: {
_ref_id: refId(),
data: "lots of data"
}
}
And change the first._ref_id to first._ref_id() whenever I am trying to access the value of it.
But I have no idea how to reset the memoized variable from inside the coping function or if this is even possible?
Have anyone had similar problem? Maybe there is a different way to solve it?
PS:
I am using lodash and immutable.js in this project but I haven't found any helper functions for this particular task.
Inspired from Most elegant way to clone a JS object, with a check for _ref_id fields :
function deepCopyWithNewRefId(obj) {
if (null == obj || "object" != typeof obj) return obj;
var copy = obj.constructor();
for (var attr in obj) {
if (obj.hasOwnProperty(attr)) {
if (attr == "_ref_id") {
copy[attr] = uuid.v4();
} else {
copy[attr] = deepCopyWithNewRefId(obj[attr]);
}
}
}
return copy;
}
A log of its use :
var uuid = { v4 : function(){ return Math.random()} };
var first = {
name: "first",
_ref_id: uuid.v4(),
spec: {
_ref_id: uuid.v4(),
data: "lots of data"
}
};
console.log(first._ref_id);
console.log(first.spec._ref_id);
var second = deepCopyWithNewRefId(first);
console.log(second);
console.log(second._ref_id);
console.log(second.spec._ref_id);
// the printed values are not the same. The rest of the object is
I have the following 2 arrays here:
> chNameArr
[ 'chanel1',
'chanel2',
'chanel3',
'chanel4',
'chanel5',
'chanel6',
'chanel7' ]
and here:
> a
[ 'channelName'
'status',
'connections',
'socketIds',
'lastRun',
'numberOfRuns',
'timeout' ]
what I am trying to achieve is the following objects per channel in an array where channelName from a get the value from chNameArr but the rest of 'a' gets an empty string
file=[{"channelName":"chanel1","status":"", "connections":"", "socketIds":"", "lastRun":"", "numberOfRuns":"", "timeout":""},
.
.
.
{"channelName":"chanel7","status":"", "connections":"", "socketIds":"", "lastRun":"", "numberOfRuns":"", "timeout":""}]
this is my attempt
> chNameArr.map(function(d){return {channelName:d}})
[ { channelName: 'chanel1' },
{ channelName: 'chanel2' },
{ channelName: 'chanel3' },
{ channelName: 'chanel4' },
{ channelName: 'chanel5' },
{ channelName: 'chanel6' },
{ channelName: 'chanel7' } ]
chNameArr.map(function(d) {
result = {};
result[a[0]] = d;
for (var i=1; i<a.length; i++) {
result[a[i]] = "";
}
return result;
})
There is no one-liner to solve this problem in general, although if you don't actually need to use the array a you could manually construct {channelName:d, status: "", ...} in your original map.