I have 3 arrays here of type channel array.
currentPickSelection: Array<channel>;
draggedChannel: channel;
droppedChannel: channel;
What I am trying to do is remove an item(the droppedChannel array item)from the currentPickSelection array and insert the draggedChannel item array onto the same index of the removed item.
Here is what I did so far, everything works except the insert part:
let index = this.currentPickSelection.findIndex(item => item === this.droppedChannel);
this.currentPickSelection.splice(index, 1, this.draggedChannel);
An this is the way I have the channel model declared:
export class CompChannel {
constructor(public compChannelCbsCode: string,
public compChannelName: string,
public compChannelLogo: string) {}
}
export class channel {
public pickCode: string;
public cbsCode: string;
public channel: string;
public logo: string;
public compChannel: CompChannel[];
constructor(pickCode: string, cbsCode: string, channel: string,
logo: string, compChannel: CompChannel[]) {
this.pickCode = pickCode;
this.cbsCode = cbsCode;
this.channel = channel;
this.logo = logo;
this.compChannel = compChannel;
}
}
Please advise what is wrong!
The droppedChannel object and the item found in currentPickSelection may not the exact same copy/clone of each other.
Try to compare with an unique value(like pickCode or cbsCode) in findIndex method instead of comparing with the whole object.
let currentPickSelection: any[] = [
{ id: 1, label: 'Test1' },
{ id: 2, label: 'Test2' },
{ id: 3, label: 'Test3' }
];
let draggedChannel: any = { id: 5, label: 'Test5' };
let droppedChannel: any = { id: 3, label: 'Test3' };
let index = currentPickSelection.findIndex(item => {
return item.id == droppedChannel.id; //use unique value instead of item object
});
if (index > -1)
currentPickSelection.splice(index, 1, draggedChannel);
Related
I have an array as shown below.
I want this pattern:
I want to Get distinct "CityRef" and "City".
then find all item in association with that.
Working TS playground.
interface GroupedItemsByCity {
cityRef: number
cityName: string,
items: Array<{
id: number,
itemName: string
}>
}
const groupedObject = returnObject.reduce<GroupedItemsByCity[]>((groupedArray, item) => {
// New slimmer item to push later
let refinedItem = {
id: item.id,
itemName: item.itemName
}
const matchedCity = groupedArray.find(city => city.cityRef === item.cityRef); // Check if the new structure already has a matching parent city for current item.
if (matchedCity) {
// If it does, push the item onto the existing city object.
matchedCity.items.push(refinedItem)
return groupedArray
}
// If it doesn't set up a new city and add the item to it
groupedArray.push({
cityRef: item.cityRef,
cityName: item.cityName,
items: [refinedItem]
})
return groupedArray
}, [])
console.log(groupedObject)
In TypeScript, if I have an interface (or an array? Not keen on terminologies) like this:
export const AnimalColours = [
{ value: 'blue', desc: 'Blue Whale' },
{ value: 'black', desc: 'Black Bear' },
{ value: 'orange', desc: 'Orange Cat' },
] as IAnimalColours[]
On the UI, I have a variable that will have any value of the string that must correspond to the AnimalColours.value:
let inputOrEventValue: string = "orange" // can be taken from input or event
How do I get to output the description by referencing inputOrEventValue to AnimalColours?
let outPutstring: string = // My value Must use AnimalColours.value
Pseudo:
If inputOrEventValue has a value
Compare with AnimalColours.value
If EQUAL, return AnimalColours.desc
So that if inputOrEventValue = orange
The outPutstring would take AnimalColours[2].desc (value: "Orange Cat")
One solution is:
for (animalColour in IAnimalColours) {
if (animalColour.value === InputOrEventValue) {
outputString = animalColour.desc;
}
}
Are there other, more elegant solutions?
So far the best I can do is:
this.animalColours.forEach(element => {
if (this.inputOrEventValue === element.value) {
this.outputString = element.desc;
}
});
Feel free to post any other answer.
Update: Solution
I've adapted the accepted solution below slightly to fit my use-case. All Credits to the poster of the accepted solution.
export class MyClass {
//Declare we'll be using arbitrary number accessors
[int: number]: any;
list: any[] = [
{ name: 'apples', amount: 3, price: 10 },
{ name: 'bananas', amount: 1, price: 3 },
{ name: 'mangos', amount: 5, price: 18 },
];
constructor() {
//On instantiation, create the getters.
this.createProperties()
}
private createProperties() {
this.list.map((c, i) => {
Object.defineProperty(this, i, {
configurable: true,
get: () => {
const v = this.getItemWithPrice(i);
//Cleverly replace this getter with the value of the calculation.
//Keeps us from redoing the calculations when the same property is gotten again.
Object.defineProperty(this.list, i, { value: v });
return v
},
});
});
}
getItemWithPrice(index: number) {
//Some calculation before returning the item.
if (!this.list[index].total) this.list[index].total = this.list[index].amount * this.list[index].price;
return this.list[index];
}
}
const someList = new MyClass();
//I can now access the list like so:
someList[1]; // { name: 'bananas', amount: 1, price: 3, total: 3 },
Original Post
I am trying to access items in a list, whose values will be calculated once requested. Consider the example:
export class MyClass {
list = [
{ name: 'apples', amount: 3, price: 10 },
{ name: 'bananas', amount: 1, price: 3 },
{ name: 'mangos', amount: 5, price: 18 },
];
getItemWithPrice(index: number) {
//Some calculation before returning the item.
if (!this.list[index].total) this.list[index].total = this.list[index].amount * this.list[index].price;
return this.list[index];
}
}
const someList = new MyClass();
I would like to access this as an array like: someList[1];, which would return the value of someList.getItemWithPrice(1);.
In my use case the calculation is complex and there can be thousands of items, so I don't want to waste resources on making calculations that we don't need. (Otherwise I could've just calculated the prices up front and return an array with the results.)
I've been looking for ways to either extend Array or implement Iterator or even use Proxy, but I can't seem to make it work. I can make Proxy work, but it seems a bit hacky and I lose the constructor name of my original class. (Proxy is probably a decent fallback, but it seems it should be easier, knowing other languages that have magic methods, or IEnumerable interfaces, etc.)
While proxies can work, they're slow, weird, and can't be polyfilled for obsolete browsers. If I were you, I'd make an object with getters instead, by iterating over the numeric indicies of the original array.
const listData = [
{ name: 'apples', amount: 3, price: 10 },
{ name: 'bananas', amount: 1, price: 3 },
{ name: 'mangos', amount: 5, price: 18 },
];
const someList = Object.defineProperties({}, Object.fromEntries(
listData.map((item, i) => [i, {
configurable: true,
get() {
console.log('Performing calculations');
// Some calculation before returning the item.
item.total = item.amount * item.price;
// Set the property directly on the someList object, removing this getter
Object.defineProperty(someList, i, { value: item });
return item;
}
}])
));
console.log(someList[1]);
console.log(someList[2]);
console.log(someList[1]);
In TS, you'll need to declare the objects as possibly having a total property.
const listData: Array<{ name: string, amount: number, price: number, total?: number }> = [
I am new in this framework. I want to convert objects into array in angular 8. But I don't get how this work.
Actually, I want to display multiple sales transactions of the a customer with status false.
So, somehow I get the values of those transaction made by the same customer as a separate different objects.
Now, I want to convert those objects into a single array so that I can iterate them in html file through *ngFor.
export class InvoicesComponent implements OnInit {
displayedColumns: string[] = ['ProductName', 'CustomerName', 'Quantity',
'Rate', 'Total'];
id;
dataSource;
salesTransaction: SalesTransactionElement[];
constructor(private service: SalesTransactionsService,
private route: ActivatedRoute)
{ }
ngOnInit() {
this.id = this.route.snapshot.paramMap.get('id');
this.service.getSalesTransaction(this.id).subscribe((singleData: any) =>
{
this.service.getAllSalesTransactions().subscribe((data: any) =>
{
data.forEach(element =>
{
if (singleData.CustomerName === element.CustomerName &&
element.Status === false) {
this.salesTransaction = element;
console.log(this.salesTransaction);
}
});
});
}
Actual Results:
/*****Separately as two objects****/
{SalesTranId: 54, ProductId: 10, CustomerId: 21, InvoiceId: null, ProductName: "Asus"}
{SalesTranId: 51, ProductId: 17, CustomerId: 21, InvoiceId: 1, ProductName: "Dell"}
Expected Results:
/**********Array of Objects************/
[{SalesTranId: 54, ProductId: 10, CustomerId: 21, InvoiceId: null, ProductName: "Asus"},
{SalesTranId: 51, ProductId: 17, CustomerId: 21, InvoiceId: 1, ProductName: "Dell"}]
Initialize the array above the constructor: salesTransaction: SalesTransactionElement[] = []
Then push into that array in your forEach handler: this.salesTransaction.push(element);
Actually you are assigned an object in your array definition of SalesTransactionElement[] so you need to push a SalesTransactionElement.
export class InvoicesComponent implements OnInit {
displayedColumns: string[] = ['ProductName', 'CustomerName', 'Quantity',
'Rate', 'Total'];
id;
dataSource;
salesTransaction: SalesTransactionElement[];
constructor(private service: SalesTransactionsService,
private route: ActivatedRoute)
{ }
ngOnInit() {
this.id = this.route.snapshot.paramMap.get('id');
this.service.getSalesTransaction(this.id).subscribe((singleData: any) =>
{
this.service.getAllSalesTransactions().subscribe((data: any) =>
{
data.forEach(element =>
{
if (singleData.CustomerName === element.CustomerName &&
element.Status === false) {
this.salesTransaction.push(element);
}
});
});
}
So I have a problem with my var array to add a new chapter, how would I go about this would I have to do this:
array.push({
chapter: [
{
id: 2,
title: 'adsf',
content: '',
authorNotes: 'asdf'
}
]
});
RiTest.ts
import * as mongoose from 'mongoose';
const Scheme = mongoose.Schema;
export const RiTestScheme = new Scheme({
novelName: String,
novelAuthor: String,
novelCoverArt: String,
novelTags: Array,
chapters: [
{
id: Number,
title: String,
content: String,
authorNotes: String
}
]
});
export class RiTestController {
public addChapter(callback: (data) => void) {
var chapterInfoModel = mongoose.model('ChaptersTest', RiTestScheme);
var array = [
{
chapter: [
{
id: 0,
title: 'prolog',
content: 'conetntt is empty',
authorNotes: 'nothing is said by author'
},
{
id: 1,
title: 'making a sword',
content: 'mine craft end chapter',
authorNotes: 'nothing'
}
]
}
];
let newChapterInfo = new chapterInfoModel(array);
newChapterInfo.save((err, book) => {
if (err) {
return callback(err);
} else if (!err) {
return callback(book);
}
});
}
}
This doesn't work, var array doesn't get saved into let newChapterInfo = new chapterInfoModel(array); what I am trying to do add another chapter to array.chapter but the array doesn't get recognized in the chapterInfoModel() how would I fix this array and add an item to the array to create a new entry into this existing collection
thank for taking your time to answer my question.
You are trying to insert array of document to your collections, That the reason its not inserting into your collection.
Document.prototype.save() will insert only one document to your collection depends on your definition. So to insert chapter here is the code below,
//array as Object
var array = {
chapter: [
{
id: 0,
title: 'prolog',
content: 'conetntt is empty',
authorNotes: 'nothing is said by author'
},
{
id: 1,
title: 'making a sword',
content: 'mine craft end chapter',
authorNotes: 'nothing'
}
]
};
//Push to your chapter array
array.chapter.push({
id: 2,
title: 'adsf',
content: '',
authorNotes: 'asdf'
});
let newChapterInfo = new chapterInfoModel(array);