Insert variable Javascript in a Choices input object - javascript

Question is simple.
I have a form made with choices.js
For create a multiple select, I use this code (from Choices Github)
var multipleCancelButton2 = new Choices('#choices-sites', {
removeItemButton: true,
choices: [
{value: 'Child ', label: 'Child ', selected: false},
{value: 'Child site', label: 'Child ', disabled: true},
{value: 'Child Three', label: 'Child Three'},
],
Edit information about (it is my code):
$.each(hotels, function(i, item) {
var myObject = { value: item.name, label: item.name, selected: 'false' };
choicesJsonh.push(myObject);
});
var textRemove = new Choices('#choices-hotels', {
editItems: true,
removeItemButton: true,
choices: choicesJsonh,
});

The contents of the choices array is not a string. Don't try to treat it as a string!
If you want to create a new object then:
var myObject = { value: item.name, label item.name, selected: false };
If you want to add that to an array then:
myArray.push(myObject);
You can combine the two statements:
myArray.push({ value: item.name, label item.name, selected: false });
Then put the array itself into the object you pass to the Choices function:
var multipleCancelButton = new Choices('#choices-hotels', {
removeItemButton: true,
choices: myArray,
});

Related

Javascript Array doesn't map correctly

I'm "consolling" the entire code... but I can't find any issue, only a weird behaviour.
Let me explain:
I've an angular component (let's call it parent) which send some tags to his child through a inputTags array.
Then I need to set another list with ALL the tags of the user, called allTags.
The array (both inputTags and allTags) is formatted like this:
{ id: 'tagId', name: 'tagName' }
I need to make an unified array of those two. The expected output should contain an array of items that it's formatted like this: { id: 'tagId', name: 'tagName', selected: boolean }
In order to do this I'm mapping the allTags array in this way:
Let's suppose that:
inputTags = [
{ id: 'work', name: 'Work' },
{ id: 'motivation', name: 'Motivation' }
];
allTags = [
{ id: 'network', name: 'Network' },
{ id: 'work', name: 'Work' },
{ id: 'smart', name: 'Smart' },
{ id: 'motivation', name: 'Motivation' }
];
Now... allTags are actually retrived from a server, so my code looks something like this:
this.tagsService.getAll().subscribe(tags => {
this.allTags = tags.map(tag => {
let select = false;
this.inputTags.forEach(inputTag => { select = (inputTag.id === tag.id) })
return {
id: tag.id,
name: tag.name,
selected: select,
};
});
})
This for me seems quite standard, but in fact NO, because instead of getting:
allTags = [
{ id: 'network', name: 'Network', selected: false },
{ id: 'work', name: 'Work', selected: true }, // is selected
{ id: 'smart', name: 'Smart', selected: false },
{ id: 'motivation', name: 'Motivation', selected: true } // is selected
];
I get this:
allTags = [
{ id: 'network', name: 'Network', selected: false },
{ id: 'work', name: 'Work', selected: false }, // is NOT selected
{ id: 'smart', name: 'Smart', selected: false },
{ id: 'motivation', name: 'Motivation', selected: true } // is selected
];
Basically the issue is that it's selecting only one tag, not multiple tags.
You can try some:
this.allTags = tags.map(tag => {
return {
id: tag.id,
name: tag.name,
selected: this.inputTags.some(inputTag => inputTag.id === tag.id)
};
});
JavaScript Array map() Method
*)creates a new array with the results of calling a function for every array element and it calls the provided function once for each element in an array, in order.
Note: map() Method does not execute the function for array elements without values and it does not change the original array.
Try the following:
this.allTags = allTags.map(tag => ({
id: tag.id,
name: tag.name,
selected: inputTags.some(i => i.id === tag.id),
}))

Find element in array and return parent

I'm having an issue trying to get parent element of found element in array.
This is my array for example:
const arr = [
{
name: 'first level',
selected: true,
subItems: [
{
name: 'second level 1',
selected: false,
subItems: [],
},
{
name: 'second level 2',
selected: true,
subItems: [
{
name: 'third level 1',
selected: false,
subItems: [],
},
{
name: 'third level 2',
selected: false,
subItems: [],
},
{
name: 'third level 3',
selected: false,
subItems: [],
}
]
},
{
name: 'second level 3',
selected: false,
subItems: [
{
name: 'third level 4',
selected: false,
subItems: []
}
]
}
]
}
];
So basically if key selected is true I would like to return it's parent element. Now I don't know how deep can this array be, so I have taken recursive approach to the problem.
const getParent = (items, parentCat = null) => {
if (items && items.length > 0) {
const selectedCat = items.find(item => item.selected === true);
if (selectedCat && selectedCat.subItems.length > 0) {
return getParent(selectedCat.subItems, selectedCat);
}
return parentCat;
}
};
const parent = getParent(arr);
But the code will only work in some cases when there are not subItems for the selected item. I would like to get parent item of deepest selected element.
EDIT: If any element has selected true, also it's parent will have true, also there will always be just one selected element per level.
The problem is that within the recursion, if none of the items are selected, you must return the parent's parent. You can accomplish that by returning null within the deepest recursion, and let the caller handle it as the stack unwinds.
const getParent = (items, parent = null) => {
const selectedItem = items.find(item => item.selected === true);
if (selectedItem) {
// if there was a deeper parent, return that
// otherwise return my own parent
return getParent(selectedItem.subItems, selectedItem) || parent;
} else {
return null;
}
};
const arr = [
{
name: 'first level',
selected: true,
subItems: [
{
name: 'second level 1',
selected: false,
subItems: [],
},
{
name: 'second level 2',
selected: true,
subItems: [
{
name: 'third level 1',
selected: false,
subItems: [],
},
{
name: 'third level 2',
selected: false,
subItems: [],
},
{
name: 'third level 3',
selected: false,
subItems: [],
}
]
},
{
name: 'second level 3',
selected: false,
subItems: [
{
name: 'third level 4',
selected: false,
subItems: []
}
]
}
]
}
];
const getParent = (items, parent = null) => {
const selectedItem = items.find(item => item.selected === true);
if (selectedItem) {
return getParent(selectedItem.subItems, selectedItem) || parent;
} else {
return null;
}
};
console.log(getParent(arr));

Descontruct array of objects to get nested values ES6

I have an array of objects like:
const array = [
{
name: 'object1',
value: true,
parameters: [
{ name: 'inner1', value: true},
{ name: 'inner2', value: false},
]
},
{
name: 'object2',
value: false,
}
];
I need to get value of each object in array.
To get object1 and object2 values I have used
const [{value: object1}, {value: object2}] = array;
How can I get values of objects which are in parameters array? How to deconstruct it in right way? Cannot find the right way..
You'd have to use parameters: and keep destructuring:
const array = [{
name: 'object1',
value: true,
parameters: [{
name: 'inner1',
value: true
},
{
name: 'inner2',
value: false
},
]
},
{
name: 'object2',
value: false,
}
];
const [{ parameters: [
{ value: value1 },
{ value: value2 }
]}] = array;
console.log(value1, value2);
But that's not remotely readable IMO. I'd prefer to use standard dot/bracket notation to get to the parameters array, and .map to extract the values:
const array = [{
name: 'object1',
value: true,
parameters: [{
name: 'inner1',
value: true
},
{
name: 'inner2',
value: false
},
]
},
{
name: 'object2',
value: false,
}
];
const values = array[0].parameters.map(({ value }) => value);
console.log(values);
You could take Array#flatMap and map the values of paramters only.
const
array = [{ name: 'object1', value: true, parameters: [{ name: 'inner1', value: true }, { name: 'inner2', value: false }] }, { name: 'object2', value: false }],
values = array.flatMap(({ parameters = []}) => parameters.map(({ value }) => value));
console.log(values);
The deconstruction must follow the shape of the object it is deconstructing. A good way to think of it in situations like this, is to just copy the object itself, and then replace each value with a variable name to assign that value to
// Object from which to deconstruct values
const myArray = [{
name: 'object1',
value: true,
parameters: [
{ name: 'inner1', value: true},
{ name: 'inner2', value: false}]
}];
// Deconstruction
const [{
name: nameVar,
value: valueVar,
parameters: [
{ name: paramNameVar1, value: valueVar1},
{ name: paramNameVar2, value: valueVar2}]
}] = myArray
Of course once you start getting more complex objects, it is possably more effort, less readable, and less efficient to deconstruct this way.

JavaScript: How can I change property names of objects in an array?

I am using this react-select: https://github.com/JedWatson/react-select
The format for options data that they require is:
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry'},
{ value: 'vanilla', label: 'Vanilla' }
];
My array is set up differently as follows:
const columns = [
{ name: 'OrderNumber', title: 'Order Number' },
{ name: 'strawberry', title: 'Strawberry' },
{ name: 'vanilla', title: 'Vanilla' }
]
I am not able to change my array. If try to use name or value in my option items, I encounter issues using them with select-react. If I change my name to value, the select options are populating, however I don't want to do that.
Can anyone teach me how can I change my array's name to value?
You could use the .map() function to make the data in columns suitable for use with react-select.
The .map() function is available on the Array type. It creates a new array from the array you call it on, and allows you to provide a function that transforms/changes each item as it is copied from the original array.
You can make use of it as follows:
const columns = [
{ name: 'OrderNumber', title: 'Order Number' },
{ name: 'strawberry', title: 'Strawberry' },
{ name: 'vanilla', title: 'Vanilla' }
]
const options = columns.map(function(row) {
// This function defines the "mapping behaviour". name and title
// data from each "row" from your columns array is mapped to a
// corresponding item in the new "options" array
return { value : row.name, label : row.title }
})
/*
options will now contain this:
[
{ value: 'OrderNumber', label: 'Order Number' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' }
];
*/
For more information, see the MDN documentation for .map()
If you just want to rename the name property to value you can use a map and destruct the name property as value and pick the rest.
const columns = [
{ name: 'OrderNumber', title: 'Order Number' },
{ name: 'strawberry', title: 'Strawberry' },
{ name: 'vanilla', title: 'Vanilla' }
];
const newColumns = columns.map( item => {
const { name: value, ...rest } = item;
return { value, ...rest }
}
);
console.log( newColumns );
But, I suspect that you would want this since react-select doesn't work (as far as I see) with title. It waits for a label prop I guess. If this is so, go with and change all the properties as #Dacre Denny suggested. I like arrow functions :) So:
const newColumns = columns.map( item =>
( { value: item.name, label: item.title } )
);
Use destructuring with renaming property will simplify.
const options = [
{ value: "chocolate", label: "Chocolate" },
{ value: "strawberry", label: "Strawberry" },
{ value: "vanilla", label: "Vanilla" },
];
const columns = options.map(({ value: name, label: title }) => ({
name,
title,
}));
console.log(columns);

TinyMCE: get values from a listbox in a modal window

I'm creating a TinyMCE Plugin for Wordpress. It has a textbox and a listbox field, both staying in a modal window.
Code below:
(function () {
tinymce.create('tinymce.plugins.windowdata', {
init : function(ed, url) {
ed.addButton('showModal', {
title: 'Show Modal',
image: url + '/img/button.png',
onclick: function () {
ed.windowManager.open({
title: 'Minestra',
body: [
{type: 'textbox', name: 'Field', label: 'Number', value: '', tooltip: 'Tooltip', maxLength: 3, classes: 'i1n'}, //textbox
{type: 'listbox', label: 'Listbox', classes: 'i1lb', values: [
{text: '', value: ''},
{text: 'Number', value: 'lone_number'},
{text: 'Bar', value: 'bar'},
]}, //listbox
],
onsubmit: function () {
var n1 = document.getElementsByClassName('mce-i1n')[0].value; //textbox value
var t1 = document.getElementsByClassName('mce-i1lb')[0].getElementsByTagName('button')[0].getElementsByClassName('mce-txt')[0].innerHTML; //listbox value
ed.execCommand('mceInsertContent', 0, n1+' is of type '+t1) //write contents
}
})
}
});
}
)
My question is about how to get the field values. What i did works very well with the textbox (the n1 var inside the onsubmit() method), but the listbox gets the same text that is shown to TinyMCE user (the text var in each listbox item).
What i want is a way to get the value instead; plus, i suppose i didn't get the right way to do it, not even with textbox. Anyone can help me? Thank you.
Better way to generate content is:
onsubmit: function (e) {
// Insert content when the window form is submitted
e.insertContent('Textbox content: ' + e.data.Field);
e.insertContent('Listbox content: ' + e.data.Listbox)
}
I solved by my own: i had to give a name to all of my fields:
{type: 'textbox', name: 'Field', label: 'Number', value: '', tooltip: 'Tooltip', maxLength: 3, classes: 'i1n'}, //textbox
{type: 'listbox', name: 'Listbox', label: 'Listbox', classes: 'i1lb', values: [
{text: '', value: ''},
{text: 'Number', value: 'lone_number'},
{text: 'Bar', value: 'bar'},
]
At this point, to generate my content i got values this way:
onsubmit: function (e) {
e.data.Field;
e.data.Listbox;
}
and used this to write in TinyMCE textarea. To get values back i had to modify textbox field this way:
{type: 'textbox', name: 'Field', label: 'Number', value: '', tooltip: 'Tooltip', maxLength: 3, classes: 'i1n', value: ed.selection.getContent()}
Similarly with listbox

Categories