javascript array is coming as empty - javascript

I need to return whole object where linkable is true. I think I am doing it in a right way but array is coming as empty. this.releaseDescriptionDatesArray is empty even I am pushing the object.
for (const item of this.datesArray) {
for (const attribute in item) {
if (attribute === 'linkable' && item[attribute] === 'true') {
this.releaseDescriptionDatesArray.push(item); // data is here
console.log( this.releaseDescriptionDatesArray, "datesArr");data is not coming here
}
}
}
console.log( this.releaseDescriptionDatesArray, "datesArr"); data is not here
}
Sample data
datesArray = [ {
"type": "disasterRecovery",
"date": "2019-07-28",
"releaseWindow": {
"start": null,
"end": null
},
"description": "Disaster Recovery",
"linkable": true
},
{
"type": "nooutageRelease",
"date": "2019-08-03",
"releaseWindow": {
"start": "2019-08-04T00:00:00",
"end": "2019-08-04T23:59:59"
},
"description": "Infrastructure Release (No Outage)",
"linkable": true
}]

If you know there is going to be an attribute linkable in every item, you don't need to parse every attribute of the items and check if one of them is linkable then check if it's true.
Also, since your are stritcly comparing your values (===), 'true' !== true, that's probably why your array is empty. With that in mind, you could simply use the filter function on your array with a callback that check if linkable is true. It will simplify a lot your code.
let datesArray = [{
"type": "disasterRecovery",
"date": "2019-07-28",
"releaseWindow": {
"start": null,
"end": null
},
"description": "Disaster Recovery",
"linkable": true
},
// i've change the value of this item for testing purpose
{
"type": "nooutageRelease",
"date": "2019-08-03",
"releaseWindow": {
"start": "2019-08-04T00:00:00",
"end": "2019-08-04T23:59:59"
},
"description": "Infrastructure Release (No Outage)",
"linkable": false
}
];
// this callback will assert that date.linkable is not null,
// and that it's value is true.
// if the attribute was null ( or undefined ), it would be evaluated as "false-y" and therefore
// not be included in the final array.
// the last part also check that the value is an actual boolean ( see Lain's comment )
let output = datesArray.filter((date) => date.linkable && date.linkable === true);
console.log(output)

item[attribute] === true
You need to use boolean true, not string 'true'
for (var item of datesArray) {
for (var attribute in item) {
if (attribute === 'linkable' && item[attribute] === true) {
releaseDescriptionDatesArray.push(item); // data is here
console.log(attribute)
console.log(this.releaseDescriptionDatesArray, "datesArr");
}
}
}

Related

Loop through array of nested objects to check empty string es6

I have an array of nested objects:
const array =[
{
"id": 1,
"time": {
"timezone": "2021-09-22T05:36:22.484Z"
"city": "Perth"
"country:: "Australia
"date": "2021/10/10"
}
},
{
​"id": 2,
​"time": {
"timezone": ​"2021-10-22T03:25:26.484Z"
"city": ""
"country: "Americas"
"date": "2021/10/10"
}
},
{
​"id": 3,
​"time": {
"timezone": ​"2021-09-27T02:43:26.564Z"
"city": ""
"country: ""
"date": "2021/10/10"
}
}];
I want to check each value in the time object to see if there exists an empty string without having to have multiple || statements.
What I have tried using lodash:
if(array.find((k)=> _.isEmpty(k.timezone)) || array.find((k)=> _.isEmpty(k.city)) || array.find((k)=> _.isEmpty(k.country)) || array.find((k)=> _.isEmpty(k.date))) {
//do something
} else {
//do something else
}
This seems to do the trick but trying to find a succinct and cleaner way to do this as there could be more values in the time object, preferably in es6.
Check if .some of the Object.values of any of the time subobjects includes the empty string.
if (array.some(
k => Object.values(k.time).includes('')
)) {
// do something
} else {
// do something else
}

How to save initial statement of object?

I have object of type:
export interface IGroupLanguage {
name: string;
languages?: Language[];
}
let data = [ { "name": "Automation", "languages": [ { "Name": "English", "Lcid": 1, "RightToLeft": true, "Code": "EN", "Mapped": true } ] }, { "name": "Monitors", "languages": [ { "Name": "Russian", "Lcid": 2, "RightToLeft": true, "Code": "RU", "Mapped": true } ] } ];
Then I tried to filter object and return a new object:
this.filteredObject = [...this.groups];
this.filteredObject.map(item => {
item.languages = item.languages.filter(
lg =>
lg.Name.toLocaleLowerCase().indexOf(searchQuery) != -1 ||
lg.Code.toLocaleLowerCase().indexOf(searchQuery) != -1
);
});
Problem is that initial object this.groups is changed also. How to save initial statement of object?
In result I need to have not modified object this.groups and filtered object this.filteredObject.
I know problem because JS copy objects by reference, but I dont know how to solve it.
Full code is:
search(searchQuery: string) {
this.filteredObject = [...this.groups];
this.filteredObject.map(item => {
let tempLang = [...item.languages];
item.languages = tempLang.filter(
lg =>
lg.Name.toLocaleLowerCase().indexOf(searchQuery) != -1 ||
lg.Code.toLocaleLowerCase().indexOf(searchQuery) != -1
);
});
console.log(this.groups);
}
ngOnInit() {
this.filteredObject = [...this.groups];
}
As result initial object console.log(this.groups); is also was modified
Because you have deep copied parent array of data not nested one, can you give it a try to below way -
this.filteredObject = [...this.groups];
this.filteredObject.map(item => {
let tempLang = [...item.languages];
item.languages = tempLang.filter(lg =>
lg.Name.toLocaleLowerCase().indexOf(searchQuery) != -1 ||
lg.Code.toLocaleLowerCase().indexOf(searchQuery) != -1
);
});
Spread syntax performs a shallow copy of the object.
MDN documentation on copying an array with spread syntax:
Spread syntax effectively goes one level deep while copying an array. Therefore, it may be unsuitable for copying multidimensional arrays as the following example shows (it's the same with Object.assign() and spread syntax).
This means that if there are any objects at the top level, their reference will be copied. That is the reason for this problem.
You can use JSON.parse(JSON.stringify()) to deep clone an object. But there will be data loss if the object has Dates, functions, undefined, Infinity, or other complex types. More info in this answer.
Also, when you are not returning any values use forEach() instead of a map().
this.filteredObject = JSON.parse(JSON.stringify(this.groups));
filteredObject.forEach(item => {
item.languages = item.languages.filter(lg =>
lg.Name.toLocaleLowerCase().indexOf(searchQuery.toLocaleLowerCase()) != -1 ||
lg.Code.toLocaleLowerCase().indexOf(searchQuery.toLocaleLowerCase()) != -1
);
});
This works for properties containing objects at any nested level.
Live Example:
let data = [ { "name": "Automation", "languages": [ { "Name": "English", "Lcid": 1, "RightToLeft": true, "Code": "EN", "Mapped": true } ] }, { "name": "Monitors", "languages": [ { "Name": "Russian", "Lcid": 2, "RightToLeft": true, "Code": "RU", "Mapped": true } ] } ];
let searchQuery = "English";
let filteredObject = JSON.parse(JSON.stringify(data));
filteredObject.forEach(item => {
item.languages = item.languages.filter(lg =>
lg.Name.toLocaleLowerCase().indexOf(searchQuery.toLocaleLowerCase()) != -1 ||
lg.Code.toLocaleLowerCase().indexOf(searchQuery.toLocaleLowerCase()) != -1
);
});
console.log(data);
console.log(filteredObject);
You need to deep clone your object. If you know the structure of your object, you can create a custom deep clone function with recursiveness. Otherwise, you can use the library lodash

Check array of objects in lodash for property value

Given the following
var content = [{
"set_archived": false,
"something": [{
"id": "aa7bb3db-19a2-4ef6-5944-892edaaf53c3",
"modified": "2016-12-01T18:23:29.743333Z",
"created": "2016-12-01T18:23:29.743333Z",
"archived": false
}]
},
{
"set_archived": true,
"something": [{
"id": "aa7bb3db-19a2-4ef6-5944-892edaaf53c3",
"modified": "2017-01-30T19:42:29.743333Z",
"created": "2017-01-30T19:42:29.743333Z",
"archived": false
}]
}
];
Using Lodash, how would I determine if either set_archived or something.archived in the array of objects is equal to true?
So in this case, because the second object has set_is_archived that is true, then the expected response should be true. If all items are false in either object, then the response should be false.
Just use:
_.filter(content, o => o["set_archived"] || o.something[0].archived).length > 0;
or
_.some(content, o => o["set_archived"] || o.something[0].archived);
PlainJs:
content.some(o => o["set_archived"] || o.something[0].archived)
or
content.filter(o => o["set_archived"] || o.something[0].archived).length > 0;
You can just use some() in plain javascript.
var content = [{
"set_archived": false,
"something": [{
"id": "aa7bb3db-19a2-4ef6-5944-892edaaf53c3",
"modified": "2016-12-01T18:23:29.743333Z",
"created": "2016-12-01T18:23:29.743333Z",
"archived": false
}]
}, {
"set_archived": true,
"something": [{
"id": "aa7bb3db-19a2-4ef6-5944-892edaaf53c3",
"modified": "2017-01-30T19:42:29.743333Z",
"created": "2017-01-30T19:42:29.743333Z",
"archived": false
}]
}];
var result = content.some(function(e) {
return e.set_archived === true || e.something[0].archived === true
})
console.log(result)
Considering the same object as the one in the question, there are couple of ways to find the solution to your problem mate.
var flag = false;
flag = content.some(function(c){
if(c["set_archived"]){
return true;
}
});
console.log(flag)
or
var flag = false;
flag = content.some(function(c){
if(c["set_archived"] || c.something[0].archived){
return true;
}
});
console.log(flag)
The above snippet will result true if atleast one of the object of the array have ["set_archived"] property true and it will return false if all the objects of the array has ["set_archived"] as false. (I could have said vice-versa)
The some() method tests whether some element in the array passes the test implemented by the provided function.
The every() method tests whether all elements in the array pass the test implemented by the provided function.
If you are looking for a stricter way I recon you go ahead with every().
You don't need lodash for this. You can do this with pure JS, using filter:
content.filter(i => i.set_archived || i.something.archied)

Push Json filtered key values to nested ul with Javascript

I need help pushing the values from a filtered json, I need this generate a nested ul list, I can not modify the json format at this point, I you check the console.log you will see the values to create the list, at this point I can't figure how to complete the 'for loop' to render the html markup needed, any help will be appreciated, this is the jsfiddle http://jsfiddle.net/43jh9hzz/, and if you check the console log you will see the values.
This is the Js:
var json='';
var property_set = new Set();
function iterate(obj, stack) {
json="<ul>";
for (var property in obj) {
if (obj.hasOwnProperty(property)) {
if (typeof obj[property] == "object") {
iterate(obj[property], stack + '.' + property);
}
else {
// console.log(property);
property_set.add(property);
json+="<li>";
if(typeof obj[property] !== "number") {
json+="<li>"+obj[property]+"</li>";
console.log(obj[property]);
}
}
} json += "</li>";
}
}
var listEl = document.getElementById('output');
iterate(jsonObj)
And this is the json format:
var jsonObj =
{
"level_1": [
{
"level_1_name": "CiscoSingaporeEBC",
"level_2": [
{
"level_2_name": "Khoo Tech Puat",
"level_2_id": 2222,
"level_3": [
{
"name": "Boon Leong Ong",
"id": 6919
},
{
"name": "Kiat Ho",
"id": 6917
},
{
"name": "Overall Experience",
"id": 6918
}
]
}
]
},
{
"level_1_name": "CiscoLondonEBC",
"level_2": [
{
"level_2_name": "Bernard Mathews Ltd.",
"level_2_id": 2367,
"level_3": [
{
"name": "Barry Pascolutti",
"id": 7193
},
{
"name": "Kathrine Eilersten",
"id": 7194
},
{
"name": "Martin Rowley",
"id": 7189
}
]
},
{
"level_2_name": "FNHW Day 1",
"level_2_id": 5678,
"level_3": [
{
"name": "Jurgen Gosch",
"id": 7834
},
{
"name": "Overall Experience",
"id": 7835
}
]
},
{
"level_2_name": "Groupe Steria Day 1",
"level_2_id": 2789,
"level_3": [
{
"name": "Adam Philpott",
"id": 7919
},
{
"name": "Pranav Kumar",
"id": 7921
},
{
"name": "Steve Simlo",
"id": 7928
}
]
}
]
}
]
};
enter code here
I'm not sure if I am interpretting your request correctly, but I think this is what you want: http://jsfiddle.net/mooreinteractive/43jh9hzz/1/
Basically, you are calling the iterate function to run, but then that's it. The function actually needs to also return the value it generates.
I've added to the end of the function, after the for loop completes:
return json;
Do now the function returns the value it generated, but there are some other issues too. When you recursively call the iterate function again inside the iterate function, you actually want to add what it returns to the current json string housing all of your returned value.
So on that line I changed it from:
iterate(obj[property], stack + '.' + property);
to
json += iterate(obj[property], stack + '.' + property);
Now that other value will come back as well inside the main list you were creating in the first run of the function. Ok so that's pretty close, but one more small thing. I think when you added additional surrounding LI, you actually wanted to do an UL. I changed those to ULs and now I think the result is like a UL/LI list representing the text parts of the JSON object.
Again, that may not be exactly what you were after, but I think the main take away is using the function to return the value, not just generate it, then do nothing with it.

Getting JSON object values by name

I have a valid JSON object like this:
{
"reasons": {
"options": [
{
"value": "",
"label": "Choose a reason",
"selected": true,
"requiresValidation": false
},
{
"value": "small",
"label": "Too little",
"selected": false,
"requiresValidation": false
},
{
"value": "big",
"label": "Too big",
"selected": false,
"requiresValidation": false
},
{
"value": "unsuitable",
"label": "I don't like it",
"selected": false,
"requiresValidation": true
},
{
"value": "other",
"label": "Other",
"selected": false,
"requiresValidation": true
}
]
}
}
and I have a variable which stores one value (e.g. unsuitable) of an option available in options.
How can I retrieve the value of requiresValidation field for the value stored in the variable without having to loop through all of the objects values inside options?
For instance, if the var content is other I'd like to access to requireValidation field of the object whose value is other (which is true). Is it possible?
Thank you.
You aren't really dealing with JSON here, you are dealing with a JS object. JSON is just a format for sending JS objects.
options is an array. The only way to access it is by index, which means you will have to do a search, one item at a time. There are functions, such as indexOf() which will return the first index of a value in an array, however, you have an array of objects, so that will not work in this case. (And internally, it is still doing a search).
function getReqVal(val) {
for (var item in mydata.reasons.options) {
if(item.value == val) {
return item.requiresValidation;
}
}
}
getReqVal("other");
The caveat is that this will return on the first one, so if you have more than one other, you won't get them.
If the options are indeed unique values, I would rearrange your object to be an associative array, with the keys being the "value" items, and the values being an object with the rest of the data:
{
"reasons": {
"options": {
"" : {
"label": "Seleziona una voce",
"selected": true,
"requiresValidation": false
},
"small" : {
"label": "Too little",
"selected": false,
"requiresValidation": false
},
"big" : {
"label": "Too big",
"selected": false,
"requiresValidation": false
},
"unsuitable" : {
"label": "I don't like it",
"selected": false,
"requiresValidation": true
},
"other" : {
"label": "Other",
"selected": false,
"requiresValidation": true
}
}
}
}
If you are (or could be) using underscore.js you could use the find method:
var item = _.find(myObj.reasons.options,
function(option){ return option.value == 'some value' });
Assuming you can't change the JSON structure itself (because perhaps you're getting it from an external source?), you can read it into a new object of your design per Marc B's suggestion. Ideally, this new object would let you index into your options array using the value key. Let's do that:
function MyOptions(optionsJSON) {
this.original_json = optionsJSON;
this.length = optionsJSON.reasons.options.length;
var original_options = optionsJSON.reasons.options;
for(var i = 0; i < this.length; i++)
this[original_options[i].value] = original_options[i];
}
var my_opts = new MyOptions(original_JSON);
var item_requiresValidation = my_opts["unsuitable"].requiresValidation;
console.log(item_requiresValidation); // should log "true"
The trade-off here is that your code will need to loop through the entire options array once, but after that you can index into the objects using the value key without searching. Validate with this jsfiddle.
You could use array filter. Some variation of this:
var $reasons = //Your JSON
function checkVal(element, index, array) {
return (element.value == "other");
}
var filtered = $reasons.reasons.options.filter(checkVal);
alert(filtered[0].requiresValidation);
Or jQuery grep might help you with the filter without looping: http://api.jquery.com/jQuery.grep/

Categories