This is suppose to look at the users category selection and then update the subcategory. The solution was recommended by someone else but I can't seem to get it to work. When I select the category, subcategory doesn't update. Can someone let me know what I'm missing.
Path: category.js
<template name="category">
{{#autoForm collection="Meteor.users" id="categoryForm" doc=currentUser type="update"}}
{{> afQuickField name='profile.categories'}}
{{/autoForm}}
</template>
Path: Schema.js
var fruitArr = ['apple', 'banana'];
var vegetablesArr = ['carrot', 'broccoli'];
Schema.Category = new SimpleSchema({
category: {
type: String,
label: "Category",
allowedValues: ['fruit', 'vegetables']
},
subcategory: {
type: String,
label: "Subcategory",
allowedValues: _.union(fruitArr, vegetablesArr),
autoform: {
options: function () {
let category = AutoForm.getFieldValue("category");
if (!category) return [{label: "Please select a category first", value: ""}];
if (category === "fruit") return _.map(fruitArr, (v, i) => ({
label: "Fruit " + (i + 1) + ": " + v,
value: v
}));
else return _.map(vegetablesArr, (v, i) => ({label: "Vegetables " + (i + 1) + ": " + v, value: v}));
}
}
}
});
Schema.UserProfile = new SimpleSchema({
categories: {
type: Schema.Category,
optional: true,
}
});
When calling AutoForm.getFormValues('categoryForm'); in the browser's console log, the following result will be returned:
{
"insertDoc":{
"profile":{
"categories":{
"category":"fruit"
}
}
},
"updateDoc":{
"$set":{
"profile.categories.category":"fruit"
},
"$unset":{
"profile.categories.subcategory":""
}
}
}
As you can see from above, the schema field subcategory is referenced as profile.categories.subcategory. Therefore, the field subcategory won't be updated because AutoForm.getFieldValue("category"); returns undefined.
You can fix this error by changing
let category = AutoForm.getFieldValue("category");
to
let category = AutoForm.getFieldValue("profile.categories.category");
inside your options function in the subcategory schema field.
Related
I want to send this data as one embed message and I don't know how many of these we have.
I tried to do like this :
let list = hk;
var id = "";
var username = "";
var identifier = ""
for (var i = 0; i < list.length; i++) {
id += list[i].id + '\n';
username += list[i].user_name + '\n';
identifier += list[i].identifier + '\n';
}
const pListEmbed = new Discord.MessageEmbed()
.setColor('#03fc41')
.setTitle('Connected')
.setDescription(`Total : ${list.length}`)
.setThumbnail(config.logo)
.addFields({ name: 'ID', value: id, inline: true }, { name: 'Name', value: username, inline: true }, { name: 'Identifier', value: identifier, inline: true },
)
.setTimestamp(new Date())
.setFooter('Used by: ' + message.author.tag, `${config.SERVER_LOGO}`);
message.channel.send(pListEmbed);
});
but it sends several separate embed messages, each containing the data
and hk is this array that we don't know how many of the data we have
array :
[
{
id: '46892319372',
user_name: 'testerOne',
identifier: '20202'
}
]
[
{
id: '15243879678',
user_name: 'testerTwo',
identifier: '20201'
}
]
[
{
id: '02857428679',
user_name: 'testerThree',
identifier: '20203'
}
]
[
{
id: '65284759703',
user_name: 'testerFour',
identifier: '20204'
}
]
Simply use .forEach, that will loop over every single element and use the "addFields" method ->
// .setThumbnail()..
list.forEach(user => pListEmbed.addFields(
{ name: 'ID', value: user.id, inline: true },
{ name: 'Name', value: user.user_name, inline: true },
{ name: 'Identifier', value: user.identifier, inline: true }
))
message.reply({ embeds : [pListEmbed] })
you can map the array into the fields like this:
separate fields
.addFields(
array.flatMap(user => [
{ name: 'ID', value: user.id, inline: true },
{ name: 'Name', value: user.user_name, inline: true },
{ name: 'Identifier', value: user.identifier, inline: true }
])
)
single fields
.addFields(
array.flatMap(user => [
{ name: 'User', value: `${id + username + identifier}`, inline: true },
])
)
Why flatMap()?
flatMap() is an inbuilt function in JavaScript which is used to flatten the input array element into a new array. This method first of all map every element with the help of mapping function, then flattens the input array element into a new array.
This question already has answers here:
Group By Multiple Columns
(14 answers)
Closed 1 year ago.
I have 2 tables: OrderDetail and Product. I try to groupby IdProduct in OrderDetail table and retrieve ( Name in Product table, Quantity in OrderDetail). But I can't get the Name, only the key.
public ActionResult GetData()
{
DbCon db = new DbCon();
var query = db.OrderDetail.Include("Product")
.GroupBy(p => p.Product_Id)
.Select(g => new { name = g.Key ,count = g.Sum(w => w.Quanity) }).ToList();
return Json(query, JsonRequestBehavior.AllowGet);
}
//code highcharts
<script>
$(document).ready(function () {
$.getJSON("/Admin/Product/GetData", function (data) {
var Names = []
var Qts = []
for (var i = 0; i < data.length; i++) {
Names.push(data[i].name);
Qts.push(data[i].count);
}
Highcharts.chart('container', {
chart: {
type: 'line'
},
title: {
text: 'Thống kê các mặt hàng bán ra'
},
subtitle: {
text: ''
},
xAxis: {
categories: Names
},
yAxis: {
title: {
text: 'Số lượng bán ra'
}
},
plotOptions: {
line: {
dataLabels: {
enabled: true
},
enableMouseTracking: false
}
},
series: [{
name: 'Số lượng bán ra',
data: Qts
}]
});
});
});
</script>
Result:
enter image description here
To get the Product Name, you can apply GroupBy with Product_Id and ProductName as your Key.
The reason why GroupBy with Product_Id and ProductName but not ProductName as:
Id is a unique identifier.
Possible that Product Name will be duplicated in different products and leads to inaccurate calculation.
Next, retrieve the Product Name from Key.
var query = db.OrderDetail.Include("Product")
.GroupBy(p => new { p.Product_Id, ProductName = p.Name })
.Select(g => new {
name = g.Key.ProductName,
count = g.Sum(w => w.Quanity)
}).ToList();
I'm trying to transform an object contain array to another one with javascript. Below is an example of the object field and what the formatted one should look like.
let Fields = {
GAME: [
{ code: '{{PES}}', title: { en: "playPES"} },
{ code: '{{FIFA}}', title: { en: "playFIFA " } },
]
};
I need The new Fields to looks like this
let newFields = {
name: 'GAME',
tags:[
{ name: 'playPES', value: "{{PES}}" },
{ name: 'playFIFA', value: "{{FIFA}}" }
]},
One contributor suggested me a method like this but i think something need to modify in it but couldn't figure it out.
export const transform = (fields) => ({
tags: Object .entries (fields) .map (([name, innerFields]) => ({
name,
tags: innerFields.map(({code, title: title: {en})=>({name: en, value: code}))
}))
});
// newFields= transform(Fields)
I'm new working with javascript so any help is greatly appreciated, Thanks.
const transform = (o) => {
return Object.entries(o).map((e)=>({
name: e[0],
tags: e[1].map((k)=>({name: (k.title)?k.title.en:undefined, value: k.code}))
}))[0]
}
console.log(transform({
GAME: [
{ code: '{{PES}}', title: { en: "playPES"} },
{ code: '{{FIFA}}', title: { en: "playFIFA " } },
]
}))
Using the entries method you posted:
let Fields = {
GAME: [
{ code: '{{PES}}', title: { en: "playPES"} },
{ code: '{{FIFA}}', title: { en: "playFIFA " } },
]
};
// 1. Obtain keys and values from first object
Fields = Object.entries(oldFields);
// 2. Create new object
const newFields = {};
// 3. Create the name key value pair from new Fields array
newFields.name = Fields[0][0];
// 4. Create the tags key value pair by mapping the subarray in the new Fields array
newFields.tags = Fields[0][1].map(entry => ({ name: entry.title.en, value: entry.code }));
Object.entries(Fields) will return this:
[
"GAME",
[TagsArray]
]
And Object.entries(Fields).map will be mapping this values.
The first map, will receive only GAME, and not an array.
Change the code to something like this:
export const transform = (Fields) => {
const [name, tags] = Object.entries(Fields);
return {
name,
tags: tags.map(({ code, title }) => ({
name: title.en,
value: code
}))
}
}
Hope it help :)
let Fields = {
GAME: [
{ code: '{{PES}}', title: { en: "playPES"} },
{ code: '{{FIFA}}', title: { en: "playFIFA " } },
]
};
let newFields = {
name: 'GAME',
tags:[
{ name: 'playPES', value: "{{PES}}" },
{ name: 'playFIFA', value: "{{FIFA}}" }
]
}
let answer = {
name: "Game",
tags: [
]
}
Fields.GAME.map(i => {
var JSON = {
"name": i.title.en,
"value": i.code
}
answer.tags.push(JSON);
});
console.log(answer);
I think that this is more readable, but not easier... If you want the result as object you need to use reduce, because when you do this
Object.keys(Fields)
Your object transform to array, but reduce can change array to object back.
let Fields = {
GAME: [
{ code: '{{PES}}', title: { en: "playPES"} },
{ code: '{{FIFA}}', title: { en: "playFIFA " } },
]
};
const result = Object.keys(Fields).reduce((acc, rec) => {
return {
name: rec,
tags: Fields[rec].map(el => {
return {
name: el.title.en,
value: el.code
}
})
}
}, {})
console.log(result)
let Fields = {
GAME: [
{ code: '{{PES}}', title: { en: "playPES"} },
{ code: '{{FIFA}}', title: { en: "playFIFA " } },
]
};
const transform = (fields) => ({
tags: Object .entries (fields) .map (([name, innerFields]) => ({
name,
tags: innerFields.map(({code, title: title,en})=>({name: title.en, value: code}))
}))
});
//check required output in console
console.log(transform(Fields));
I am building a datatable and have added a checkbox dropdown for adding/removing columns in the table. Everything works fine except it is not rerendering the table until I click on one of the header titles.
At the top of the function component, I am setting the state as follows:
const [formColumns, setDisplayFields] = useState(formFields);
formFields is retrieved from a file and is formatted as below. It's an array of JSON column objects that looks like this:
[id: {
name: 'id',
label: 'Patient Id',
displayColumn: false,
displayOrder: 1,
},
firstName: {
name: 'firstName',
label: 'First Name*',
requiredErrorMsg: 'First name is required',
displayColumn: true,
displayOrder: 2,
},
middleName: {
name: 'middleName',
label: 'Middle Name',
displayColumn: false,
displayOrder: 0,
},
lastName: {
name: 'lastName',
label: 'Last Name*',
requiredErrorMsg: 'Last name is required',
displayColumn: true,
displayOrder: 0,
},
suffix: {
name: 'suffix',
label: 'Suffix',
displayColumn: false,
displayOrder: 0,
},
dob: {
name: 'dob',
label: 'Date of Birth*',
requiredErrorMsg: 'Birth date is required',
invalidErrorMsg: 'This is not a valid date',
displayColumn: true,
displayOrder: 3,
},
organization: {
name: 'organization',
label: 'Organization',
displayColumn: false,
displayOrder: 4,
},
]
There are actually more columns, but this should suffice for describing what I'm doing. The 'displayColumn' element is changed in an onChange event in the same component that displays the table (passes it as a prop into checkbox menu). Here's the onchange:
/**
* handleCheckboxSelect
* #param {string} colname
*/
var handleCheckboxSelect = (colname) =>
{
//return the index of the column checked/unchecked
var icol = getColumnIndex(formColumns, colname);
console.log('FOUND COLINDEX = ' + icol + '.');
if (icol > -1) {
//toggle the display parameter
formColumns[icol].displayColumn = (formColumns[icol].displayColumn === false);
//store the updated column in the column list
setDisplayFields(formColumns);
}
else {
console.log('checkbox colname = ' + colname);
}
}
As you can see, I am using state as required, and any time state changes, it should force a re-render. However, it's not. Is it because I am using an array of objects? If I pass a single column back and stroe that in state, would that fix the issue? I'm stumped. Any help would be greatly appreciated!
You are setting same formColumns reference on setDisplayFields which will not trigger re-render of the component. Try to copy formColumns to a new array and make changes on that array.
Try this -
var handleCheckboxSelect = (colname) =>
{
//create new array from existing one
let newColumns = [...formColumns];
var icol = getColumnIndex(newColumns, colname);
console.log('FOUND COLINDEX = ' + icol + '.');
if (icol > -1) {
//toggle the display parameter
newColumns[icol].displayColumn = (newColumns[icol].displayColumn === false);
//store the updated column in the column list
setDisplayFields(newColumns);
}
else {
console.log('checkbox colname = ' + colname);
}
}
I have created a somehow functional "deeply" nested array filtering functionality. This functionality displays car, which has a color "RED" assigned to them. However the cars, which "pass" the filter is the car, which only has 1 color assigned. How can ensure that arrays within arrays are being checked by the criteria? Would I require creating a loop within loop? The desired outcome would be that if criteria is set to "RED" it will also display the BMW and SUZUKI as these cars also have this color. Any help, suggestions or further links to other posts to achieve the desired outcome would be truly appreciated as I was not able to find anything very useful on my own. The post, which has been most useful has been this one - Filtering an array with a deeply nested array in JS Below I have attached the code snippet of my current code.
const myCars = [
{ name: "BMW",colour: ["White","Red","Black"] },
{ name: "AUDI",colour: ["Yellow","Silver"] },
{ name: "VW",colour: ["Purple","Gold"] },
{ name: "NISSAN",colour: ["White","Black"] },
{ name: "SUZUKI",colour: ["Red"] },
];
for (x in myCars) {
var keys = Object.keys(myCars[x])
var carSpec = myCars.filter(function(fltr) {
return (fltr.colour == "Red");
});
document.getElementById("show1").innerHTML += carSpec[x].name + " " + "has these colours - " + carSpec[x].colour + "<hr />";
}
<p>Car List.</p>
<p id="show"></p>
<p id="show1"></p>
You need to filter by an includes test over the colour array:
const myCars = [
{ name: "BMW",colour: ["White","Red","Black"] },
{ name: "AUDI",colour: ["Yellow","Silver"] },
{ name: "VW",colour: ["Purple","Gold"] },
{ name: "NISSAN",colour: ["White","Black"] },
{ name: "SUZUKI",colour: ["Red"] },
];
const show1 = document.getElementById("show1");
myCars
.filter(({ colour }) => colour.includes('Red'))
.forEach(({ name, colour }) => {
show1.innerHTML += name + " " + "has these colours - " + colour + "<hr />";
});
<p>Car List.</p>
<p id="show"></p>
<p id="show1"></p>
You can use reduce to get an array of cars which have are available in red , then use forEach to loop over it and display the text.
join will join all the contents of an array by the delimiter
const myCars = [{
name: "BMW",
colour: ["White", "Red", "Black"]
},
{
name: "AUDI",
colour: ["Yellow", "Silver"]
},
{
name: "VW",
colour: ["Purple", "Gold"]
},
{
name: "NISSAN",
colour: ["White", "Black"]
},
{
name: "SUZUKI",
colour: ["Red"]
},
];
let hasRed = myCars.reduce(function(acc, curr) {
if (curr.colour.indexOf('Red') !== -1) {
acc.push(curr)
}
return acc;
}, []).forEach((item) => {
document.getElementById("show1").innerHTML += item.name + " " + "has these colours - " + item.colour.join(',') + "<hr />";
})
<p>Car List.</p>
<p id="show"></p>
<p id="show1"></p>