format currencies in a Vue component? - html

Good day everyone, I'm trying to format the value that JSON brings me in currency, I saw some suggestions but I still can't convert the value.
This is how I've my code structured
<template>
...
<div class="currency-selection">
<input type="text" :value="conversionValue * cryptoQuantity " readonly />
...
<template>
<script>
export default {
name: 'CurrencySelect',
data: () => ({
conversionValue: 0,
cryptoQuantity: 1
}),
axios
.get(
"https://min-api.cryptocompare.com/data/price?fsym=btc&tsyms=COP"
)
.then((res) => {
this.conversionValue = res.data.COP;
})
.catch((e) => {
console.log(e);
});
}
Right now the value is 169057977.17 but I want it to be displayed like this: 169.057.977,17

You can use toLocaleString to format numbers acording to the language and region you define.
Use Number.toLocaleString('es-CO') get this: 169.057.977,17
See this for a list of supported locales
See this example
<script>
export default {
data() {
return {
conversionValue: 0,
cryptoQuantity: 1
}
},
async mounted () {
this.conversionValue = await fetch("https://min-api.cryptocompare.com/data/price?fsym=btc&tsyms=COP").then(raw => raw.json()).then(json => json.COP)
}
}
</script>
<template>
<input type="text" :value="(this.cryptoQuantity * this.conversionValue).toLocaleString('es-CO')"/>
</template>

Related

Not able to populate the select drop down with JSON in reactJS

I'm trying to fetch key "name" and its corresponding value using JSON in the drop down "Select" of reactJS. But it does not work when I'm executing my code. I have attached my code, Kindly have a look!
I have tried using componentDidMount to fetch the data by making API call. I am a beginner so I'm trying to figure out what ways can make it work.
class devName extends Component {
state = {
names: [],
selectedName: "",
validationError: ""
}
componentDidMount() {
fetch("http://127.0.0.1:8080/dashboard/get_names")
.then((res) => {
return res.json();
})
.then(data => {
let namesFromAPI = data.map(name => { return { value: name, display: name } })
this.setState({ names: [{ value: '', display: '(Select the site)' }].concat(namesFromAPI) });
}).catch(err => {
console.log(err);
});
}
render() {
return (
<div className="wrapper">
<div className="form-wrapper">
<Toolbar />
<form className="form">
<label className="label1">Select Name from the drop down</label> <hr />
<div>
<Select
value={this.state.selectedName}
onChange={(e) => this.setState({selectedName: e.target.value, validationError: e.target.value === "" ? "You must select a site name" : ""})}>
{/* placeholder="Loading Site List..." > */}
{this.state.names.map((name) => <option key={name.value} value={name.display}>{name.display} </option>)}
</Select>
<div style={{color: 'red', marginTop: '5px'}}>
{this.state.validationError}
</div>
<br />
</div>
<label className="label1">Create New Name From Template</label>
<hr />
<div className="addButton">
<button type="Submit">Add</button> <hr />
</div>
<div className="submitButton">
<button type="submit">Submit</button>
</div>
</form>
</div>
</div>
);
}
}
export default devName;
JSON CODE LOOKS LIKE:
[
{
"type": "state",
"id": 2131,
"temporaryEle": {},
"name": "First Unit#1234 TON" .. and so on
}
]
There is no error message. Though the desired result should be "Select Drop Down populates with : " Select one of the name please"
First Unit#1234 TON
Second Unit#8934 QON
Third Unit#6534 JON
Edit:
I've read one of your comments and it seems like you're having CORS issues with fetch.
Add the baseurl as proxy in your package.json file
// Package.json
{
...other configs,
"proxy": "http://127.0.0.1:8080"
}
Then you'd call your fetch like so: fetch('/dashboard/get_names').then((res) => {...})
Resource for you to look at:
https://create-react-app.dev/docs/proxying-api-requests-in-development/
Old:
According to your JSON data, you might have to destucture a level deeper on your object while mapping the data in componentDidMount
let namesFromAPI = data.map(({name}) => {
return { value: name, display: name }
})
// OR
let namesFromAPI = data.map(name => {
return { value: name.name, display: name.name }
})
Use destucturing on name parameter, you can implicitly return object from arrow function when you wrap it in () data.map(({name}) => ({ value: name, display: name }))

React: Passing a Prop in w/ event for setState

I'm working with a nested state object that I have been updating with onChange functions, like so:
const [someState, setSomeState] = useState({
customer: [
{
name: "Bob",
address: "1234 Main Street",
email: "bob#mail.com",
phone: [
{
mobile: "555-5555",
home: "555-5555"
}
]
}
]
});
const updateSomeStatePhone = e => {
e.persist();
setSomeState(prevState => {
prevState.customer[0].phone[0].mobile = e.target.value;
return {
...prevState
};
});
};
<p>Update Mobile Number<p>
<select
value={someState.customer[0].phone[0].mobile}
onChange={updateSomeStatePhone}
>
<option value="123-4567">"123-4567"</option>
</select>
This gets the trick done. Currently however, if I want to update multiple state properties via a large form with dropdowns/input fields etc, I have to hard code 6 different onChange handlers for those fields.
Instead, I would prefer to have only one onChange handler, and pass in the state from the form field for the state property that I am changing, but I can't figure out the syntax:
const updateSomeState = (e, prop) => {
e.persist();
setSomeState(prevState => {
prevState.prop = e.target.value;
return {
...prevState
};
});
};
<p>Update Mobile Number<p>
<select
value={someState.customer[0].phone[0].mobile}
onChange={updateSomeState(e, prop)}
>
<option value="123-4567">"123-4567"</option>
</select>
I've tried using different types of syntax to chain the passed in 'prop' value to prevState:
prevState.prop = e.target.value;
prevState.(prop) = e.target.value;
${prevState} + '.' + ${prop} = e.target.value; // Dumb, I know
But the function never recognizes the "prop" that I pass in from the function. I'm sure there must be a simple way to do this. Any help would be greatly appreciated.
Does it have to be a single useState hook? I would recommend using useReducer or simplifying it a bit with multiple useState hooks.
Multiple useState hooks
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
function App() {
const [name, setName] = React.useState("");
const [address, setAddress] = React.useState("");
const [email, setEmail] = React.useState("");
const [mobile, setMobile] = React.useState("");
const [home, setHome] = React.useState("");
const getResult = () => ({
customer: [
{
name,
address,
email,
phone: [
{
mobile,
home
}
]
}
]
});
// Do whatever you need to do with this
console.log(getResult());
return (
<>
<input
value={name}
placeholder="name"
onChange={e => setName(e.target.value)}
/>
<br />
<input
value={address}
placeholder="address"
onChange={e => setAddress(e.target.value)}
/>
<br />
<input
value={email}
placeholder="email"
onChange={e => setEmail(e.target.value)}
/>
<br />
<input
value={mobile}
placeholder="mobile"
onChange={e => setMobile(e.target.value)}
/>
<br />
<input
value={home}
placeholder="home"
onChange={e => setHome(e.target.value)}
/>
</>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Single useReducer (with simplified state)
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
const reducer = (state, action) => {
const { type, value } = action;
switch (type) {
case "SET_NAME":
return { ...state, name: value };
case "SET_ADDRESS":
return { ...state, address: value };
case "SET_EMAIL":
return { ...state, email: value };
case "SET_MOBILE":
return { ...state, phone: [{ ...state.phone[0], mobile: value }] };
case "SET_HOME":
return { ...state, phone: [{ ...state.phone[0], home: value }] };
default:
throw Error(`Unexpected action: ${action.type}`);
}
};
const initialState = {
name: "",
address: "",
email: "",
phone: [
{
mobile: "",
home: ""
}
]
};
function App() {
const [state, dispatch] = React.useReducer(reducer, initialState);
// Do what you need with state
console.log(state);
return (
<>
<input
value={state.name}
placeholder="name"
onChange={({ target: { value } }) =>
dispatch({ type: "SET_NAME", value })
}
/>
<br />
<input
value={state.address}
placeholder="address"
onChange={({ target: { value } }) =>
dispatch({ type: "SET_ADDRESS", value })
}
/>
<br />
<input
value={state.email}
placeholder="email"
onChange={({ target: { value } }) =>
dispatch({ type: "SET_EMAIL", value })
}
/>
<br />
<input
value={state.phone.mobile}
placeholder="mobile"
onChange={({ target: { value } }) =>
dispatch({ type: "SET_MOBILE", value })
}
/>
<br />
<input
value={state.phone.home}
placeholder="home"
onChange={({ target: { value } }) =>
dispatch({ type: "SET_HOME", value })
}
/>
</>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
useReducer is a better choice for doing this. Examples all over the internet.
Why you shouldn't use useState to pass an object is because it doesn't act like setState. The underlying object reference is the same. Therefore, react will never trigger a state change. In case you want to use the same useState for objects. You may have to implement your own version to extend that (example below ) or you can directly use useReducer hook to achieve the same.
Here's an example with useState for you to notice the state update on every change.
const [form, setValues] = useState({
username: "",
password: ""
});
const updateField = e => {
setValues({
...form,
[e.target.name]: e.target.value
});
};
Notice the ...form in there. You can do it this in every update you want or you can use your own utility or useReducer as I mentioned.
Now coming to your code, there are other concerns.
You are using your phone as an array which can be an object. Or better yet separate properties will do as well. No harm.
If you have customers as an array, you have to loop through the records. Not just update the index by hardcoding. If there's only one customer better not keep the array but just an object. Assuming it is an array of customers, and you are looping through it, here's how to update mobile.
const updatedCustomers = state.customers.map(item => {
const { phone } = item;
return { ...item, phone: { mobile: e.target.value }};
// returns newCustomer object with updated mobile property
});
// Then go ahead and call `setSomeState ` from `useState`
setSomeState(...someState, { customer: updatedCustomers });// newState in your case is
Instead, I would prefer to have only one onChange handler, and pass in
the state from the form field for the state property that I am
changing, but I can't figure out the syntax
If you haven't figured that out from the first example. Here's how in short steps.
Give your HTML element a name attribute.
Then instead use the [e.target.name]
return { ...item, phone: { [e.target.name]: e.target.value }};
Use lodash's _.set helper.
const updateSomeState = (e, prop) => {
e.persist();
setSomeState(prevState => {
let customers = [...prevState.customers] // make a copy of array
let customer = {...customers[0]} // make a copy of customer object
_.set(customer, prop, e.target.value)
customers[0] = customer;
return {
...prevState, customers
};
});
};
BTW, in your existing updateSomeStatePhone you are modifying prevState object which is supposed to be immutable.

State element does not appear on react simple map with react-tooltip

The code is working with the property 'name', names appear correctly on the map.
I wanted to enrich the json file with datas coming from my mysql database (like, add the name of countries in french or spanish for example).
I added a state 'countries' which will be initialized with json file converted in object. I fetch data from my sql database and then I set the state 'countries' with data I wanted to add.
Here is the code :
import React, { Component } from "react"
import {
ComposableMap,
ZoomableGroup,
Geographies,
Geography,
} from "react-simple-maps"
import ReactTooltip from "react-tooltip"
import jsonWorldMap from "./maps/world-50m.json"
const wrapperStyles = {
width: "100%",
height: "100%",
backgroundColor: "#0565A1"
}
class WorldMap extends Component {
constructor(){
super()
this.state = {
zoom: 1,
color: "#39464E",
countries: jsonWorldMap
}
}
componentDidMount() {
//get all countries in db
fetch('http://localhost:3001/countries')
.then(res => res.json())
.then(body =>
body.data.forEach(function(elementSql){
jsonWorldMap.objects.units.geometries.forEach(function(elementJson){
if(elementSql.alpha3 == elementJson.id)
{
elementJson.properties.nameFr = elementSql.name_fr;
}
})
})
)
this.setState({ countries: jsonWorldMap }, () => console.log(this.state.countries))
}
render() {
return (
<div style={wrapperStyles}>
<ComposableMap>
<ZoomableGroup center={[0,20]}>
<Geographies geography={this.state.countries}>
{(geographies, projection) => geographies.map((geography, i) => geography.id !== "ATA" && (
<Geography
className="Geography"
key={i}
data-tip={geography.properties.nameFr}
geography={geography}
projection={projection}
/>
))}
</Geographies>
</ZoomableGroup>
</ComposableMap>
<ReactTooltip />
</div>
)
}
}
export default WorldMap
So you can see that I added a component to have a console.log at the end of the component. See what console.log gives :
So you can see that the property 'nameFr' is present in the state object 'countries'. But, If I try to display it as tooltip, it doesn't work. And it works perfectly with property 'name' (in data-tip)
If data-tip={geography.properties.name} works fine but data-tip={geography.properties.nameFr} does not, then it seems that the problem is with state.
See your componentDidMount method. You are updating state with jsonWorldMap at the end of this method.
But as fetch is async , at that moment jsonWorldMap may not be updated yet. So I think you should move that line inside fetch. please see below:
componentDidMount() {
const _this = this; // hold this inside _this
//get all countries in db
fetch('http://localhost:3001/countries')
.then(res => res.json())
.then(body => {
body.data.forEach(function(elementSql){
jsonWorldMap.objects.units.geometries.forEach(function(elementJson){
if(elementSql.alpha3 == elementJson.id)
{
elementJson.properties.nameFr = elementSql.name_fr;
}
})
});
_this.setState({ countries: jsonWorldMap }, () => console.log(this.state.countries)); //making sure setting updated jsonWorldMap to state
}
)
}
hope it helps.
thanks
Wrap Geography with an element that uses data-tip as a props.
<div data-tip={geography.properties.nameFr}>
<Geography ... />
</div>
In order to <Geography data-tip={props.nameFr}/> work, Geography component need to use the data-tip property internaly, something like:
function Geography(props) {
return <h1 data-tip={props['data-tip']}>I'm a map</h1>;
}
To solve your problem you need to attach data-tip property to Geography wrapper, for example:
function Geography(props) {
return <h1>I'm a map</h1>;
}
function ComponentWithTooltip({ props }) {
return (
<div data-tip="nameFr">
<Geography />
</div>
);
}
function App() {
return (
<>
<Geography data-tip="hello-world" /> // Your way, won't work
<ComponentWithTooltip /> // Work
<div data-tip="nameFr2"> // Work
<Geography />
</div>
// Works with div wrapper, without won't work.
{geographies.map((geofraphy, i) => (
<div key={i} data-tip={geofraphy.properties.nameFr}>
<Geography />
</div>
))}
<ReactTooltip />
</>
);
}
Check out the demo with all use cases:

How to use Filter with ReactJS to prevent duplicates in an array from being displayed

I have a ReactJS page with three dropdown list, two of the dropdown list are displaying duplicate values. The values are being consumed from a json file. I researched using filter to remove the duplicates, but I'm unsure as to how I'm to apply it to my array when using React JS along with Fetch.
I created a function which employs the filter method, but I'm uncertain as to how I'm to implement it onto data: [], which contains the data consumed from the json file. This is the sample json file: https://api.myjson.com/bins/b1i6q
This is my code:
import React, { Component } from "react";
class Ast extends Component {
constructor() {
super();
this.state = {
data: [],
cfmRateFactor: "10"
};
} //end constructor
change = e => {
this.setState({
[e.target.name]: e.target.value
});
}; //end change
removeDups(array) {
return array.reduce((result, elem) => {
if (!result.some((e) => e.clientName === elem.clientName)) {
result.push(elem);
}
return result;
} , []);
}
componentWillMount() {
fetch("https://api.myjson.com/bins/b1i6q", {
method: "GET",
headers: {
Accept: "application/json",
"Content-type": "application/json"
}
/*body: JSON.stringify({
username: '{userName}',
password: '{password}'
})*/
}) /*end fetch */
.then(results => results.json())
.then(data => this.setState({ data: data }));
} //end life cycle
render() {
console.log(this.state.data);
return (
<div>
<div className="container">
<div className="astContainer">
<form>
<div>
<h2>Memeber Selection:</h2>
{["clientName", "siteName", "segmentName"].map(key => (
<div className="dropdown-padding">
<select key={key} className="custom-select">
{this.state.data.map(({ [key]: value }) => (
<option key={value}>{value}</option>
))}
</select>
</div>
))}
</div>
<div className="txt_cfm">
<label for="example-text-input">Modify CFM Rate Factor:</label>
<input
class="form-control"
type="textbox"
id="cfmRateFactor"
name="cfmRateFactor"
value={this.state.cfmRateFactor}
onChange={e => this.change(e)}
/>
</div>
<div>
<div>
<button type="submit" className="btn btn-primary">
Submit
</button>
</div>
</div>
</form>
</div>
</div>
</div>
);
}
}
export default Ast;
Could I please get some help with this? I'm still very new to using React JS.
You could use Map, it's a data structure for keeping key-value pairs. It will give you best performance for large data.
removeDuplicates(arr) {
const map = new Map();
arr.forEach(v => map.set(v.abc_buildingid, v)) // having `abc_buildingid` is always unique
return [...map.values()];
}
// this hook is better to start fetching data than componentWillMount
componentDidMount() {
fetch("https://api.myjson.com/bins/b1i6q", {
method: "GET",
headers: {
Accept: "application/json",
"Content-type": "application/json"
}
})
.then(results => results.json())
.then(data => this.setState({ data: this.removeDuplicates(data) })); // use the defined method
} //end life cycle
filter won't solve your problem. But reduce will.
You could have the following :
function removeDups(array) {
return array.reduce((result, elem) => {
if (!result.some((e) => e.abc_buildingid === element.abc_buildingid)) {
result.push(elem);
}
return result;
} , []);
}

How to use React SetState on nested data with empty top level names?

I have the following JSON data:
[
{"ID":1,"Latitude":"-41.276253","Longitude":"173.283842","Image":"Church.jpg"},
{"ID":2,"Latitude":"-41.267783","Longitude":"173.279114","Image":"Centre.jpg"}
]
I am trying to import it so it can be rendered & started with the following code:
componentDidMount() {
fetch('/home/briefsJson').then(response => response.json()).then(data => {
console.log(data);
this.setState({
latitude: data.Latitude,
longitude: data.Longitude,
image: data.Image
});
});
}
This doesn't as the data is multidimensional/nested. But every example I've found is using better structured data with top level names.
How can I use setState & render to display this data?
If you want to import json from a js file you would do it like this.
Data.js
const Data = [
{"ID":1,"Latitude":"-41.276253","Longitude":"173.283842","Image":"Church.jpg"},
{"ID":2,"Latitude":"-41.267783","Longitude":"173.279114","Image":"Centre.jpg"}
]
export default Data
Then import it where you want to use it. Now you can map through the data as you like.
App.js
import Data from './data'
import React, {Component} from 'react'
class App extends Component {
state = { Data:[] }
componentDidMount() { this.setState({ Data: Data }) }
render() {
return(
<div> {this.state.Data.map(item => <div> The id is: {item.ID} </div> }</div>
)
}
}
Maybe you want to change the names of the items, and return a new data structure with less attributes this is how you would do it.
componentDidMount() {
fetch('/home/briefsJson').then(response => response.json()).then(data => {
const newData = data.map(item => {
latitude:item.Latitude,
longitude: item.Longitude,
image: item.Image}
}
this.setState({
Data:newData
});
});
}
Now if you want to display this data in render.
renderData = () => {
return (
<div>
{this.state.Data.map(item => (
<div>
{item.latitude}
{item.longitude}
<img src={item.img} />
</div>
)}
</div>
)
}
render() {
return (
<div> {this.renderData()} </div>
)
}
It would probably just be easier to first construct what you want, then do a mapping in the rendering. It looks like you don't even need to do anything to convert it, since the json data is exactly what you want in the first place. So:
componentDidMount() {
fetch('/home/briefsJson').then(response => response.json()).then(data => {
console.log(data);
this.setState({ data });
});
}
render() {
return (
<div>
{this.state.data.map(datum => (element))}
</div>
);
}