Add text or heading between checkbox options - javascript

Right know I hace a Modal/Pop-up which shows a bunch of checkboxes, but I want to be able to put some headings or something such as that between some of them because some are part of one category and others not and there will be a lot of checkboxes and it will be really difficult to differenciate if I dont have something like that, the code I hace right know is the follwoing, thanks in advice :)
title: "This is a prompt with a set of checkbox inputs!",
inputType: 'checkbox',
inputOptions: [{
text: 'Choice One',
value: '1',
},
{
text: 'Choice Two',
value: '2',
},
{
text: 'Choice Three',
value: '3',
},
{
text: 'Choice One',
value: '1',
},
{
text: 'Choice Two',
value: '2',
},
{
text: 'Choice Three',
value: '3',
},
{
text: 'Choice One',
value: '1',
},
{
text: 'Choice Two',
value: '2',
},
{
text: 'Choice Three',
value: '3',
},
{
text: 'Choice One',
value: '1',
},
{
text: 'Choice Two',
value: '2',
},
{
text: 'Choice Three',
value: '3',
}],
callback: function (result) {
if(result){
$('#opcion1').val(result);
save();
window.location = base_url_admin+'record/reporte';
console.log(result);
}
}
});```

Related

How to filter a nested array of object by values and get root object

I have a json object as below:
[
{
name: 'data 1',
users: [
{
username: 'user 1',
full_name: 'name 1',
sources: [
{ type: 'type 1', name: 'source name 1' },
{ type: 'type 2', name: 'source name 2' },
],
},
{
username: 'user 2',
full_name: 'name 2',
sources: [
{ type: 'type 3', name: 'source name 3' },
{ type: 'type 4', name: 'source name 4' },
],
},
],
},
{
name: 'data 2',
users: [
{ username: 'user 3', full_name: 'name 3' },
{
username: 'user 4',
full_name: 'name 4',
sources: [
{ type: 'type 5', name: 'source name 3' },
{ type: 'type 6', name: 'source name 5' },
],
},
],
},
{
name: 'data 3',
users: [
{ username: 'user 5', full_name: 'name 5' },
{
username: 'user 6',
full_name: 'name 6',
sources: [
{ type: 'type 5', name: 'source name 6' },
{ type: 'type 6', name: 'source name 7' },
],
},
],
},
];
I need a function that filter data recursively by its all values.
For example when I type "data 1" it should return an array such as
[
{
name: 'data 1',
users: [
{
username: 'user 1',
full_name: 'name 1',
sources: [
{ type: 'type 1', name: 'source name 1' },
{ type: 'type 2', name: 'source name 2' },
],
},
{
username: 'user 2',
full_name: 'name 2',
sources: [
{ type: 'type 3', name: 'source name 3' },
{ type: 'type 4', name: 'source name 4' },
],
},
],
},
];
or if I type "source name 3" it should return both "data 1" and "data 2" objects as an array.
The json object may have more arrays or objects in its values. I have tried something like this but it returns all data instead of filtered data.
function search(data) {
return data.filter((data) => {
Object.values(data).some((value) =>
value.constructor.name === 'Array'
? search(value)
: value.constructor.name === 'Object'
? Object.values(value).some((innerValue) =>
innerValue.toString().toLowerCase().includes(searchValue)
)
: value.toString().toLowerCase().includes(searchValue)
);
});
}
If I had to do that by some specific key it would be easy but I have to filter dynamically by all keys. What should I do to filter a json object like this?
You could take an recursive approach. By having an object it iterates the values as well.
const
has = value => object => Object
.values(object)
.some(v => v === value || v && typeof v === 'object' && has(value)(v)),
filter = (array, value) => array.filter(has(value)),
data = [{ name: 'data 1', users: [{ username: 'user 1', full_name: 'name 1', sources: [{ type: 'type 1', name: 'source name 1' }, { type: 'type 2', name: 'source name 2' }] }, { username: 'user 2', full_name: 'name 2', sources: [{ type: 'type 3', name: 'source name 3' }, { type: 'type 4', name: 'source name 4' }] }] }, { name: 'data 2', users: [{ username: 'user 3', full_name: 'name 3' }, { username: 'user 4', full_name: 'name 4', sources: [{ type: 'type 5', name: 'source name 3' }, { type: 'type 6', name: 'source name 5' }] }] }, { name: 'data 3', users: [{ username: 'user 5', full_name: 'name 5' }, { username: 'user 6', full_name: 'name 6', sources: [ { type: 'type 5', name: 'source name 6' }, { type: 'type 6', name: 'source name 7' }] }] }];
console.log(filter(data, 'data 1'));
console.log(filter(data, 'source name 3'));
.as-console-wrapper { max-height: 100% !important; top: 0; }

How to pass tests correctly in Typescript?

The problem:
I'm trying to write a TypeScript function suitable for a previously written JEST test. There are 5 tests in total. The function I wrote passes all the tests, but unfortunately, I was asked to write again in the review. How to write this more efficiently?
Example case:
Imagine an array that contains folders. These folders can have files in it. move function moves a file to another folder and returns the new state of given list.
Example list:
const list = [
{
id: '1',
name: 'Folder 1',
files: [
{ id: '2', name: 'File 1' },
{ id: '3', name: 'File 2' },
{ id: '4', name: 'File 3' },
{ id: '5', name: 'File 4' },
],
},
{
id: '6',
name: 'Folder 2',
files: [{ id: '7', name: 'File 5' }],
},
]
If I run move(list, '4', '6') then I expect file with id 4 moved to the folder which has id 6. Function should return the new state below;
const result = [
{
id: '1',
name: 'Folder 1',
files: [
{ id: '2', name: 'File 1' },
{ id: '3', name: 'File 2' },
{ id: '5', name: 'File 4' },
],
},
{
id: '6',
name: 'Folder 2',
files: [
{ id: '7', name: 'File 5' },
{ id: '4', name: 'File 3' },
],
},
]
move.ts
type File = {
id: string;
name: string;
};
type Folder = {
id: string;
name: string;
files: File[];
};
type List = Folder[];
export default function move(list: List, source: string, destination: string): List {
let sourceFileIndex = -1;
let sourceFolderIndex = -1;
let destinationFolderIndex = -1;
for (let i = 0; i < list.length; i += 1) {
const { id, files } = list[i];
if (id === source) {
throw new Error('You cannot move a folder');
}
if (id === destination) {
destinationFolderIndex = i;
}
if (destinationFolderIndex > -1 && sourceFileIndex > -1) break;
for (let j = 0; j < files.length; j += 1) {
if (files[j].id === destination) {
throw new Error('You cannot specify a file as the destination');
}
if (files[j].id === source) {
sourceFileIndex = j;
sourceFolderIndex = i;
break;
}
}
}
if (destinationFolderIndex === -1) {
throw new Error('Given destination id did not match any folder');
}
if (sourceFolderIndex === -1) {
throw new Error('Given source id of file was not found in any folder');
}
list[destinationFolderIndex].files.push(
...list[sourceFolderIndex].files.splice(sourceFileIndex, 1),
);
return list;
}
move.spec.ts
import move from './move';
describe('move', () => {
it('moves given file to another folder', () => {
const list = [
{
id: '1',
name: 'Folder 1',
files: [
{ id: '2', name: 'File 1' },
{ id: '3', name: 'File 2' },
{ id: '4', name: 'File 3' },
{ id: '5', name: 'File 4' },
],
},
{
id: '6',
name: 'Folder 2',
files: [{ id: '7', name: 'File 5' }],
},
];
const result = [
{
id: '1',
name: 'Folder 1',
files: [
{ id: '2', name: 'File 1' },
{ id: '3', name: 'File 2' },
{ id: '5', name: 'File 4' },
],
},
{
id: '6',
name: 'Folder 2',
files: [
{ id: '7', name: 'File 5' },
{ id: '4', name: 'File 3' },
],
},
];
expect(move(list, '4', '6')).toStrictEqual(result);
});
it('throws error if given source is not a file', () => {
const list = [
{
id: '1',
name: 'Folder 1',
files: [{ id: '2', name: 'File 1' }],
},
{ id: '3', name: 'Folder 2', files: [] },
];
expect(() => move(list, '3', '1')).toThrow('You cannot move a folder');
});
it('throws error if given destination is not a folder', () => {
const list = [
{
id: '1',
name: 'Folder 1',
files: [{ id: '2', name: 'File 1' }],
},
{ id: '3', name: 'Folder 2', files: [{ id: '4', name: 'File 2' }] },
];
expect(() => move(list, '2', '4')).toThrow('You cannot specify a file as the destination');
});
it('throws error if given source was not found', () => {
const list = [
{
id: '1',
name: 'Folder 1',
files: [
{ id: '2', name: 'File 1' },
{ id: '3', name: 'File 2' },
{ id: '4', name: 'File 3' },
{ id: '5', name: 'File 4' },
],
},
{
id: '6',
name: 'Folder 2',
files: [{ id: '7', name: 'File 5' }],
},
];
expect(() => move(list, '9', '6')).toThrow(
'Given source id of file was not found in any folder',
);
});
it('throws error if given destination was not found', () => {
const list = [
{
id: '1',
name: 'Folder 1',
files: [
{ id: '2', name: 'File 1' },
{ id: '3', name: 'File 2' },
{ id: '4', name: 'File 3' },
{ id: '5', name: 'File 4' },
],
},
{
id: '6',
name: 'Folder 2',
files: [{ id: '7', name: 'File 5' }],
},
];
expect(() => move(list, '4', '9')).toThrow('Given destination id did not match any folder');
});
});
As I said, it passed 5 tests but was not accepted. What is the problem?

Changing nested object's structure

I want to convert an object from one format to another. So far my attempts at doing this recursively failed; either I'm getting a maximum stack exception or I'm unable to iterate over all paths.
Let's assume we have an object that lists questions and their answers. There may be N questions and M answers.
Object at start:
var before = {
item: 'Question 1',
id: '1',
type: 'Question',
items: [
{
item: 'Answer 1',
id: '1.1',
type: 'Answer',
items:
[
{
item: 'Question 2',
id: '1.1.1',
type: 'Question',
items: [
{
item: 'Answer 2.1',
id: '1.1.1.1',
type: 'Answer'
},
{
item: 'Answer 2.2',
id: '1.1.1.2',
type: 'Answer'
}
]
}
// ...
]
}, {
item: 'Answer 1',
id: '1.2',
type: 'Answer',
items:
[
{
item: 'Question 3',
id: '1.2.1',
type: 'Question',
items: [
{
item: 'Answer 3.1',
id: '1.2.1.1',
type: 'Answer'
},
{
item: 'Answer 3.2',
id: '1.2.1.2',
type: 'Answer'
}
]
}
// ...
]
}
// ...
]
}
Object how it should look like (wrap all in 'items' array; change key names 'item' to 'title', 'id' to 'key', remove 'type', add 'color' depending on 'type'):
var after = {
items: [
{
title: 'Question 1',
key: '1',
color: 'Red',
items: [
{
title: 'Answer 1',
key: '1.1',
color: 'Blue',
items:
[
{
title: 'Question 2',
key: '1.1.1',
color: 'Red',
items: [
{
title: 'Answer 2.1',
key: '1.1.1.1',
color: 'Blue'
},
{
title: 'Answer 2.2',
key: '1.1.1.2',
color: 'Blue'
}
]
}
// ...
]
}, {
title: 'Answer 1',
key: '1.2',
color: 'Blue',
items:
[
{
title: 'Question 3',
key: '1.2.1',
color: 'Red',
items: [
{
title: 'Answer 3.1',
key: '1.2.1.1',
color: 'Blue'
},
{
title: 'Answer 3.2',
key: '1.2.1.2',
color: 'Blue'
}
]
}
// ...
]
}
// ...
]
}
]
}
It seems easy enough, but I can't get it to work. This is how I tried to iterate:
function iter(o) {
for(let k in o) {
if (!(['item', 'items', 'id'].includes(k))) // My object contains a few more keys I don't want to go down further into
continue
if (o[k] !== null && typeof o[k] === 'object') {
iter(o[k]); // Max stack exception
return;
}
}
};
Thank you very much!
You could map the objects and rename the keys and map nested items.
const
iter = ({ item: title, id: key, type, items, ...o }) => ({
title,
key,
color: 'color' + key,
...o,
...(items && { items: items.map(iter) })
}),
before = { item: 'Question 1', id: '1', type: 'Question', items: [{ item: 'Answer 1', id: '1.1', type: 'Answer', items: [{ item: 'Question 2', id: '1.1.1', type: 'Question', items: [{ item: 'Answer 2.1', id: '1.1.1.1', type: 'Answer' }, { item: 'Answer 2.2', id: '1.1.1.2', type: 'Answer' }] }] }, { item: 'Answer 1', id: '1.2', type: 'Answer', items: [{ item: 'Question 3', id: '1.2.1', type: 'Question', items: [{ item: 'Answer 3.1', id: '1.2.1.1', type: 'Answer' }, { item: 'Answer 3.2', id: '1.2.1.2', type: 'Answer' }] }] }] },
result = [before].map(iter);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can achieve this using map, I wrote an simple test to show my point here
this is the important part of the code
function rename(item: any) {
return {
title: item.item,
key: item.id,
color: item.type === 'Question' ? 'red' : 'blue',
items: item.items?.map(rename)
}
}
console.log(items.map(rename))
Of course if you're using typescript, change any to the appropriate type and pay attention that I'm using ? operator which will not work with javascript, so you could do something like
...
items: item.items ? item.items.map(rename) : undefined
...

Need help for assigning a variable with discord bot command

so I am trying to build my own discord bot with discord.js. There is one really important thing that I want to achieve.
I want to reassign a variable through a bot command. My current code looks like this:
client.on("message", (msg) => {
if (msg.content.startsWith(config.prefix + "boosting")) {
const embed = new Discord.MessageEmbed()
.setColor("0xd08d11")
.setTitle("**Random Title**")
.setDescription(Some description)
.addFields(
{ name: '\u200B', value: '\u200B' }, //spacer
{ name: "Person 0", value: 'Personvalue', inline: true },
{ name: '\u200B', value: '\u200B' }, //spacer
{ name: 'Price', value: 'Pricevalue', inline: true },
{ name: '\u200B', value: '\u200B' }, //spacer
{ name: 'Person 1', value: '40k', inline: true },
{ name: 'Person 2', value: '40k', inline: true },
{ name: 'Person 3', value: '40k', inline: true },
{ name: 'Person 4', value: '40k', inline: true },
)
.setThumbnail(logo)
.setTimestamp()
.setFooter('created by me or something like that');
client.channels.cache.get(`here_is_my_channel_id`).send(embed);
}
});
client.login(config.token)
Okay, so right now I can type .boosting to get an embed message from my bot, but the thing is, that i want to type .boosting Variable1 Variable2 and so on to give new values to the attributes of the embed message. And with attributes I mean something like the description or the fields name or values. I tried something like this:
let Variable = "Test";
client.on("message", (msg) => {
if (msg.content.startsWith(config.prefix + "boosting" + " " + Variable)) {
const embed = new Discord.MessageEmbed()
.setColor("0xd08d11")
.setTitle("**Random Title**")
.setDescription(Variable)
.addFields(
{ name: '\u200B', value: '\u200B' }, //spacer
{ name: "Person 0", value: 'Personvalue', inline: true },
{ name: '\u200B', value: '\u200B' }, //spacer
{ name: 'Price', value: 'Pricevalue', inline: true },
{ name: '\u200B', value: '\u200B' }, //spacer
{ name: 'Person 1', value: '40k', inline: true },
{ name: 'Person 2', value: '40k', inline: true },
{ name: 'Person 3', value: '40k', inline: true },
{ name: 'Person 4', value: '40k', inline: true },
)
.setThumbnail(logo)
.setTimestamp()
.setFooter('created by me or something like that');
client.channels.cache.get(`here_is_my_channel_id`).send(embed);
}
});
client.login(config.token)
Now I can write .boosting Test and the description of this embed message will have this as it's value.
I know that I need to define the variable, but is there any possibility to reassign it with a bot command? So it can change from the value "Test" to "something" for example. Appreciate every help!
You can split your the message into an array of words:
const args = message.content.slice(config.prefix.length).split(/ +/).slice(1)
// example: `.boosting hello people of the world`
// returns: ['hello', 'people', 'of', 'the', 'world']
So, if you'd like to get the first argument (word), you can use args[0]. For the second, args[1], and so on.
You updated code:
client.on("message", (msg) => {
if (msg.content.startsWith(config.prefix + "boosting" + " " + Variable)) {
const args = message.content.slice(config.prefix.length).split(/ +/).slice(1)
const embed = new Discord.MessageEmbed()
.setColor("0xd08d11")
.setTitle("**Random Title**")
.setDescription(args[0])
.addFields(
{ name: '\u200B', value: '\u200B' }, //spacer
{ name: "Person 0", value: 'Personvalue', inline: true },
{ name: '\u200B', value: '\u200B' }, //spacer
{ name: 'Price', value: 'Pricevalue', inline: true },
{ name: '\u200B', value: '\u200B' }, //spacer
{ name: 'Person 1', value: '40k', inline: true },
{ name: 'Person 2', value: '40k', inline: true },
{ name: 'Person 3', value: '40k', inline: true },
{ name: 'Person 4', value: '40k', inline: true },
)
.setThumbnail(logo)
.setTimestamp()
.setFooter('created by me or something like that');
client.channels.cache.get(`here_is_my_channel_id`).send(embed);
}
});
client.login(config.token)

bootbox custom dialog with both radio and select inputs

I'm trying to understand if it's possible to place a select input on the right of a radio input in a custom bootbox dialog. Example:
bootbox.prompt({
title: "This is a prompt with a set of radio inputs!",
message: '<p>Please select an option below:</p>',
inputType: 'radio',
inputOptions: [
{
text: 'Choice One',
value: '1',
},
{
text: 'Choice Two',
value: '2',
},
{
text: 'Choice Three',
value: '3',
}
],
callback: function (result) {
console.log(result);
}
});
This will show three radio items.
I want to place on the right of, say, 'Choice Two' a select:
inputType: 'select',
inputOptions: [
{
text: 'Choose one...',
value: '',
},
{
text: 'Choice One',
value: '1',
}]
But I don't understand if this is possible with bootbox.

Categories