Angular: Cannot retrieve function parameter value as an object property selector - function

I have an issue trying to retrieve a function parameter value as an object property selector into a .filter() method.
This is my code:
myFunction(property, value) {
function myFilter(obj) {
return obj.details.name == value;
}
return this._http.get(this.Url).map((response: Response) => response.json().filter(myFilter));
}
I want to replace return obj.details.name == value; by return obj.property == value;.
obj.property is the parameter of my function myFunction(property, value). The value parameter value works fine and is well retrieved.
This is what I want:
getFilteredFMsBy(property, value) {
function specificFilter(obj) {
return obj.property == value;
}
return this._http.get(this.Url).map((response: Response) => response.json().filter(specificFilter));
}
If I define the value of property in the function, same case. It doesn't work:
getFilteredFMsBy(property, value) {
property = "details.name";
function specificFilter(obj) {
return obj.property == value;
}
return this._http.get(this.Url).map((response: Response) => response.json().filter(specificFilter));
}
Any idea?

Seems like you need to access object[prop][prop2] given the object and the string "prop.prop2"
from this answer: Javascript: Get deep value from object by passing path to it as string you can do deepFind:
function deepFind(obj, path) {
var paths = path.split('.')
, current = obj
, i;
for (i = 0; i < paths.length; ++i) {
if (current[paths[i]] == undefined) {
return undefined;
} else {
current = current[paths[i]];
}
}
return current;
}
then do
getFilteredFMsBy(property, value) {
property = "details.name";
function specificFilter(obj) {
return deepFind(obj, property) == value; // <-- use it here
}
return this._http.get(this.Url).map((response: Response) => response.json().filter(specificFilter));
}

How about this?
getFilteredFMsBy(property: string, value:any) {
return this._http.get(this.Url).map((response: Response) => response.json().filter((obj) => { return obj[property] == value; }));
}

Related

How to return value based on array inspection + if-statement?

I am getting a warning on the following function
function currencySubmenuTitle(ctx) {
let id = Object.keys(currencies).find(element => {
if (currencies[element].id === ctx.match[1]) {
return element
}
})
if (typeof id === 'undefined' || id === null) {
return "No match found"
} else {
return `💰 ${toTitleCase(id)} : ${currencies[id].current}`
}
}
Note: My id and element are different, so I can't just take the element and use that as the string return.
The warning is:
2:51 warning Expected to return a value at the end of arrow function array-callback-return
2:51 warning Expected to return a value at the end of arrow function consistent-return
How do I return my value in this function in a compliant way (aka not how I am doing it)
Can I thenify this? Run the if statement based on the return of the array-evaluation?
The evaluation of the statement can happen in the return line, so no specific if-statement is needed here. Simply do:
function currencySubmenuTitle(ctx) {
let id = Object.keys(currencies).find(element => {
return currencies[element].id === ctx.match[1]
})
if (typeof id === 'undefined' || id === null) {
return "No match found"
} else {
return `💰 ${toTitleCase(id)} : ${currencies[id].current}`
}
}

Angular, cannot access members of object in the array in custom pipes

Below is my custom pipe where I am unable to access the members of the customfilter array which is of type Item.
import { Pipe, PipeTransform } from '#angular/core';
import {Bus} from '/home/pavan/Desktop/Pavan/apstrtcAngular/src/app/Bus';
import { Item } from './Item';
#Pipe({
name: 'busFilter'
})
export class BusFilterPipe implements PipeTransform {
transform(items: Bus[], customfilter: Item): Bus[] {
if(!items || !customfilter)
{
return items;
}
return items.filter((item: Bus)=>
this.applyFilter(item, customfilter));
}
applyFilter(bus:Bus, customfilter: Item):
boolean{
if( customfilter[0].item_id){
if(typeof customfilter[0].item_id==='string'){
if(typeof bus.bustype==='string')
{
if(customfilter[0].item_id===bus.bustype)
{
return false;
}
} }
}
return true;
}
}
Below is my Item.ts and ng multiselect.
export class Item {
/**
* #type {number} id Unique numeric identifier.
*/
item_id: string;
item_text:string;
}
<ng-multiselect-dropdown class="ngfilter"
[placeholder]="'Select BusType'"
[data]="BusTypes"
[(ngModel)]="customfilter"
[settings]="dropdownSettings"
(onSelect)="onItemSelect($event)"
(onSelectAll)="onSelectAll($event)"></ng-multiselect-dropdown>
I am unable to find the issue here, I cannot look at the value of item_id during debugging too. please help me to know where the issue is. Thank you.
import { Pipe, PipeTransform } from '#angular/core';
import {Bus} from '/home/pavan/Desktop/Pavan/apstrtcAngular/src/app/Bus';
import { Item } from './Item';
import { forEach } from '#angular/router/src/utils/collection';
#Pipe({
name: 'busFilter'
})
export class BusFilterPipe implements PipeTransform
{
transform(items: Bus[], customfilter: Item[]): Bus[] {
let ResultSet: Bus[] = [];
if (!items || !customfilter) {
return items;
}
else if (customfilter.length == 0) {
return items;
}
else{
for (let i = 0; i < items.length; i++) {
for (let j = 0; j < customfilter.length; j++) {
if (customfilter[j].item_text === items[i].bustype) {
ResultSet.push(items[i]);
console.log("Result Set =" + ResultSet);
}
}
}
return ResultSet;
}
}
}
Based on your comments and my understanding of your code written in the pipe, modify your pipe like this (please read through the comments in the code):
transform(items: Bus[], customfilter: Item[]): Bus[] {
if(!items || !customfilter)
{
return items;
}
// making custom filter an Array if it isn't already
customFilter = customFilter instanceof Array ? customFilter : [customFilter];
// you seem to ignore the custom filters which don't have item_id
customFilter = customFilter.filter((eachCustom) => eachCustom.item_id);
// create an array of new items which satisfy your criteria
return items.reduce((acc, eachBus) => {
// if bus's bustype is not string then no need to filter
if (typeof eachBus.bustype != 'string') {
acc.push(eachBus)
}
else {
// if the bustype is a string
// then you have to see if this bus's bustype matches any of the custom filters and it's id type
// if not found then that bus should be present in the final bus list
let filterFound = customFilter.findIndex((eachFilter) => {
return (typeof eachFilter.item_id === 'string') && (typeof eachBus.bustype === 'string') && (eachFilter.item_id === eachBus.bustype);
});
if (filterFound === -1) {
// this bus is not found in the filter
acc.push(eachBus)
}
}
return acc;
}, [])
}
Below is a script in javascript to verify the result
function transform(items, customfilter) {
if(!items || !customfilter)
{
return items;
}
// making custom filter an Array if it isn't already
customFilter = customFilter instanceof Array ? customFilter : [customFilter];
// you seem to ignore the custom filters which don't have item_id
customFilter = customFilter.filter((eachCustom) => eachCustom.item_id);
// create an array of new items which satisfy your criteria
return items.reduce((acc, eachBus) => {
// if bus's bustype is not string then no need to filter
if (typeof eachBus.bustype != 'string') {
acc.push(eachBus)
}
else {
// if the bustype is a string
// then you have to see if this bus's bustype matches any of the custom filters and it's id type
// if not found then that bus should be present in the final bus list
let filterFound = customFilter.findIndex((eachFilter) => {
return (typeof eachFilter.item_id === 'string') && (typeof eachBus.bustype === 'string') && (eachFilter.item_id === eachBus.bustype);
});
if (filterFound === -1) {
// this bus is not found in the filter
acc.push(eachBus)
}
}
return acc;
}, [])
}
let buses = [{bustype: 1}, {bustype: "volvo-ac"}, {bustype: "volvo-non-ac"}, {bustype: "non-volvo-ac"}, {bustype: "non-volvo-non-ac"}]
let customFilter = [{item_id: "volvo-ac"}, {item_id: "non-volvo-ac"}]
console.log(transform(buses, customFilter))
// expected output won't contain the buses present in the filter

use directive return value

I have this dirctive that return title or null , how can i use this return value in html component ???
element:ElementRef;
#Input() pageTabTitle:string;
constructor(el:ElementRef) { this.element =el; }
ngOnChanges(): void {
setTimeout(() => {
this.hasTooltip(this.pageTabTitle);
})
}
hasTooltip(title:string) {
if(this.isOverflown()) {
return title;
} else {
return null;
}
}
isOverflown():boolean {
return this.element.nativeElement.scrollWidth >
this.element.nativeElement.clientWidth;
}
I want to use this value in tooltip title
[attr.data-original-title]="" // here I want to set return directive value
I think your directive doesn't have #Output - it couldn't return something:)
If you want that it emit some event with value, you should #Output property and emit it when you need.
Angular Io

The keyword "is" in the return type of TypeScript function

In VSCode's source file, there are some functions with a particular return type specification, like this:
export function isString(str: any): str is string {
if (typeof (str) === _typeof.string || str instanceof String) {
return true;
}
return false;
}
So I wonder what is the purpose of "str is string" instead of just writing "boolean".
Can we use "str is string" and the like in any other circumstances?
That is called User-Defined Type Guards.
Regular type guards let you do this:
function fn(obj: string | number) {
if (typeof obj === "string") {
console.log(obj.length); // obj is string here
} else {
console.log(obj); // obj is number here
}
}
So you can use typeof or instanceof, but what about interfaces like this:
interface Point2D {
x: number;
y: number;
}
interface Point3D extends Point2D {
z: number;
}
function isPoint2D(obj: any): obj is Point2D {
return obj && typeof obj.x === "number" && typeof obj.y === "number";
}
function isPoint3D(obj: any): obj is Point2D {
return isPoint2D(obj) && typeof (obj as any).z === "number";
}
function fn(point: Point2D | Point3D) {
if (isPoint2D(point)) {
// point is Point2D
} else {
// point is Point3D
}
}
(code in playground)

How should i get matching sub-objects from nested json object

I have an obj like this:
var obj = { thing1 : { name: 'test', value: 'testvalue1'},
thing2 : { name: 'something', thing4: {name:'test', value: 'testvalue2'}},
}
I want to write a function like findByName(obj, 'test').It returns all the matching sub-objects with the same name. So it should return:
{ name: 'test', value: 'testvalue1'}
{name:'test', value: 'testvalue2'}
Right now this is what i have:
function findByName(obj, name) {
if( obj.name === name ){
return obj;
}
var result, p;
for (p in obj) {
if( obj.hasOwnProperty(p) && typeof obj[p] === 'object' ) {
result = findByName(obj[p], name);
if(result){
return result;
}
}
}
return result;
}
obviously it only return the first matching.. how to improve this method?
You need to push the results into an array and make the function return an array.
Also, do a sanity check whether the object is null or undefined to avoid errors.
Here is your code modified.
Note: I have also modified the parent object ,which is "obj", by adding a "name" property with value "test" so the result should have the parent object in the result as well.
function findByName(obj, name) {
var result=[], p;
if(obj == null || obj == undefined)
return result;
if( obj.name === name ){
result.push(obj);
}
for (p in obj) {
if( obj.hasOwnProperty(p) && typeof obj[p] === 'object') {
newresult = findByName(obj[p], name);
if(newresult.length>0){
//concatenate the result with previous results found;
result=result.concat(newresult);
}
}
}
return result;
}
var obj = { thing1 : { name: 'test', value: 'testvalue1'},
thing2 : { name: 'something', thing4: {name:'test', value: 'testvalue2'}},
name:'test' //new property added
}
//execute
findByName(obj,"test");
Run this in your console and upvote if this helps you.