react-select: How can I use the optionRenderer prop with the Async component? - react-select

I am using react-select to make a select box that geocodes an address and then provides a drop down list of the corresponding local government areas of that search returns.
I am just trying to format each option so it shows the State eg. Queensland after the local government area eg. Brisbane.
So I'm trying to get it to return something like:
Brisbane <small>Queensland</small>
But in the HTML it escapes and renders the tags.
It looks like optionRenderer would work, but it seems to be only available with the Select component of react-select and I am currently using Async because I want to wait for the geocoded latitude and longitude from Mapbox.
Anyone know a way to format options while using the <Async /> component?

OK so I worked out what I was doing wrong. The optionRenderer={this.renderOption} prop was working after all but I was returning a string instead of a JSX component.
So here's my method anyway for anyone who has this issue in the future:
renderOption(option) {
return <div> {option.label} <small>small</small></div>;
}
So I'll just need to split the option.label up and put the State in between the tags.

Related

Vue js - is that right to put all my code in watch?

I Have component A and Component B
in component A i have an API call.
when i passing info to my component b:
<B :structuresMetaData="structureTree"></B>
Inside mounted the variable structuresMetaData the length is 0
and inside the watch the length is 1.
my issue that mounted appear before the watch.
is it would be right to put all my code in watch ? if not what is the solution ?
It looks like structureTree is being changed after <B> is created/mounted.
You have two options depending on your use case:
The first option is to defer the creation of <B> until your data is loaded. This way you don't need <B> to watch for changes to the prop and the prop will be fully populated in the created/mounted hook. This is the simpler approach.
Assuming structureTree is initially an empty array:
<B
v-if="structureTree.length > 0"
:structuresMetaData="structureTree"
/>
created() {
// this.structuresMetaData is a non-empty array here
}
I usually initialize my data with null so that I can distinguish between "not loaded" and "loaded" (where "loaded" can actually be an empty array if the data I fetched from the API was empty).
The second way is using a watcher in <B> to react to changes to the prop. You will need to do this method if the bound prop might change multiple times and you need <B> to update in some way to that change.
watch: {
structuresMetaData(value) {
// React to the change, load secondary data, etc
}
}
What exactly are you doing in <B> that requires a watcher? It's best to avoid explicit watchers if you can avoid them because it usually means you are copying data around and it gets messy when you don't have a single source of truth. Use pure computed properties whenever you can if you just want to transform the data in some way.

How to add a link (or any html) to a getter response in Vuex?

I'm building a blockchain explorer using Vue and Vuex and I stumbled upon a problem I can't solve thus far.
Essentially I have a getter that returns a full transaction info based on operation name. For instance, if the operation is po_transfer, I want to give user details on what type of asset, quantity, sender and receiver of this particular operation (#mat sent 10 BTC to #ned).
Since I collect data from different applications and games of one particular blockchain, I have dozens of these operations (transfer, open, cancel, sell, purchase, issue, build, explore, upgrade and so forth). Thus, I created a getter that returns all of that in a human readable form, instead of po_transfer.
It works perfectly with text but I need to add a link in my response as well.
In our previous example (#mat sent 10 BTC to #ned) #mat and #ned should be links that lead to correspondent websites that I set up for them.
So my question is - how to I add link inside of the Vuex getter response?
I already tried to use plain javascript with document.body.appendChild(myLink) but it only shows an href text (http://somewebsite.com/#mat), instead of actually giving me an embedded link (#mat) that leads to this href.
Here's what I have now:
dappInfo: (state, getters) => (op, id) => {
if (op === 'transfer') {
return getters.dappJsonByTrxId(id).from + ' sent ' +
getters.dappJsonByTrxId(id).amount +
` to #${getters.dappJsonByTrxId(id).to}`
}
}
dappJsonByTrxId: (state) => (id) => {
return state.transactions.find(t => t.transaction_id === id).operations[0][1] || ''
}
I need this getters.dappJsonByTrxId(id).from to return #mat.
<a href=`example.com/${getters.dappJsonByTrxId(id).from}> #${getters.dappJsonByTrxId(id).from}<a/>
doesn't work as well. It returns me <a>..</a> in a text form.
I assume you're not supposed to return html in getters but I really need to solve this one because everything else is working. Would really appreciate any help. Thanks in advance.
P.S. You can check the demo of explorer right here.
You can output string value containing all your html tags <a href=".... /> composed in a getter and then output it as html using v-html directive, f.e. <div v-html="yourJsString"/>.
When composing string with html, ecmaScript templates aka string interpolation may come in handy.

Vue2 component as <vue-component>value</vue-component>

It is possible to pass a value to the component between the component tags?
Example: in a component to format value to money, I created as :
<vue-component value="50" />
and it display
$ 50,00
Now, just for curiosity, it is a way to call the component like these:
<vue-component>50</vue-component>
Read about slots: vuejs.org/v2/guide/components-slots.html
Fe: <template><h1><slot/></h1></template>
You can access ita value via: this.$slots.default[0].text
The fact that it's possible doesn't mean that you should do it. Actually, on the contrary. Props have multiple advantages (such as marking as required, default value, validators and many more) but in thr first place they are standardised way of passing data to children components every vuejs developer will understand.

Add target blank to a link in a props in Vue.js

I use the ReadMore plugin to crop articles in a page. The plugin provides a props to redirect to a http link when the "read more" is clicked. But I need to display the link in a new tab. The props receives the link in a string.
I tried several ways to add the target blank attribute to this string before passing it to the props. With no success. Like:
http://www.example.com/page-to-see.html target=_"blank"
I used it with or without quotes but in any case, the link works but the attribute is skipped.
Is there a way to intercept this and add a target blank later?
I saw in other questions the use of router-link but I don't know how to manipulate the props content in the first place.
Any clue would be warmly welcomed
Edit: adding more code to give a clearer explanation of the problem I try to solve:
In the template:
<read-more more-str="read more" :text="dwId.texte" :link="dwId.link" less-str="less" :max-chars="540"></read-more>
I get the values from a DB with Axios. The props are specified by the plugin documentation.
The :link must be a string and it's what it gets from the DB. It works. But as I explained, I need to open in a new tab.
Edit: what I tried:
I try to make a computed property that would add the target blank to a string and use it in the read-more props:
computed: {
target: function() {
return this.dwIds.filter((dwId) => {
return dwId.link + target="_blank"
});
},
}
I have two issues here: first , the result is an object and the props requires a string. Furthermore, the way I add the target blank is not correct but I can't find the right syntax yet.
You need to use it as a directive, and override parts of the initial element you're passing. Otherwise there is no way to "intercept" it. Here's the code to the "component" version that won't do the trick for you.

VueJS Component Input Sync

I want to create components which have input which two-way bind to the local scope of the component.
Without a component, I would create a new Vue instance and then set my data to what I need. Then using v-model, bind an input to that data and it can be manipulated from the input.
However, converting the same code to a component, I cannot for the life of me get any input in a component to bind to its data. I have tried props, :data.sync, data attributes but no matter what I have tried, the input within a component does nothing.
I have created a JSFiddle to illustrate this:
https://fiddle.jshell.net/f0pdmLhy/2/
What I would like to happen is the input in the component to two way bind to the err variable, just like the non component version underneath.
How would I accomplish this?
I basically want to create components that I can instansiate with ajax data and then populate the inputs. The inputs could then update the data and I can use a save method to send the data to the server. Can this even be done using components?
So there are a couple of things:
The external resource you were using was somehow faulty. I've used
jsfiddle default Vue instance and it works fine.
When you declare a component, you should not define the data as an object, but as a function returning an object. Read here: https://vuejs.org/guide/components.html#Component-Option-Caveats
A working example here: https://fiddle.jshell.net/by4csn1b/1/
Yes, with components, the reactivity can be accomplished just like with an instance.
One catch with components, is that data must be a function that returns an object.
Also, to maintain the two way binding, use v-model in your input.
Vue.component('ii', {
template: '<span>{{err}}</span><input type="text" v-model="err"><hr>',
data: function () {
return {
err: 123
}
}
})
Fiddle: https://fiddle.jshell.net/f0pdmLhy/25/