Can't load options with Select.Async - react-select

I can't get the basic application with async options loading to work. The getOptions function gets called but the select control doesn't display them. Here's the code and Plunkr link https://plnkr.co/edit/vKZXhjQRhDWflMQpt8b5?p=preview
var options = [
{ value: 'one', label: 'One' },
{ value: 'two', label: 'Two' }
];
function logChange(val) {
console.log("Selected: " + JSON.stringify(val));
}
function getOptions(input) {
console.log(input)
return Promise.resolve(options)
}
ReactDOM.render(
<Select.Async
name="form-field-name"
value="one"
loadOptions={getOptions}
onChange={logChange}
/>,
document.getElementById('example')
);

I believe all you need to do is return { options: yourDataArray } instead of yourDataArray.
For example, in your code, return Promise.resolve(options) should be changed to return Promise.resolve({options})
Hope this helps.

Related

Check all checkboxes by default

So I have this checkbox group
b-form-checkbox-group.ml-4.b-check(
v-model="selected",
v-if="productGroup.show",
:options="productGroup.products",
I am trying to have the list of :options to be checked by default. I am having issues with settign this up.
Here is my code, I don't know why it is not working.
toggleAll(checked, productGroup) {
if (checked) {
let productIds = this.selected ? [...this.selected] : [];
productGroup.products.forEach((product) => {
productIds.push(product.id);
});
this.selected = _.uniq(productIds);
} else {
let temp = [...this.selected];
productGroup.products.forEach((product) => {
if (temp.indexOf(product.id) > -1) {
temp.splice(temp.indexOf(product.id), 1);
}
});
this.selected = temp;
}
Assume your option group is an array of object data, and you will use another array to track the selected options, as follows:
data() {
return {
selected1: [],
group1: [
{ id: 1, text: 'Item 1', value: 'item1' },
{ id: 2, text: 'Item 2', value: 'item2' }
]
}
}
Your toggleAll method needs to add all the group's values to the tracking array to toggle them on, and it needs to remove all values to toggle them off:
methods: {
toggleAll(checked, group, selected) {
// First remove any selected items, regardless of the toggle state
selected.splice(0, selected.length)
// Now, if the toggle is true, add all items
if (checked) {
group.forEach(o => selected.push(o.value));
}
}
}
Using the example data above, call the above method like:
this.toggleAll(true, this.group1, this.selected1);

Highcharts-vue - Calling my own tooltip label formatter function

I have been trying to call my own function for formatting the x and y axis values in a tooltip in Highcharts vue.
Consider the following;
data() {
return {
currencySymbol: "$",
};
},
computed: {
chartOptions() {
var symbol = this.currencySymbol;
return {
chart: {
type: "spline"
},
title: {
text: "Sin chart"
},
yAxis: {
gridLineDashStyle: "Dot",
labels: {
style: {
color: "#000"
},
formatter: label => {
return (
symbol + Highcharts.Axis.prototype.defaultLabelFormatter.call(label)
);
}
}
},
tooltip: {
formatter: function () {
return Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' +
this.formatNumber(this.y, this.fractionalDigits, this.locale, this.currencySymbol);
}
},
series: [
{
data: [10, 0, 8, 2, 6, 4, 5, 5],
color: "#6fcd98"
}
]
};
}
}
The labels work fine but the tooltip function call will not work. I have tried putting my formatNumber() function in both methods() and outside of any of the Vue hooks. Neither work.
Note that fractionDigits, locale and currencySymbol have been resolved at this point.
Wondering if someone can advise on the correct approach?
Also note that the formatter works when I remove the call to my formatNumber() function. It's lack of scope appears to be where the problem lies.
If I should assume that this.formatNumber, this.fractionDigits, this.locale, and this.currencySymbol would be references to a component's internal data, then the problem would occurs because of this context within tooltip's formatter function, which does not actually indicate on the component, but on the object on which the formatter was called, namely the TooltipFormatterContextObject.
In order to fix it, you can save appropriate context in the beginning of the chartOptions computed property function, and just refer it when calling component functions. Please take a look on the example below, where I've put the 'template' function named like yours, and presented how it could be implemented.
Live example: https://codesandbox.io/s/highcharts-vue-demo-wqwzu
Kind regards!
Not sure if it's the most elegant but I found a solution to this problem for myself.
I created a utility js file called helper.js, added my exported function (I'll need it in other places anyway) and put it in a directory called utils.
The contents are as follows;
export function formatNumber(number, maxFractionDigits, locale, currencySymbol) {
// function logic here
}
Then I imported same into my component and simply called the method as follows;
import {formatNumber} from "../../utils/helper";
export default {
data() {
return {
currencySymbol: "$",
};
},
computed: {
chartOptions() {
var symbol = this.currencySymbol;
return {
chart: {
type: "spline"
},
title: {
text: "Sin chart"
},
...
tooltip: {
formatter: function () {
return Highcharts.dateFormat('%Y-%m-%d %H:%M:%S', this.x) + '<br/>' +
formatNumber(this.y, this.fractionalDigits, this.locale, this.currencySymbol);
}
},
series: [
{
data: [10, 0, 8, 2, 6, 4, 5, 5],
color: "#6fcd98"
}
]
};
}
}
}

Binding an object from checkboxes

I need to bind an object from checkboxes, and in this example, a checkbox is its own component:
<input type="checkbox" :value="option.id" v-model="computedChecked">
Here's my data and computed:
data() {
return {
id: 1,
title: 'test title',
checked: {
'users': {
},
},
}
},
computed: {
computedChecked: {
get () {
return this.checked['users'][what here ??];
},
set (value) {
this.checked['users'][value] = {
'id': this.id,
'title': this.title,
}
}
},
....
The above example is a little rough, but it should show you the idea of what I am trying to achieve:
Check checkbox, assign an object to its binding.
Uncheck and binding is gone.
I can't seem to get the binding to worth though.
I assume you want computedChecked to act like an Array, because if it is a Boolean set, it will receive true / false on check / uncheck of the checkbox, and it should be easy to handle the change.
When v-model of a checkbox input is an array, Vue.js expects the array values to stay in sync with the checked status, and on check / uncheck it will assign a fresh array copy of the current checked values, iff:
The current model array contains the target value, and it's unchecked in the event
The current model array does not contain the target value, and it's checked in the event
So in order for your example to work, you need to set up your setter so that every time the check status changes, we can get the latest state from the getter.
Here's a reference implementation:
export default {
name: 'CheckBoxExample',
data () {
return {
id: 1,
title: 'test title',
checked: {
users: {}
}
}
},
computed: {
computedChecked: {
get () {
return Object.getOwnPropertyNames(this.checked.users).filter(p => !/^__/.test(p))
},
set (value) {
let current = Object.getOwnPropertyNames(this.checked.users).filter(p => !/^__/.test(p))
// calculate the difference
let toAdd = []
let toRemove = []
for (let name of value) {
if (current.indexOf(name) < 0) {
toAdd.push(name)
}
}
for (let name of current) {
if (value.indexOf(name) < 0) {
toRemove.push(name)
}
}
for (let name of toRemove) {
var obj = Object.assign({}, this.checked.users)
delete obj[name]
// we need to update users otherwise the getter won't react on the change
this.checked.users = obj
}
for (let name of toAdd) {
// update the users so that getter will react on the change
this.checked.users = Object.assign({}, this.checked.users, {
[name]: {
'id': this.id,
'title': this.title
}
})
}
console.log('current', current, 'value', value, 'add', toAdd, 'remove', toRemove, 'model', this.checked.users)
}
}
}
}

Vue.js - Element UI - HTML message in MessageBox

I'm using vue-js 2.3 and element-ui. This question is more specific to the MessageBox component for which you can find the documentation here
Problem
I'd like to be able to enter html message in the MessageBox
More specifically I would like to display the data contained in dataForMessage by using a v-for loop.
Apparently, we can insert vnode in the message but I have no idea where to find some information about the syntax.
https://jsfiddle.net/7ugahcfz/
var Main = {
data:function () {
return {
dataForMessage: [
{
name:'Paul',
gender:'Male',
},
{
name:'Anna',
gender:'Female',
},
],
}
},
methods: {
open() {
const h = this.$createElement;
this.$msgbox({
title: 'Message',
message: h('p', null, [
h('span', null, 'Message can be '),
h('i', { style: 'color: teal' }, 'VNode '),
h('span', null, 'but I would like to see the data from '),
h('i', { style: 'color: teal' }, 'dataForMessage'),
])
}).then(action => {
});
},
}
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
I think this is what you want.
methods: {
open() {
const h = this.$createElement;
let people = this.dataForMessage.map(p => h('li', `${p.name} ${p.gender}`))
const message = h('div', null, [
h('h1', "Model wished"),
h('div', "The data contained in dataForMessage are:"),
h('ul', people)
])
this.$msgbox({
title: 'Message',
message
}).then(action => {
});
},
}
Example.
You can also use html directly and convert to vnodes by using domProps:
const html = '<div><h1>Model wished</h1><div>The data contained in dataForMessage are:</div><ul><li>Paul Male</li><li>Anna Female</li></ul></div>'
const message = h("div", {domProps:{innerHTML: html}})
(The above is simplified without the loop. Just to get the idea)
Fiddle

How to chain get and map the result with lodash?

I've got a list I'm trying to pull an object from using _.get but following that selection I need to loop over the object to create a new property. So far I've been successful using a combination of _.get and _.map as shown below but I'm hoping I can use _.chain in some way.
var selected = _.get(results, selectedId);
return _.map([selected], result => {
var reviews = result.reviews.map(review => {
var reviewed = review.userId === authenticatedUserId;
return _.extend({}, review, {reviewed: reviewed});
});
return _.extend({}, result, {reviews: reviews});
})[0];
Is it possible to do a transform like this using something other than map (as map required me to break this up/ creating an array with a solo item inside it). Thank you in advance!
I can see that you're creating unnecessary map() calls, you can simply reduce all those work into something like this:
var output = {
reviews: _.map(results[selectedId], function(review) {
return _.defaults({
reviewed: review.userId === authenticatedUserId
}, review);
})
};
The defaults() method is similar to extend() except once a property is set, additional values of the same property are ignored.
var selectedId = 1;
var authenticatedUserId = 1;
var results = {
1: [
{ userId: 1, text: 'hello' },
{ userId: 2, text: 'hey' },
{ userId: 1, text: 'world?' },
{ userId: 2, text: 'nah' },
]
};
var output = {
reviews: _.map(results[selectedId], function(review) {
return _.defaults({
reviewed: review.userId === authenticatedUserId
}, review);
})
};
document.body.innerHTML = '<pre>' + JSON.stringify(output, 0, 4) + '</pre>';
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.js"></script>