How to write filter condition for specific object key? - ecmascript-6

I have an object:
const list = {
apples: '2',
grapes: '1',
almonds: 'allergic',
bags: '',
}
What I want to is if list.bags === '' exclude it from object, so that final result will be:
const list = {
apples: '2',
grapes: '1',
almonds: 'allergic',
}
I tried filtering it out, but it always removes bags
const newList = Object.fromEntries(Object.entries(list).filter(
([key, v]) => key !== 'bags' && v !== '',
),
);
How can I write this type of condition for filter?

If you just want to remove a single property, I'd use Object.assign (or spread properties) to clone the object and just delete that property if necessary:
const newList = {...list};
if (newList.bags === '') {
delete newList.bags;
}

Related

Compare two JSON objects in Angular

I want to check if two JSON objects are same in Typescript(Angular), ignoring some key value pairs which may be optional.
obj1 = {name: 'Anna', password: 'test123', status: 'active'}
obj2 = {name: 'Anna', password: 'test123'}
Technically 'status' is optional, so I want the comparison to return true only considering first two properties. How to check this?
You could:
Get common keys of obj1 and obj2 (with a set)
Compare each key one-to-one
function compare(obj1, obj2) {
const commonKeys = [...new Set([...Object.keys(obj1), ...Object.keys(obj2)])];
for (const key of commonKeys) {
if (obj1[key] !== obj2[key]) {
return false;
}
}
return true;
}
try this
Boolean theSame= obj1.name==obj2.name && obj1.password==obj2.password;

react axios post generates json in array format. How to convert this to "name":"value" type format

const submitService = {
serviceType: this.state.serviceType,
dateOfService: this.state.dateOfService,
vehicleId: this.state.vehicleId,
orderNum: this.state.orderNum,
driverId: this.state.driverId,
vendorName: this.state.vendorName,
issueId: this.state.issueId
};
axios.post("http://localhost:8072/TruckyServiceMicroService/admin/services/saveService/", submitService)
.then(response => {
if (response.data != null) {
this.setState(this.initialState);
alert("Service Created Successfully");
}
});
This is the const forming the json and the post request sent using the const. On sending the post request through axios, it adds square braces in the json
initialState = {
serviceType: [], vehicleId: '', dateOfService: '', orderNum: '', driverId: '', vendorName: '', issueId: ''
}
This is the state
if you want a quick fix, change:
const submitService = {
serviceType: this.state.serviceType,
dateOfService: this.state.dateOfService,
vehicleId: this.state.vehicleId,
orderNum: this.state.orderNum,
driverId: this.state.driverId,
vendorName: this.state.vendorName,
issueId: this.state.issueId
};
to:
const keys = ["serviceType","dateOfService","vehicleId","orderNum","driverId","vendorName","issueId"]
const submitService = Object.entries(this.state).reduce((res, ([key, val])) => {
if(keys.includes(key))
res[key] = Array.isArray(val)?val[0]:val
return res
}, {})
this basically creates the payload with keys and values pairs of state but if the value is array type it just uses the first index of it.

Derive HTML based on value of nested array

Looking to group and create relevant html based from an object.
const _ = require('lodash');
const items = [
{
value: 'fruit',
label: 'apple',
},
{
value: 'Mango',
label: 'Mango',
groupBy: 'fruit'
},
{
value: 'Orange',
label: 'Orange',
groupBy: 'fruit'
},
// Will need to group all above by fruit, similarly
{
value: 'vegetable',
label: 'artichoke',
},
{
value: 'aubergine',
label: 'aubergine',
groupBy: 'vegetable'
}
];
_renderItems = () => {
const itemsList = _.chain(items)
.map(item => (
this._renderItem(item)
))
.value()
return '<div class="item-container">'+ itemsList+'</div>'
}
_renderItem = (item = {}) => {
console.log(item)
}
_renderItems()
/*
desired output
<div class="fruit">
Label:Apple
Label:Mango
Label:Orange
</div>
<div class="vegetable">
label:artichoke
label:aubergine
label:broccoli
</div>
*/
Code sample here of progress here https://repl.it/repls/ElectronicUsableTheories . In general, I have trouble adding a wrapping div based on grouped value.
So all fruit should be grouped first key will not have groupBy key but its value will be the key of all next items which needs to be grouped
Group the items by the groupBy or by value if groupBy doesn't exist. Then you can map the groups. The 2nd parameter that map passes to the callback is the key (the groupBy value), that you can use as the class. It addition map the items, take the label, and format. Combine the group's string, and the itemList's string, and return.
const items = [{"value":"fruit","label":"apple"},{"value":"Mango","label":"Mango","groupBy":"fruit"},{"value":"Orange","label":"Orange","groupBy":"fruit"},{"value":"vegetable","label":"artichoke"},{"value":"aubergine","label":"aubergine","groupBy":"vegetable"}];
const _renderItem = ({ label } = {}) => `label: ${label}\n`;
const _renderItems = () =>
_(items)
.groupBy(o => o.groupBy || o.value) // if not groupBy use value
.map((group, key) => {
const itemsList = group.map(_renderItem).join('');
return `<div class="item-container ${key}">\n${itemsList}</div>`;
})
.join('\n');
const result = _renderItems();
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>

Conditional Anonymous type

I am working on Web API and using Anonymous type to make JSON as output. I am stuck in the following scenario:
If there is no record(VALUE) available then i don't want to show that KEY. Meaning, Key should only appear when and only when there is value.
Below is the JSON object i am creating -
"TU": [
{
"BLOCK": [
[
"00:00",
"00:59"
]
]
}
],
"WE": [],// empty
"TH": [],// empty
"FR": [],// empty
"SA": [] // empty
Here for Tuesday we do have records and hence its showing but later for WE,TH,FR,SA there are not records and hence i don't want to show them so my result will be MO/TU only.
I am using below code:
var result = new
{
CustomerID = custId,
DeviceID = dId,
Kind = kind,
WebList = filter.Select(filt => new
{
URL = filt.FilterName,
TimeBlockFlag = new ChicoHelper().GetFlag(browserlimit, filt.ID, filt.FilterOptionID, KindId),
DAILY = browserlimit.Where(xx => xx.FilterID == filt.ID && xx.OptionTypeID == daily).Select(xx => xx.BlockTimeLimit).SingleOrDefault(),
WEEKLY = browserlimit.Where(xx => xx.FilterID == filt.ID && xx.OptionTypeID == weekly).Select(xx => xx.BlockTimeLimit).SingleOrDefault(),
MONTHLY = browserlimit.Where(xx => xx.FilterID == filt.ID && xx.OptionTypeID == monthly).Select(xx => xx.BlockTimeLimit).SingleOrDefault(),
HASVALUES = browserlimit.Where(xx => xx.FilterID == filt.ID).Count() > 0 ? 1 : 0,
BLOCKTYPE = new ChicoHelper().GetBlockType(browserlimit,filt.ID,filt.FilterOptionID,KindId),
SU = blockedlimit.Where(x => x.OptionID == sunday && x.FilterID == filt.ID).GroupBy(x => new { x.BlockDay })
.Select(x => new
{
BLOCK = x.Select(y =>
new[] { y.BlockStartTime.MakeFormatedTime(), y.BlockEndTime.MakeFormatedTime() }
)
}),
MO = blockedlimit.Where(x => x.OptionID == monday && x.FilterID == filt.ID).GroupBy(x => new { x.BlockDay })
.Select(x => new
{
BLOCK = x.Select(y =>
new[] { y.BlockStartTime.MakeFormatedTime(), y.BlockEndTime.MakeFormatedTime() }
)
}),
TU = blockedlimit.Where(x => x.OptionID == tuesday && x.FilterID == filt.ID).GroupBy(x => new { x.BlockDay })
.Select(x => new
{
BLOCK = x.Select(y =>
new[] { y.BlockStartTime.MakeFormatedTime(), y.BlockEndTime.MakeFormatedTime() }
)
}),
// if i can put some condition like if there is not record for WE then don't show it.
WE = blockedlimit.Where(x => x.OptionID == wednesday && x.FilterID == filt.ID).GroupBy(x => new { x.BlockDay })
.Select(x => new
{
BLOCK = x.Select(y =>
new[] { y.BlockStartTime.MakeFormatedTime(), y.BlockEndTime.MakeFormatedTime() }
)
}),
The main reason for doing this is to reduce the JSON size which will be consumed by Mobile Devices.
Please help me with this.
The properties of an anonymous type are fixed at compile-time - you can't make them conditional. However, some other approaches you might want to think about:
You could investigate whether a property is still included in the JSON representation if its value is null. If it's not, you could add an extension method NullIfEmpty() which returns null if its input is empty.
You could try performing the JSON conversion from the anonymous type in code first, then delete any properties with an empty set of results, then just return that JSON object from the API. (I don't know Web API myself, but there must be a way of saying "Here's a JSON object - ask it for its string representation" rather than using an anonymous type.)
You could ditch the anonymous type entirely, and build up the JSON representation programmatically, setting just the properties you want.
In any approach, I would strongly advise you to extract a common method to come up with the property value based on a day of the week, so you can have:
...
SU = blockedLimit.GetDayBlocks(sunday),
MO = blockedLimit.GetDayBlocks(monday),
TU = blockedLimit.GetDayBlocks(tuesday),
...
There's no reason to have all that code repeated 7 times. In fact, I'd probably refactor that part before doing anything else - it'll make it easier to experiment.

Linq - pulling a value from a null query result

I have a linq query that needs to pull a date column out of a row. The expression currently looks like this
myObject.OrderByDescending(s=> s.MyDate).Where(s => s.CRAStatus.Description == "CheckedOut").FirstOrDefault().MyDate)
The problem is that if there are no rows that are "CheckedOut", the query will return a null and attempting to get "MyDate" will throw an exception. We have some verbose solutions, like:
.ForMember(dest => dest.CheckOutDate, opt => opt.MapFrom(src => {
var temp = src.CRAStatusChangeEvents.OrderByDescending(s=> s.MyDate).Where(s => s.CRAStatus.Description == "CheckedOut").FirstOrDefault();
return temp == null ? temp.MyDate : null;
}));
But it would be nice to find something a little more concise. Any Ideas?
Why not
myObject.OrderByDescending(s=> s.MyDate)
.Where(s => s.CRAStatus.Description == "CheckedOut")
.Select(s => s.MyDate as DateTime?)
.FirstOrDefault();
or
myObject.Where(s => s.CRAStatus.Description == "CheckedOut")
.Max(s => s.MyDate as DateTime?);
One option is to set the default if empty to an "empty" instance (think of string.Empty--its a known instance that represents an empty result):
var date = (myObject
.OrderByDescending(s=> s.MyDate)
.Where(s => s.CRAStatus.Description == "CheckedOut")
.DefaultIfEmpty(MyObject.Empty)
.FirstOrDefault()).MyDate;
Here's a snippet that shows how it works:
var strings = new string[]{"one", "two"};
var length =
(strings.Where(s=>s.Length > 5)
.DefaultIfEmpty(string.Empty)
.FirstOrDefault()).Length;
run that and length is 0. Remove the DefaultIfEmpty line and you get a NRE.
var checkedOut = myObject.Where(s => s.CRAStatus.Description == "CheckedOut");
if (checkedOut.Count() > 0) {
var result = checkedOut.Max(s=> s.MyDate).MyDate;
}
How about an extension method?
static class MyObjectEnumerableExtensions
{
public static TMember GetMemberOfFirstOrDefault<TMember>(this IEnumerable<MyObject> items, Func<MyObject, TMember> getMember)
{
MyObject first = items.FirstOrDefault();
if (first != null)
{
return getMember(first);
}
else
{
return default(TMember);
}
}
}
Sample usage:
List<MyObject> objects = new List<MyObject>();
objects.Add(new MyObject { MyDate = DateTime.MinValue });
var filteredObjects = from s in objects where s.MyDate > DateTime.MinValue select s;
DateTime date = filteredObjects.GetMemberOfFirstOrDefault(s => s.MyDate);
Console.WriteLine(date);