How do I return specific field of nested object array in angular having fields value? - arrays

I have an nested object array like this.
here is my array:
public collections: ICollections[] = [
{
collectionName: 'Brands',
collectionFields: [
{
columnTitle : 'brandTitle',
Type : dtEnum.string,
control: {
controlTitle: controlsEnum.input,
controlType: controlsEnum.input,
controlProperties:
{
placeholder: 'Enter brand title here ...',
type: 'text',
autocomplete: false,
}
},
columnWidth: 200
}
],
collectionFieldValidation: [{name: 'test'}],
hasPaginator: true,
stickyColumn: 0,
stickyHeader: true
},
{
columnTitle : 'brandURL',
Type : dtEnum.string,
control: {
controlTitle: controlsEnum.input,
controlType: controlsEnum.input,
controlProperties: {
placeHolder: 'Enter Brand URL',
type: 'text',
autocomplete: false,
}
},
columnWidth: 300
},
{
columnTitle : 'brandDescription',
Type : dtEnum.string,
control: {
controlTitle: controlsEnum.textarea,
controlType: controlsEnum.textarea,
controlProperties: {
placeHolder: 'Enter Brand Description',
type: 'text',
autocomplete: false,
}
},
columnWidth: 300
}
];
I want to reach to placeholder field. how do I find it by having only collectionName field with Brands value and columnTitle field with brandURL value ?
this question asked before just with collectionName field value but I find out that my filter should include more than one field.

first of all, find the collection that corresponds to "Brands" or any other thing:
let result = collections.find(p => p.collectionName === "Brands");
then get the placeholder field:
change your_index to 0 or your specific index
if (result) {
let placeholder = result.collectionFields[your_index].control.controlProperties.placeholder;
}

Here is my solution :
placeholder_finder(collectionSearchKey: string, fieldSearchKey: string): string {
let field: any;
let placeholder: string;
const obj = this.genInfo.collections.filter(
x => x.collectionName === collectionSearchKey
);
obj.forEach(data => {
field = data.collectionFields.filter(
x => x.columnTitle === fieldSearchKey
);
});
field.forEach(element => {
placeholder = element.control.controlProperties.placeHolder;
});
return placeholder;
}

Related

Tell me how to correctly add values ​to display in the table

I have such an object
the "from" field and the "to" field are responsible for the date (shows the value for the selected date period).
the currency field shows the default currency from which other currencies are converted.
field enter currency - (my test field which is not needed yet).
field value is the value of my currency.
my currencies are stored in Manage Currencies
I want to use as many currencies as possible
but I don't know how to do it right because if I continue to add currencies through Manage Currencies, I will have to correct the code as well, because my table filling looks like this:
<template if:true={data}>
<lightning-datatable
key-field="id"
hide-checkbox-column
data={data}
columns={columns}>
</lightning-datatable>
</template>
____________________________________________________________
#track columns = [
{ label: 'Date', fieldName: 'key'},
{ label: 'USD', fieldName: 'USD', type: 'currency' },
{ label: 'CAD', fieldName: 'CAD', type: 'currency' },
{ label: 'EUR', fieldName: 'EUR', type: 'currency' },
{ label: 'GBP', fieldName: 'GBP', type: 'currency' },
{ label: 'KZT', fieldName: 'KZT', type: 'currency' },
{ label: 'BYN', fieldName: 'BYN', type: 'currency' },
];
getExchangeRates({baseCurrency : this.defaultCurrency, dateFrom : this.dateFrom, dateTo : this.dateTo, value : this.defaultValueSelectedCurrency})
.then(resultJSON => {
let result = JSON.parse(resultJSON);
let recordsByDates = result.rates;
console.log('Test result 2');
console.log(recordsByDates);
this.data = [];
for (var key in recordsByDates) {
let record = {
key: key,
date : recordsByDates[key].date,
USD : recordsByDates[key].USD,
CAD : recordsByDates[key].CAD,
EUR : recordsByDates[key].EUR,
GBP : recordsByDates[key].GBP,
BYN : recordsByDates[key].BYN,
KZT : recordsByDates[key].KZT
}
this.data.push(record);
}
console.log(record);
console.log(this.data);
})
.catch(error => {
this.error = error;
console.log(error);
});
and it will look terrible:

React Material-UI: Populating Rows in DataGrid returns undefined

In my React application, I want to fill the rows of a Material-UI Data Grid with backend data.
To achieve this, I make a GET request to the backend, which returns an AxiosResponse containing the data.
This AxiosResponse, I store in a variable named list, using useState().
Afterwards, I iterate over list to map the data to an Array of Objects, named testrows.
In the return method with DataGrid, I want to set property row to testrows.
However on rendering, it returns an error saying that testrow is undefined.
What am I doing wrong here?
import ...
export default function FruitList() {
const [list, setList] = useState<AxiosResponse>();
const columns: GridColDef[] = [
{
field: 'id',
headerName: 'Fruit ID',
type: 'number',
},
{
field: 'type',
headerName: 'Fruit Type',
type: 'string',
},
{
field: 'harvest',
headerName: 'Harvest Date',
type: "date",
},
{
field: 'entryDate',
headerName: 'Entry Date',
type: "date",
},
];
// Get list of fruits and store in variable "list"
useEffect(() => {
axios.get('http://localhost:3000/v1/fruit/'
.then(result => {
setList(result);
})
}, [])
let testrows = list?.data.map((element: { id: any, type: any, harvest: any, entryDate: any }) => {
return {
id: element.id,
type: element.type,
harvest: element.harvest,
entryDate: element.entryDate
}
}
);
// also tried useMemo:
const testrows = useMemo(() =>
list?.data.map((element: { id: any, type: any, harvest: any, entryDate: any }) => {
return {
id: element.id,
type: element.type,
harvest: element.harvest,
entryDate: element.entryDate
}
}),
[list?.data]
);
// console output: "test: undefined"
console.log("test: ", testrows);
return (
<div>
<div>
<DataGrid
rows={testrows}
columns={columns}
/>
</div>
</div>
);
}

discord.js - validate embed?

I want to validate a discord embed before sending it.
Which means, I want to know if an embed has nothing wrong with it before actually sending it on a channel.
var embed = {
title: 'some title',
description: 'some description',
color: 'foo bar'
}
// embed.color is not a valid color, so it will trigger an error when I send it.
// Here I want some way to know that there's something wrong with the embed object.
message.channel.send({embed});
I have made a function to validate embeds. However, it's incomplete and may have false positives or false negatives, but it should meet your needs.
function validURL(url) {
try {
new URL(url);
} catch (err) {
return false;
}
return true;
}
function validEmbed(embed) {
return Object.entries({
title: (title) => typeof title === 'string',
description: (description) => typeof description === 'string',
url: (url) => validURL(url),
timestamp: (timestamp) => (new Date(timestamp)).getTime() > 0,
color: (color) => typeof color === 'number',
fields: (fields) => fields.every(field => typeof field.name === 'string' && typeof field.value === 'string' && typeof field.inline === 'boolean'),
thumbnail: (thumbnail) => validURL(thumbnail.url),
image: (image) => validURL(image.url),
author: (author) => typeof author.name === 'string' && validURL(author.url) && validURL(author.icon_url),
footer: (footer) => typeof footer.text === 'string' && validURL(footer.icon_url)
}).every(field => {
if (!(field[0] in embed)) return true;
return embed[field[0]] && field[1](embed[field[0]]);
});
}
Here is an exaple snippet:
function validURL(e){try{new URL(e)}catch(e){return!1}return!0}function validEmbed(e){return Object.entries({title:e=>"string"==typeof e,description:e=>"string"==typeof e,url:e=>validURL(e),timestamp:e=>new Date(e).getTime()>0,color:e=>"number"==typeof e,fields:e=>e.every(e=>"string"==typeof e.name&&"string"==typeof e.value&&"boolean"==typeof e.inline),thumbnail:e=>validURL(e.url),image:e=>validURL(e.url),author:e=>"string"==typeof e.name&&validURL(e.url)&&validURL(e.icon_url),footer:e=>"string"==typeof e.text&&validURL(e.icon_url)}).every(t=>!(t[0]in e)||e[t[0]]&&t[1](e[t[0]]))}
/* returns true */
console.log(validEmbed({
title: 'The title'
}));
/* returns true */
console.log(validEmbed({
title: 'The title',
description: 'Sample Description.',
url: 'https://i.imgur.com/ttHwmCl.jpg',
timestamp: '2020-07-30T14:44:05.876Z',
color: 3447003,
fields: [{
name: 'name',
value: 'value',
inline: false
},
{
name: 'name2',
value: 'value2',
inline: true
}
],
thumbnail: {
url: 'attachment://stackoverflow2.jpg'
},
image: {
url: 'attachment://stackoverflow.jpg'
},
author: {
name: 'Daemon Beast',
url: 'https://i.imgur.com/P4L260P.jpg',
icon_url: 'https://i.imgur.com/P4L260P.jpg'
},
footer: {
text: 'footer text',
icon_url: 'https://i.imgur.com/ttHwmCl.jpg'
}
}));
/* returns false */
console.log(validEmbed({
author: 4567876567
}));

Typescript - Check values in one array are present in another

I have the following array. I am using this array to dynamically produce checkboxes on my UI. This is being used to save user config as to what they will be able to see in a nav menu.
accessLevels: any = [
{
description: "Properties",
type: '1',
selected: false
},
{
description: "Equipment",
type: '2',
selected: false
},
{
description: "Jobs",
type: '3',
selected: false
},
{
description: "Calender",
type: '4',
selected: false
}
]
I am making a call to an API which returns me an array of the users config. So what I will get is an array of the pages and their type like this:
{
description: "Equipment",
type: '2'
},
{
description: "Jobs",
type: '3'
}
In the array returned from the API I am just getting the values that should appear checked on the check boxes so what I want to do is loop through the returned array and check if any of the types match any types in the checkbox array if they do I want to set 'selected' to true. Thus checking the checkbox.
Here is what I have so far:
async loadLandlordConfig(key: string) {
const result = await this.userService.loadLandlordConfig(key);
//let accessLevels = [];
this.selectedApiValues = result[0].accessLevels;
this.selectedApiValues.forEach((selectedValue)=> {
});
}
Im not sure how to cross check the values and then change selected to true.
Hope I have made everything clear enough.
Any questions please ask. All help appreciated.
const accessLevels: any[] = [
{
description: 'Properties',
type: '1',
selected: false
},
{
description: 'Equipment',
type: '2',
selected: false
},
{
description: 'Jobs',
type: '3',
selected: false
},
{
description: 'Calender',
type: '4',
selected: false
}];
const results: any[] = [
{
description: 'Equipment',
type: '2'
},
{
description: 'Jobs',
type: '3'
}];
accessLevels.forEach(accessLevel => {
accessLevel.selected = results.some(x => x.type === accessLevel.type); });
For small arrays
You can check for the existence within a filter using some:
const intersect = this.array1.filter(a1 =>
this.array2.some(a2 => a1.type === a2.type));
The problem with this is that you are doing multiple loops through array 2.
For larger arrays
To keep your loops to a constant number, you could create a map of one of your arrays, and check that within a filter of the other array:
const map2 = new Map(this.array2.map(x => [x.type, s]));
const intersect = this.array1.filter(a1 =>
map.has(a1.type));
This adds a little bit of complexity, but is more efficient for all but the simplest cases.
You can achieve what you want with the following simple example :
let accessLevels = [
{
description: "Properties",
type: '1',
selected: false
},
{
description: "Equipment",
type: '2',
selected: false
},
{
description: "Jobs",
type: '3',
selected: false
},
{
description: "Calender",
value: '4',
selected: false
}
]
let api = [
{
description: "Equipment",
type: '2'
},
{
description: "Jobs",
value: '3'
}
];
for(var i = 0; i < accessLevels.length; i++) {
accessLevels[i].selected = api.find(e => e.description === accessLevels[i].description) ? true : false;
}
console.log(accessLevels);
You can use Map collection to have O(1) while mapping the second array:
const unique = new Map(received.map(s => [s.description, s]));
const result = accessLevels.map(({ description, type})=>
({selected: (unique.get(description) ? true : false), type, description}))
An example:
let accessLevels = [
{
description: "Properties",
type: '1',
selected: false
},
{
description: "Equipment",
type: '2',
selected: false
},
{
description: "Jobs",
type: '3',
selected: false
},
{
description: "Calender",
type: '4',
selected: false
}
]
const received = [
{
description: "Equipment",
type: '2'
},
{
description: "Jobs",
value: '3'
}
];
const unique = new Map(received.map(s => [s.description, s]));
const result = accessLevels.map(({ description, type})=>
({selected: (unique.get(description) ? true : false), type, description}))
console.log(result);
I've made some changes to your code. Here's how it looks like:
async loadLandlordConfig(key: string) {
const result = await this.userService.loadLandlordConfig(key);
// assuming there's always a result.
// ACCESS_LEVELS is the list of your config.
accessLevels = result[0].accessLevels;
this.selectedApiValues = ACCESS_LEVELS.map((al: any) => {
const selected = accessLevels.findIndex(a => a.type === al.type) > -1;
return { ...al, selected }
})
}
This will give you with the value
this.selectedApiValues = [
{
description: "Properties",
type: '1',
selected: false
},
{
description: "Equipment",
type: '2',
selected: true
},
{
description: "Jobs",
type: '3',
selected: true
},
{
description: "Calender",
type: '4',
selected: false
}
]

kendo ui: how to remove a dataItem of a dataSource bound to some comboBox, inside combobox dataBound event

I have a grid, inside of some column of which I have created a combobox editing UI, using columns.editor function.
My goal is every time a user selects some value from the combobox -while populating a newly created grid record-, this value to be
removed from the list options of a next record's combobox.
One of the things i've tried is shown below:
function equipmentDropDownEditor(container, options) {
var equipmentComboBox = $('<input id="equipmentDropDownEditor" required data-text-field="name" data-value-field="name" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoComboBox({
autoBind: false,
dataSource: equipmentTypesDS,
dataBound: function(e) {
var equipmentData = e.sender.dataSource.data();
if(currentlyInsertedEquipmentTypes.length > 0){
for(var i=0;i<currentlyInsertedEquipmentTypes.length;i++){
$.each( equipmentData, function( index, selectedEquipmentData ) {
if (selectedEquipmentData.name == currentlyInsertedEquipmentTypes[i]){
var dataItem = e.sender.dataSource.at(index);
console.log("dataItem: " + dataItem.name + " is being removed");
e.sender.dataSource.remove(dataItem);
}
});
}
}
}
});
}
I've created a global array variable named "currentlyInsertedEquipmentTypes" inside of which I hold all the user's already selected values
(for example if the user has created 2 records inside the grid and has selected "laptop" option in the combobox of the first and "workstation" option
in the combobox of the second --> currentlyInsertedEquipmentTypes = ["laptop", "workstation"] ).
Inside the combobox dataBound event I check whether the user has already selected values (currentlyInsertedEquipmentTypes.length>0)
and if he has, I locate the corresponding object inside the bound dataSource and I remove it, so that it wont be available in the next record's combobox list.
This is where the whole thing crashes even though the data item removal takes place.
Am i missing something that i should do after the data item removal? Should i rebind the datasource to the combobox in some way?
Any help would be much appreciated.
[EDIT]
---- The combobox datasource code
var equipmentTypesDS= new kendo.data.DataSource({
transport: {
read: {
url: "api/equipment_types",
type: "GET",
data: {
//"equipment_category": 1
},
dataType: "json"
}
},
schema: {
data: "data",
total: "total"
}
});
--- the kendo grid code:
$("#popup_equipment").kendoGrid({
dataSource: {
schema:{
model:{
id: "equipment_type_id",
fields:{
equipment_type_id: { editable: false },
name: { }, //validation: {required: true}, defaultValue: "LAPTOP",
items:{ type: "number", defaultValue:1, validation: { required: true, min: 1} }
}
}
}
},
toolbar: ["create"],
columns: [
{ field: "name", title: "εξοπλισμός", width: "300px", editor: equipmentDropDownEditor, template: "#=name#" },
{ field: "items", title:"πλήθος", width: "80px"},
{ command: ["destroy"], title: " ", width: "100px" }
],
//editable: "inline",//true,
editable:{confirmation: false},
scrollable: false,
selectable: false
});
[EDIT 2]
$("#popup_equipment").kendoGrid({
dataSource: {
schema:{
model:{
id: "equipment_type_id",
fields:{
equipment_type_id: { editable: false },
name: { }, //validation: {required: true}, defaultValue: "LAPTOP",
items:{ type: "number", defaultValue:1, validation: { required: true, min: 1} }
}
}
}
},
toolbar: ["create"],
columns: [
{ field: "name", title: "εξοπλισμός", width: "60%", editor: equipmentDropDownEditor, template: "#=name#" },
{ field: "items", title:"πλήθος", width: "20%"},
{ command: ["destroy"], title: " ", width: "20%" }
],
editable:{confirmation: false},
scrollable: false,
selectable: false,
save: function(e){
console.log("GRID SAVE EVENT! ", e);
var equipment_name = e.values.name;
equipmentTypesDS.get(equipment_name).used = true;
console.log("equipmentTypesDS", equipmentTypesDS);
console.log("END OF GRID SAVE EVENT!");
}
});
function equipmentDropDownEditor(container, options) {
var equipmentComboBox = $('<input id="equipmentDropDownEditor" required data-text-field="name" data-value-field="name" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoComboBox({
autoBind: false,
dataSource: equipmentTypesDS,
});
}
var equipmentTypesDS= new kendo.data.DataSource({
transport: {
read: {
url: "api/equipment_types",
type: "GET",
data: {
//"equipment_category": 1
},
dataType: "json"
}
},
schema: {
data: "data",
total: "total",
model:{
id: "name"
}
},
filter: { field: "used", operator: "neq", value: true }
});
I would suggest a different approach. Instead of removing the element filter it out.
Example: I define a DataSource with a list of Cities (your Inserted Equipment) as follow:
var cityDS = new kendo.data.DataSource ({
data : [
{ City : "Seattle", used : false },
{ City : "Tacoma", used : false },
{ City : "Kirkland", used : false },
{ City : "Redmond", used : false },
{ City : "London", used : false },
{ City : "Philadelphia", used : false },
{ City : "New York", used : false },
{ City : "Boston", used : false }
],
schema : {
model : {
id : "City"
}
},
filter: { field: "used", operator: "eq", value: false }
});
As you can see I added a field called used that simply says if that City is already used or not. And I set it as id of this DataSource. In addition, I set a filter saying that I only want those where used id equal (eq) to false.
The editor function is pretty much yours:
function cityDropDownEditor(container, options) {
var equipmentComboBox = $('<input required data-text-field="City" data-value-field="City" data-bind="value:' + options.field + '"/>')
.appendTo(container)
.kendoComboBox({
autoBind: false,
dataSource: cityDS
});
}
but with no dataBound or any other event handler.
Finally in the Grid when I save a record, I filter that city from the list. Something like:
var grid = $("#grid").kendoGrid({
dataSource: ds,
editable : "popup",
pageable : true,
toolbar: [ "create" ],
columns :
[
{ field: "FirstName", width: 90, title: "First Name" },
{ field: "LastName", width: 200, title: "Last Name" },
{ field: "City", width: 200, editor : cityDropDownEditor }
],
save : function(e) {
console.log("e", e);
var city = e.model.City;
cityDS.get(city).used = true;
}
}).data("kendoGrid");
This might work if you start the Grid with no elements otherwise you would have to conveniently initialize the used field. It might require some additional code dealing with cases as changing the City but from your description, doesn't seem to be the case.
You can see this running here : http://jsfiddle.net/OnaBai/ZH4aD/

Resources