How to delete elements of and array by two attributes in AngularJS? - javascript

I have an array of objects in AngularJS like this:
var example = [ {id:'1',
read: false,
folder: 'inbox'},
{id:'2',
read: true,
folder: 'inbox'},
{id:'3',
read: true,
folder: 'trash'},
{id:'4',
read: false,
folder: 'trash'}];
And I need to delete any object that has the attributes folder == 'trash' and read == true at the same time.
So I tried to do it like this with lodash:
example = lodash.filter(example, function(value, index) {
return (value.folder !== 'trash') && (value.read !== true);
});
It should delete only the item #3, but it deletes #3 and #4.
Obviously I'm not understanding how lodash.filter really works.
Can someone please help?

You logical operator is not correct. set the condition to folder == 'trash' and read == true and the negate it.
example = lodash.filter(example, function(value) {
return (value.folder == 'trash' && value.read == true) == false;
});

You need to remove the quotes around 'true'. You want to keep all the elements where the folder is not 'trash' or the read property is not true so your logic would look like this
return (value.folder !== 'trash') || (value.read !== true);

The operator !== is false. use == instead.
return (value.folder == 'trash' && value.read == 'true') == false;

Related

Is there a way to refactor this AND and XOR logical branch?

I have 2 user IDs and I would like to do different but very similar logic if I have only one or both. Is there a way to consolidate this code, as right now it looks ugly.
function getUserPermission(primaryId, secondaryId, role) {
let permission = userInfo.permissionList.filter( permission => {
//logical AND
if(primaryId && secondaryId){
// have both IDs, use both IDs
(permission.primaryId === primaryId && permission.secondaryId === secondaryId) && permission.role === role
}
//logical XOR
else if((primaryId && !secondaryId) || (!primaryId && secondaryId)) {
// have only 1 ID, use 1 ID
(permission.primaryId === primaryId || permission.secondaryId === secondaryId) && permission.role === role
}
})[0]
return permission
}
First, it seems like this logic doesn't handle when both ids are invalid. You'll want to handle that somehow (looks like both the other answers so far include something along those lines).
Next, since you're only returning the first matching permission, I would suggest using a solution that doesn't keep looping once you've found that first match. In that respect, Array.find() is far better than Array.filter() for this use case.
If I were to put the other answers together, it would be something like this:
function getUserPermission(primaryId, secondaryId, role) {
if (!primaryId && !secondaryId) return null // at least one must be populated, why loop at all?
return userInfo.permissionList.find(permission =>
permission.role === role
&& (!primaryId || primaryId === permission.primaryId) // if primary is populated, it needs to match
&& (!secondaryId || secondaryId === permission.secondaryId) // if secondary is populated, it needs to match
);
}
...but that doesn't handle the case where a perfectly valid ID happens to be 0. That could depend on your data, though. Perhaps you're always using string-based IDs, for example. It also checks for valid ids on every loop (something you may or may not be perfectly comfortable with)
With those potential issues in mind, I made some assumptions about your data/types and threw a more unorthodox approach together in an attempt to solve them:
const getUserPermission = (primaryId = -1, secondaryId = -1, role = '') => {
if (primaryId < 0 && secondaryId < 0) return null
const conditions = [ p => p.role === role ]
.concat(primaryId >= 0 ? [ p => p.primaryId === primaryId ] : [])
.concat(secondaryId >= 0 ? [ p => p.secondaryId === secondaryId ] : [])
return userInfo.permissionList.find(p => conditions.every(fn => fn(p)))
}
...this last one makes an array of functions, conditions, to check each permission against. The first one to match every condition should be returned (in theory, at least - I didn't test it)
What about something like this?
if(!primaryId && !secondaryId) {
throw Error("No ID was provided");
}
let permission = userInfo.permissionList.filter(p => p.role === role);
if(primaryId) {
permission = permission.filter(p => p.primaryId === primaryId);
}
if(secondaryId) {
permission = permission.filter(p => p.secondaryId === secondaryId);
}
return permission[0];
function getUserPermission(primaryId, secondaryId, role) {
return userInfo.permissionList.find(permission =>
permission.role === role
&& (!!primaryId || !!secondaryId)// at least one is populated
&& (!primaryId || primaryId === permission.primaryId)// if primary is populated, it needs to match
&& (!secondaryId || secondaryId === permission.secondaryId)// if secondary is populated, it needs to match
);
}
This is slightly different from your code in that if there is no match, it returns null, whereas yours throws an exception. If you mean to throw, you can always put the result in a variable and check for null.
What about this refactoring :
function getUserPermission(primaryId = undefined,secondaryId = undefined,role) {
primaryId === undefined && secondaryId === undefined && throw new Error("Ids are required");
const userPermission = userInfo.permissionList
.filter((permission) => role && permission.role === role)
.filter((permission) => primaryId && permission.primaryId === primaryId)
.filter(
(permission) => secondaryId && permission.secondaryId === secondaryId
);
return userPermission[0];
}

Optimize a function that ensures an object's properties does not have any of these values

I have an array of objects that represent form fields. I want to make sure that none of the elements in the array have their initial values. As in all fields need to be updated. The initial value is below. I'd like a simple function that checks each element and ensures none of these properties have the default fields.
[
{
key: 0,
name: '',
typeLabel: '',
typeValue: 0,
value: '',
}
...
]
Looking for help on improving this
collection.every((obj) => {
if (obj.key === 0) return false;
if (obj.name === '') return false;
if (obj.typeLabel === '') return false;
if (obj.typeValue === 0) return false;
if (obj.value === '') return false;
return true;
});
EDIT: Actually just thought of this
collection.every((obj) => {
const values = Object.values(obj);
return values.includes(0, '');
});
To be honest I'm not sure how much more better you can make it, it looks pretty decent to me! Any changes I'd make would be subjective changes that don't actually matter. Curious what other people will answer with though, maybe I'm missing something :)
I mean you could do this and it's arguably less if/elses and uses a named function to explain what it is doing which is maybe nicer? But meh I don't think this matters all that much:
function inputValueHasBeenSet(inputObject) {
return !!inputObject.key &&
!!inputObject.name &&
!!inputObject.typeLabel &&
!!inputObject.typeValue &&
!!inputObject.value;
}
collection.every(inputValueHasBeenSet);

Based on condition add true or false

I've 5 cells in a table. If the value are empty for those cells i need to disable them.
I can do something like this for each cells which work's.
function cellOne(params) {
if (params.value === null || params.value === undefined) {
return false
} else {
return true;
}
}
"CellOne": { disabled:cellOne }
is there any other way to check null value of each cell and add disable property instead of creating multiple function for each cells. Please help
You don't need to go for typescript code.You can do it in the template itself.
<your-cell [disabled]="!params.value"></your-cell>
Your function would return the same thing as :
function cellOne(params) {
return params.value != null
}
which you can easily inline instead of having a separate function for that.
To check for params that might be null or undefined too, you can use :
return params && params.value != null

map for array and comparing at least one coincidence

In javascript, I have this situation:
this.props.number is always a number 0, 1,or 2
this.props.columnas is an array of objects like this:
[
{value:'1',text:'AA'},
{value:'2',text:'BB'},
{value:'3',text:'CC'},
{value:'4',text:'DD'},
{value:'5',text:'EE'},
{value:'6',text:'FF'},
{value:'7',text:'GG'}
]
selected is an array of objects too like this:
[{col:"2", ope:"", val:""}, {col:"5", ope:"", val:""}, {col:"7", ope:"", val:""}, ]
And I have this code:
this.props.columnas.map(function(col){
if(this.props.number == 0) {
if (col.value == selected[0].col)
disabledIndice = true
else
disabledIndice = false;
}
else if(this.props.number == 1) {
if (col.value == selected[0].col || col.value == selected[1].col)
disabledIndice = true
else
disabledIndice = false;
}
else if(this.props.number == 2) {
if (col.value == selected[0].col || col.value == selected[1].col || col.value == selected[2].col)
disabledIndice = true
else
disabledIndice = false;
}
return <option value={col.value} disabled={disabledIndice}>{col.text}</option>
}.bind(this))}
(forget the bind. function and es5, I will use arrow functions anyway)
It's too long and it's not doing what I need to do. I want to use map again in selected to find which col.value is the same than the one stored on selected.
In the code above, I'm assuming that I'll have 3 objects for selected, but that's not always the case. Sometimes could be 1, 2 or 3 objects, thats why the code is using those ìf for each case (the numbers of objects is defined by this.props.number). That's ugly.
I've tried something like this:
this.props.columnas.map(function(col){
indicesYaSeleccionado.map(function(item){
if (col.value == item.col)
disabledIndice = true
else disabledIndice = false;
});
return <option key={constant.guid()} value={col.value} disabled={disabledIndice}>{col.text}</option>
}.bind(this))
But that I will always get disabledbecause I'm comparing each value, I need to set as disabledIndice = true at least in 1 coincidence.
Any tip? It was a long explanation, sorry.
From what I've understand, you just have to see if the current col value is in the selected.val array.
this.props.columnas.map(function(col){
let disabledIndice =
selected.findIndex(e => e.col === col.value) !== -1
? true : false
return <option value={col.value} disabled={disabledIndice}>{col.text}</option>
}.bind(this))}
This code should work fine.
You'll have to re-add this.props to your contextualized variables, but this should cover it. And I tried to give you as many arrow functions as I could. Your return will break the code, but if used with something like React's JSX it should work fine.
//removed this.props references for the sake of this example
const columnas = [
{value:'1',text:'AA'},
{value:'2',text:'BB'},
{value:'3',text:'CC'},
{value:'4',text:'DD'},
{value:'5',text:'EE'},
{value:'6',text:'FF'},
{value:'7',text:'GG'}
];
//could be 0, 1, or 2
let curNum = 1
let selected = [{col:"2", ope:"", val:""}, {col:"5", ope:"", val:""}, {col:"7", ope:"", val:""}, ]
columnas.map( el => {
let disabledIndice = selected.every( sel => el.value == sel.col ) ?
true : false;
return <option key={constant.guid()} value={col.value} disabled={disabledIndice}>{col.text}</option>
}.bind(this))
});

Do you need to type out == null with Element.previousSibling?

If I want to check if an element is the first child of it's parent, I can do it like this:
if (element.previousSibling == null) {
...
}
But is it "wrong" to do it like this:
if (!element.previousSibling) {
...
}
? Since it still works since !!null == false and !!anyElement == true?

Categories