I'm stuck with return a value using Array.map in Angular 2
So what am I missing here?
export class TabsPage {
#ViewChild(SuperTabs) superTabs: SuperTabs;
public rootTab: string = 'ProductListPage';
public categories: Array<any>;
public collection_id: number;
public selectedindex: any;
private getArrayIndex(source, target) {
source.map((element, index) => {
if (element.attrs.collection_id === target) {
// Returns the Value i need
console.log('i: ', index);
return index;
}
});
}
constructor(
public navCtrl: NavController,
public navParams: NavParams,
public shopifyClientProvider: ShopifyClientProvider,
private superTabsCtrl: SuperTabsController,
) {
this.categories = navParams.get('collections');
this.collection_id = navParams.get('collection_id');
this.selectedindex = this.getArrayIndex(this.categories, navParams.get('collection_id'));
// Returns undefined
console.log('Index ', this.selectedindex);
}
}
I know this question is already answered but I have one solution for this same.
.ts file code
private getArrayIndex(source, target) {
let indx = -1;
source.map((element, index) => {
if (element.attrs.collection_id === target) {
// Returns the Value i need
console.log('i: ', index);
indx = index;
}
});
return indx;
}
You can use findIndex() to do this in pretty short order:
I don't know exactly what your data looks like, but given an array:
const target = 2;
const source = [
{
attrs: {
collection_id: 1
}
},
{
attrs: {
collection_id: 2
}
},
{
attrs: {
collection_id: 3
}
},
];
const index = source.findIndex(element => element.attrs.collection_id === target);
would return 1 for the index. If the index isn't found, -1 will be returned.
Plunkr: https://plnkr.co/edit/5B0gnREzyz6IJ3W3
Hope that helps you out.
Looks like Typescript breaks the return. With this modification i get the desired Value:
private getArrayIndex(source, target) {
let found: number;
source.map((element, index) => {
if (element.attrs.collection_id === target) {
console.log('i: ', index);
found = index;
}
});
return found;
}
Related
I am having an issue when I try to get a specified user from Firebase, Firestore.
export class TaskService {
tasksCollection: AngularFirestoreCollection<Task>;
taskDoc: AngularFirestoreDocument<Task>;
tasks: Observable<Task[]>;
task: Observable<Task>;
constructor(private afs: AngularFirestore) {
this.tasksCollection = this.afs.collection('tasks', ref => ref.orderBy('title', 'asc'));
}
getTask(id: string): Observable<Task> {
this.taskDoc = this.afs.doc<Task>(`clients/${id}`);
this.task = this.taskDoc.snapshotChanges().pipe(map(action => {
if (action.payload.exists === false) {
return null;
} else {
const data = action.payload.data() as Task;
data.id = action.payload.id;
return data;
}
}));
return this.task;
}
}
And this is my Component.ts file
export class TaskDetailsComponent implements OnInit {
id: string;
task: Task;
hasHours = false;
showHoursOnUpdate: false;
constructor(
private taskService: TaskService,
private router: Router,
private route: ActivatedRoute
) { }
ngOnInit() {
// Get id from url
this.id = this.route.snapshot.params.id;
// Get client
this.taskService.getTask(this.id).subscribe(task => {
if (task != null) {
if (task.hours > 0) {
this.hasHours = true;
}
}
this.task = task;
});
console.log(this.id);
console.log(this.task);
}
}
The result for id is good.
But the result for object (task) is undefined.
P.S
I also have functions for getting all the users and adding a new user, so if that's relevant please let me know in the comments
Your line of code
this.id = this.route.snapshot.params.id;
In this case id is not a table column but it's your document id by Firestore
Here an example of firestore
So your Id in this case is the red one and not the blue one.
just wanted to avoid if statements is there way to assign values to object if they have similar keys in response instead of checking each object with if ?
what could be efficient approach here ?
main.ts
public responsehandler(#Body()data: any): any {
const response: Idetails = {} as Idetails;
if (data.details === undefined || data.details === null) {
return data;
}
if (data.details) {
if (data.details.primary) {
response.details.primary.beginningBalance = data.details.primary.beginningBalance;
response.details.primary.endingBalance = data.details.primary.endingBalance;
}
if (data.details.secondary) {
response.details.secondary.beginningBalance = data.details.secondary.beginningBalance;
response.details.secondary.endingBalance = data.details.secondary.endingBalance;
}
}
return response;
}
interface.ts
export interface Idetails {
primary:balanceDetails;
secondary: balanceDetails;
}
export interface balanceDetails {
beginningBalance: string;
endingBalance: string;
}
data
details: {
primary: {
beginningBalance: 458,
endingBalance: 890
},
secondary: {
beginningBalance: 47,
endingBalance: 871
}
}
Check this out: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/hasOwnProperty
You could try this approach:
public responsehandler(#Body()data: any): any {
const response: Idetails = {} as Idetails;
if (!data.details) {
return data;
}
for (const key in response.details) {
if (data.details.hasOwnProperty(key)) {
response.details[key] = data.details[key];
}
}
return response;
}
You should check more validations or conditions to make it work for you.
If your goal is just to avoid if statements, you could rewrite it like so:
// in js (sorry not a ts user)
function responseHandler(data) {
return data.details == null ? data : {details: {...data.details}};
}
console.log(responseHandler({details: {primary: {beginningBalance: 0, endingBalance: 1}}}));
console.log(responseHandler({details: {secondary: {beginningBalance: 0, endingBalance: 1}}}));
console.log(responseHandler({noDetails: 'oopsy'}));
I am trying to update object array inside observable subscribe method. But it is not updating as expecting.
My implementation is as follows.
Compoent.ts
constructor(private shopHomeService: ShopHomeService) {
this.shopHomeService.shopItemChanged.subscribe(
(item) => {
if (item) {
this.items = shopHomeService.getShopItems();
if (this.items.length > 0) {
const findItem = this.items.find(shopItem => shopItem.Id === item.Id);
if (findItem) {
findItem.OrderQuantity = findItem.OrderQuantity + 1;
} else {
this.items.push(item);
}
} else {
this.items.push(item);
}
this.items = this.items.slice();
shopHomeService.ShopItems = this.items;
this.shopItems = [];
this.shopItems = this.items;
}
}
);
}
Service.ts
import { Injectable } from '#angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
#Injectable()
export class ShopHomeService {
private shopItems = [];
private shopItem: any;
shopItemChanged = new BehaviorSubject<any>(this.shopItem);
constructor() { }
getShopItems() {
console.log(this.shopItems);
return this.shopItems;
}
set ShopItems(shopItems) {
this.shopItems = shopItems;
console.log(this.shopItems);
}
addShopItem(item) {
item.OrderQuantity = 1;
item.Discount = 0;
item.DiscountPercentage = 0;
this.shopItemChanged.next(item);
}
removeShopItem(item) {
this.shopItems = this.shopItems.filter(element => element.Id !== item.Id);
this.shopItemChanged.next(this.shopItems);
}
}
Initially OrderQuantity property set to 1 in every objects of the array items.
When same type of object adding to shopItems it will increase value of OrderQuantity by 1. Logic has implemented above code. But when shop items change it always gives object array with OrderQuantity = 1. (shopHomeService.getShopItems() returns array list with OrderQuantity = 1, but when the shopHomeService.ShopItems call it sent rderQuantity = 2)
I want to track changes to the properties of my classes in typescript so that I only update the fields in my database which have actually changed. Currently, I am using an array where I add properties when they change and then I iterate through the array to determine what fields changed and need to be updated in the database. However, I would prefer to do this with some sort of isDirty check. My thought is that I would be able to call something like if (property.dirty) then {} to determine if a property has changed.
I remember being able to do something along these lines in vb.net, but it's been a while and I can't remember exactly what we did in that codebase.
Is the desired code below possible?
Current Code
class test{
private _ID: Guid;
private _dirty: Array<{}>;
get ID(): Guid {
return this._ID;
}
set ID(id: Guid) {
if (this._ID != id) {
this._ID = id;
this._dirty.filter(function (f) { return f.Field == "id" }).length > 0 ? this._dirty.filter(function (f) { return f.Field == "id" })[0].Value = id.toString() : this._dirty.push({Field: "id", Value: id});
}
}
get Name(): string {
return this._Name;
}
set Name(name: string) {
if (this._Name != name) {
this._Name = name;
this._DirtyFields.filter(function (f) { return f.Field == "ccseq_name" }).length > 0 ? this._DirtyFields.filter(function (f) { return f.Field == "ccseq_name" })[0].Value = name : this._DirtyFields.push(new EntityField("ccseq_name", name, FieldType.String));
}
}
}
Desired Code
class test{
private _ID: Guid;
get ID(): Guid {
return this._ID;
}
set ID(id: Guid) {
if (this._ID != id) {
this._ID = id;
this._ID.isDirty = true;
}
}
get Name(): string {
return this._Name;
}
set Name(name: string) {
if (this._Name != name) {
this._Name = name;
this._Name.isDirty = true;
}
}
}
In javascript you can add a property to an object so it's not a problem to do this:
this._ID.dirty = true;
Even when Guid doesn't have this dirty member.
The problem of course is typescript which will complain because of that.
To avoid that you can simply do:
private _ID: Guid & { dirty?: boolean };
Edit
Again, javascript already supports it, you can do this:
obj.dirty = true;
For any js type: booleans, strings, arrays and even functions.
But for having support for that in typescript you can do this:
interface Object {
dirty?: boolean;
}
But be aware that you are adding this to **all* of the objects that you have in your code. As you're not actually changing the prototype it won't have any effect in runtime, but typescript-wise it will effect all instances.
The way I solved this was to create a Field class that I then used as properties in my Objects.
Field Class
export class EntityField {
private _Field: string;
private _Value: any;
private _FType: FieldType;
private _isDirty: boolean;
constructor(field: string, value: any, fType: FieldType) {
this._Field = field;
this._Value = value;
this._FType = fType;
this._isDirty = false;
}
markClean(): void {
this._isDirty = false;
}
markDirty(): void {
this._isDirty = true;
}
get isDirty(): boolean {
return this._isDirty;
}
get Field(): string {
return this._Field;
}
set Field(field) {
if (this._Field !== field) {
this._Field = field;
}
}
get Value(): any {
return this._Value;
}
set Value(value: any) {
if (this._Value !== value) {
this._Value = value;
this._isDirty = true;
}
}
get FType(): FieldType {
return this._FType;
}
set FType(fType: FieldType) {
if (this._FType != fType) {
this._FType = fType;
}
}
}
Usage
export class Entity{
public Name: Field
}
Entity test = new Entity()
Entity.Name.isDirty() // Returns False
Entity.Name.Value = "Test";
Entity.Name.isDirty() // Returns True
this.listvalue;
list.forEach((v: any) => {
v.data.forEach((v2: any) => {
this.searchlist.push({
header: v.header,
value: v2.value_0
});
});
});
i want to pass the this.listvalue on the place of v2.value_0 =>v2.this.listvalue but this is not working giving syntax error I also tried v2.valueof(this.listvalue) but its also not working like that i want to change call the v2 via this.listvalue
How can I do this? what is the correct syntax for this scenario?
the whole code is here
export class Md2Component {
#Input() list: any;
#Input() listvalue: any;
public searchlist;
public placeholder: String = "Searct the JSON";
public switch: boolean = true;
public switch5: boolean = true;
public searchlistresult: any
public data: string;
public header1: String;
public resultant_list: any;
public lastone: user[] = [];
#Output() _onSelect = new EventEmitter<any>();
public anyinstance: any
public user2: user
s = '';
public index;
constructor() {
}
ngOnInit() {
this.data = this.listvalue;
this.createSearchList(this.list);
this.latest(this.searchlist);
}
private createSearchList(list: any) {
this.searchlist = [];
this.listvalue;
list.forEach((v: any) => {
v.data.forEach((v2: any) => {
this.searchlist.push({
header: v.header,
value: v2.value_0
});
});
});
}
search1(s) {
this.search(s);
if (this.switch != true) {
this.latest(this.searchlistresult)
}
}
search(s) {
this.switch = false;
this.searchlistresult = _.filter(this.searchlist, (o: any) => {
if (s) {
return _.startsWith(_.lowerCase(o.value), _.lowerCase(s));
}
this.switch = true;
return true;
});
}
latest(list: any) {
const arr = list;
const keys = [];
for (let i of arr) {
if (!keys.includes(i.header)) keys.push(i.header);
}
const result = keys
.map(k => Object.assign({header: k}, {
data: arr.filter(x => x.header === k)
.map(y => Object.assign({}, {value: y.value}))
}));
this.anyinstance = result;
}
generateArray(obj) {
return Object.keys(obj).map((key) => {return obj[key]});
}
onSelect(header: any, value: any) {
{
console.log(header);
console.log(value);
this.s = value;
this.user2 = {
header: header,
value: value
}
this.lastone.push({
'header': header,
'value': value,
}
);
this.switch = true;
this._onSelect.emit(this.user2);
}
}
}
You've said this.listvalue is an #Input() so we will assume it has been initialized with a value already.
UPDATE You can try passing as a parameter. As the global scope of listvalue is what's causing your issue, passing it into the function will bring it into the correct scope.
// Bringing listvalue into scope, to avoid use of 'this' accessor.
private createSearchList(list: any, listvalue: any) {
this.searchlist = [];
list.forEach((v: any) => {
v.data.forEach((v2: any) => {
this.searchlist.push({
header: v.header,
value: listvalue
});
});
});
}