How can I get URI from ApexCharts with React Js - javascript

I am trying to get the chart URI by using the Data URI method. I've seen a bunch of examples using Apexchart Js to get pdf like this CodePen from ApexChart, when trying to reproduce it on react I got TypeError: Cannot read property 'type' of undefined
Here is my component did mount look like this:
componentDidMount() {
console.log(this.state.loading);
if (this.state.loading === false) {
const {options} = this.state;
const node = ReactDOM.findDOMNode(this);
if (node instanceof HTMLElement) {
var chart = new ApexCharts(node.querySelector('.charty'), options);
chart.render().then(() => {
setTimeout(function() {
chart.dataURI().then(uri => {
console.log(uri);
});
}, 4000);
});
}
} else {
return;
}
}
Type is defined as well in my state and in the render like so :
<div className='rfe'>
<div className='rfea'>
From {this.state.AxisMonth[0]} to{' '}
{this.state.AxisMonth[this.state.AxisMonth.length - 1]}
</div>
<Chart
className='charty'
type='area'
options={this.state.options}
series={this.state.series}
width='1000'
height='380'
/>
</div>
</div>
here is the error I got
Really need help with this.

You can use the exec function to call any method of ApexCharts from a React component.
getDataUri() {
ApexCharts.exec("basic-bar", "dataURI").then(({ imgURI, blob }) => {
console.log(imgURI);
});
}
Here's a full codesandbox example

Related

How to test condition rendered elements with react testing library

I'm trying to cover my functionality with test, i have the image input:
<input
data-testid="fileuploadtestid"
type="file"
accept="image/*"
capture="camera"
onChange={uploadImage}
/>
On change method checks if file provided and creates the link;
const uploadImage = (e) => {
const { files } = e.target;
if (files?.length) {
const url = URL.createObjectURL(files[0]);
setImageUrl(url);
} else {
setImageUrl("");
}
};
Based on imageUrl value image renders conditionally:
{imageUrl && (
<img
data-testid="prevtestid"
className="preview_img"
src={imageUrl}
alt={imageUrl}
crossOrigin="anonymous"
ref={imageRef}
/>
)}
And i want to check if it renders correctly using react testing library to get the image element I use data-testid="prevtestid":
test("renders learn react link", async () => {
const { container, rerender } = render(<Home />);
global.URL.createObjectURL = jest.fn();
const file = new File(["(⌐□_□)"], "pug.png", { type: "image/png" });
const input = screen.getByTestId("fileuploadtestid");
fireEvent.change(input, { target: { files: [file] } });
rerender(<Home />);
expect(screen.getByTestId("prevtestid")).toBeInTheDocument();
}
);
I attached the latest version what have i tried to implement, i tried to use waitFor, rerender, render in various ways but i'm getting the same error all time:
Unable to find an element by: [data-testid="prevtestid"].
Please tell me how can i test it ?
The mock that you are creating is not really returning anything. You should return a url so that the components get's an imageUrl and is then able to show the <img /> element.
global.URL.createObjectURL = jest.fn().mockReturnValueOnce('https://www.samplerandomdomain.com/images/123.jpg');

Check prop values before loading component

I have a simple React component that injects an instance of the Rich Text Editor, TinyMCE into any page.
It is working, but sometimes a bad prop value gets through and causes errors.
I was wondering, if there is a way to check if the values of planetId or planetDescriptor are either empty or null before anything else on the page loads.
I tried wrapping all the code in this:
if(props)
{
const App = (props) => { ... }
}
But that always throws this error:
ReferenceError: props is not defined
Is there a way to check for certain values in props before I finish loading the component?
thanks!
Here is the app:
const App = (props) => {
const [planetDescriptor, setPlanetDescriptorState] = useState(props.planetDescriptor || "Planet Descriptor...");
const [planetId, setPlanetIdState] = useState(props.planetId);
const [planet, setPlanetState] = useState(props.planet);
const [dataEditor, setDataEditor] = useState();
const handleEditorChange = (data, editor) => {
setDataEditor(data);
}
const updatePlanetDescriptor = (data) => {
const request = axios.put(`/Planet/${planetId}/planetDescriptor`);
}
return (
<Editor
id={planetId.toString()}
initialValue={planetDescriptor}
init={{
selector: ".planetDescriptor",
menubar: 'edit table help'
}}
value={dataEditor}
onEditorChange={handleEditorChange}
/>
)
}
export default App;
You had the right idea in the conditional. Just need to put it inside the component rather than wrapping the whole thing. What you can try is something similar to what the react docs for conditional rendering has for a sample. What this does is it check if the props = null / undefined and then returns or renders the error state. Else it returns the Editor.
if (!props) {
return <h1>error state</h1>
}
return <Editor></Editor>
You can't wrap the code in the way you tried as you are working with JSX, not plain javascript, so you can't use the if statement there.
I suggest using a ternary, like so:
const SomeParentComponent = () => {
const propsToPass = dataFetchOrWhatever;
return (
<>
{propsToPass.planetDescriptor && propsToPass.planetId ?
<App
planetDescriptor={propsToPass.planetDescriptor}
planetId={propsToPass.planetId}
anyOtherProps={???}
/> :
null
}
</>
)
};
This will conditionally render the App component, only if both of those props exist.
You can also use && to have the same effect:
... code omitted ...
{propsToPass.planetDescriptor && propsToPass.planetId &&
<App
planetDescriptor={propsToPass.planetDescriptor}
planetId={propsToPass.planetId}
anyOtherProps={???}
/>
}
... code omitted ...
Which approach you use is largely up to preference and codebase consistency.

Cannot read property 'map' of undefined error. React Typescript

I have this code here. I keep getting an error:
TypeError: Cannot read property 'map' of undefined.
Here are a few facts:
I get data from the front-end javascript file. So there shouldn't be any async problems.
singleCategory.title Always displays correctly.
The error happens only if I refresh the page. If I comment out the map code and add code. So that React could inject it without refresh. It works. I only get an error if I refresh the page or try to navigate to it.
Why does singleCategory.title display correctly but using map is undefined? Also map is undefined only on refresh. If code is injected it works properly.
const CoursesCategories: React.FC = () => {
const [singleCategory, setSingleCategory] = useState<CategoriesInterface>([] as any);
useEffect(() => {
const fullUrl = window.location.href;
const segments = new URL(fullUrl).pathname.split('/');
const id = segments.pop() || segments.pop();
for (let category of Categories ) {
if (category.url === id) {
setSingleCategory(category);
console.log(singleCategory)
}
}
}, [singleCategory]);
return (
<div>
{
singleCategory.courses !== [] ? (
<div>
<CategoryTitle title={singleCategory.title} />
<div className={wrapper.headerWrapper}>
{
singleCategory.courses.map((course: CoursesInterface) => (
<h2 key={course.id}>{course.title}</h2>
)
)
}
</div>
</div>
) : ''
}
</div>
)
}
Edit 1. If I write like this I get.
Cannot read property 'length' of undefined
{ singleCategory.courses.length > 0 && singleCategory.courses.map((course: CoursesInterface) => (
<h2 key={course.id}>{course.title}</h2>
)
)}
Since you're using typescript you could use optional chaining :
{ singleCategory.courses?.length > 0
&& singleCategory.courses?.map((course: CoursesInterface) => (
<h2 key={course.id}>{course.title}</h2>
)
)}
because at the first rendering that property is not available.

`object` supplied to `ReactiveComponent`, expected `function`

I'm getting this error when trying to use ReactiveSearch for a search bar. This is how I'm initialising it:
render() {
const { tenantConfig, size, componentId } = this.props;
return (
<ReactiveComponent
componentId={componentId}
defaultQuery={this.defaultQuery}
>
<SearchDropdownDashboard
size={size}
handleSearchDashboard={this.handleSearchDashboard}
fetching={this.state.fetching}
tenantConfig={tenantConfig}
/>
</ReactiveComponent>
);
}
And this is the function that is being passed in:
defaultQuery = () => {
const { dashboardText } = this.state;
const { mustNotObj } = this.props;
let obj;
obj = {
query: {
bool: {
must_not: mustNotObj,
must: multiMatchSearch(dashboardText)
}
},
from: 0,
size: 20
};
return obj;
};
Any suggestions as to what I'm doing wrong here? The function seems to be passed correctly to the component.
If you are using v3, then it is due to the recent changes introduced in API. You will need to use render prop or React render Pattern as done in the below example.
You can check the docs here: https://opensource.appbase.io/reactive-manual/advanced/reactivecomponent.html#usage-with-defaultquery.
I have created the example of Usage of ReactiveComponent on both the versions:
v3 : https://codesandbox.io/s/serene-ritchie-rjo3m
v2 : https://codesandbox.io/s/tender-ramanujan-f3g31
Hope this helps!

Load external JSON in React

So I quite new to this. I want to load a external json file into react, and then use it.
The problem apparently is that the json hasn't been yet loaded, so I get errors. Like Cannot read property 'map' of undefined etc. The console.log give:
1
3
Uncaught TypeError: Cannot read property 'map' of undefined
So I've read this has to do with asynchronous things. But I can't find any example on how to fix it. Or how to make it work.
I would really appreciate it to see a small example like this, to make it work.
Later on I want to make it possible to filter the json with <input type=text etc> with some kind of dynamic search. But first things first. So can someone help me out?
This is my simple file:
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(){
super();
this.state = {
data: []
};
console.log('1');
};
componentDidMount() {
fetch("http://asite.com/file.json")
.then( (response) => {
return response.json() })
.then( (json) => {
this.setState({data: json});
console.log('2');
})
};
render() {
console.log("3");
return(
<div className="Employee">
{
this.state.data.employees.map(function(employee) {
return (
<div>
<h1> {employee.name} </h1>
</div>
)
})
}
</div>
)
}
}
export default App;
Since you have this.state.data.employees, I would assume you want to shape the initial state like this:
constructor(){
super();
this.state = {
data: {
employees: []
}
};
};
You can either choose to save to the state another variable which is flipped when you know you've loaded the data, or just check to ensure the data exists before trying to map it.
The latter could be done like below:
<div className="Employee">
{ this.state.data.employees &&
this.state.data.employees.map(function(employee) {
return (
<div>
<h1> {employee.name} </h1>
</div>
)
})
}
</div>
Or you could adjust the initial state to include an empty (but initialized) version of the return such as:
this.state = {
data: { employees: [] }
};
Checking to ensure the state contains the data field you're mapping is much safer though incase the return ever doesn't include the field.

Categories

Resources