leaflet-radar + react : checkbox_div is not defined error - reactjs

Note: Using React
I'm having trouble setting up a radar in my leaflet map object. I'm able to generate the map easily, but I get an error when I try adding a radar to the map.
The issue comes from this slice of code:
import RadarMap from 'leaflet-radar'
.
.
.
drawMap(){
let radar;
this.map = L.map(this.id);// eslint-disable-line
this.map.setView([this.latitude, this.longitude], this.zoom);
L.tileLayer("https://tile-{s}.openstreetmap.fr/hot/{z}/{x}/{y}.png", { // eslint-disable-line
accessToken: this.accessToken
}
).addTo(this.map);
radar = new L.Control.Radar({}); // eslint-disable-line
radar.addTo(this.map);
}
The error specifically occurs when I call this line:
radar.addTo(this.map);
If I don't call this line, my code will correctly generate a map. But this one line
breaks the map.
To be frank, I've been working on this error for hours now. I've altered this code zealously;
yet iteration after iteration, I still can't get this radar to work. If anyone knows how to help me with this problem, I'd be extremely grateful.

I figured out the problem.
Leaflet-radar was trying to use a global variable named checkbox_div. Since checkbox_div did not exist as a global variable, an error was raised. Adding checkbox_div as a global variable fixed the error.
I solved this error by using globalThis in the constructor of the element and using that to add a global variable.
constructor(props){
super(props);
globalThis.checkbox_div = undefined; // eslint-disable-line
}
In my solution, I gave checkbox_div the value of undefined, but I think it's possible to give checkbox_div any value. Just instantiating checkbox_div is the key.
An alternative solution would be to simply add checkbox_div in the .html file like this
<script>
var checkbox_div;
</script>

Related

TypeDI: class in injected service is not a function or service is not found

I'm using TypeDI in a Typescript ReactJS project and I need to generalize the User Repository/retrieval.
So what I did up to now is having an interface:
export interface IAdminUserService{
getUsers():User[];
getUser(id:string):User;
...
}
Have an implementation:
#Service('aws-user-service')
class AWSUserService implements IAdminUserService {
...various implementations for interface methods...
}
And finally, the class I'll be using, the one I should inject the other one in:
#Service('user-service')
export class AdminUserService{
constructor(
#Inject('aws-user-service') public service:AWSUserService
){
}
}
Then when I need to actually use that stuff, I try to run the following:
const adminUserService: AdminUserService = Container.get<AdminUserService>('user-service'); // throw ServiceNotFound error
or the following:
const adminUserService: AdminUserService = Container.get<AdminUserService>(AdminUserService); // kinda good
adminUserSerivce.service.getUsers() // throws 'adminUserSerivce.service.getUsers' is not a function
I did put import 'reflect-metadata'; on top of each file using TypeDI.
So now I really don't know what to do/try to make this work.
I even try to use Container.set(<id>, <class>) before using the Container.get(<class|id>) but it doesn't change anything at all.
Also tried not putting strings into the #Service() decorator or even putting an object like {id:<id>} but still, nothing seems to work properly.
Am I doing something wrong? should I fix something, somewhere?
EDIT:
Just tried the sample code from the TypeDI page and I'm getting the same exact error: serviceInstance.injectedService.printMessage is not a function so it might probably be something related to the library, more than my code itself.

Get Class Name of Class Subclassing Array in TypeScript?

I have the following class (ported from JavaScript wherein this works [prior to adding the types]) within TypeScript:
class A extends Array {
private _foo: string;
constructor(settings: any) {
super();
this._foo = 'foo';
}
get Foo() {
return (this._foo);
}
set Foo(value) {
this._foo = value;
}
}
let test = new A({ });
test.push('1');
test.push(2);
test.push('3');
// outputs "A" in JavaScript
// outputs "Array" in TypeScript
console.log(test.constructor.name);
The issue is outlined at the bottom of the code snippet, I'm expecting to get the class name back from test.constructor.name of "A" but am instead getting "Array". It seems like in the specific case of subclassing Array objects, TypeScript blows away the constructor name. Is there a way to find the class name within TypeScript which doesn't rely upon .constructor.name?
This happens because you have es5 as a target in compilerOptions and Typescript polyfills class
Have a look at generated code for es5 vs ES2015.
If you don't need to support really old browsers you can safely use a higher target than es5
I've tested your code in the Playground here
And it correctly outputs "A". I suspect something else is going on, possibly with your build tools or config.
I would suggest trying to use just tsc to narrow down the problem. If tsc correctly outputs, you can then move on to any other plugins, or build steps

Calling push() on array, TypeError: Attempted to assign to readonly property

Working in React Native. I'm trying to declare an array and then push things to said array, but I'm getting the error TypeError: Attempted to assign to readonly property
CONTEXT:
The app prints via a thermal printer.
The print method receives an array of commands
Example:
print([{appendText: "blah"}, {
appendCutPaper: StarPRNT.CutPaperAction.PartialCutWithFeed,
}]
The print method is asynchronous and if you attempt to call the method again before the last call has finished, it errors.
Because of #2, we created a queue system that accepts a job (array of commands) and then works through the jobs synchronously.
In a React component, I'm attempting to create a job by declaring an empty array named printJob
and then pushing various commands to it. In this case, we take a snapshot of a View and then push the commands returned by the printImage method to the printJob array.
onClick={() => {
const printJob = []
viewShot.current
.capture()
.then((uri) => {
printJob.push(...printImage(uri))
})
.catch((err) => alert(err))
newPrintJob(printJob)
}
printImage returns the array of commands to print an image and cut the paper:
const CUT_PAPER = {
appendCutPaper: StarPRNT.CutPaperAction.PartialCutWithFeed,
}
export function printImage(uri) {
return [{ appendBitmap: uri }, CUT_PAPER]
}
So the goal is to generate the array of commands and pass that to the queue as a job. Now, I could just do newPrintJob(printImage(uri)) in the above case, which works completely fine. However, there is a particular setting the user can configure where it will need to print multiple images, one per ticket (in other words, multiple printImages). I want to consider all of that one job, hence the need to create the printJob array.
THE PROBLEM:
I'm getting an error TypeError: Attempted to assign to readonly property which seems to be triggered by printJob.push(...printImage(uri)). If I comment that line out, the error doesn't get thrown.
I don't understand why this would happen because you can call push on an array, even if it's declared as a constant. I also tried declaring it with var and let and still received the same error.
I hope I've provided enough context here. LMK if I need to add more.
Additional info:
"react": "16.13.1"
"react-native": "~0.63.3"
Turns out the issue was not pushing to the array. The issue was was trying to add the job to the queue:
newPrintJob(printJob)
...outside of the async's callback. Solution was to move the newPrintJob line into the .then block.

How to include mxFloorplan.js in mxGraph inside React application using Typescript?

So I'm trying to create a simple react application to render a mxGraph that I'm loading from a file. I can load the model, but some shapes aren't rendering correctly. The problem is that they are a specific shape, that are part of the floorplan package, and I can't find a way to include those shapes in my code.
ps.: I'm new to working with mxGraph.
Things I tried
First thing I tried was downloading the mxFloorplan.js file into my application, and import it, like so:
// App.tsx
import './models/mxFloorplan'
const mx = factory({
mxBasePath: './models'
})
let graph: mxGraph
...
Because the docs on extending mxShape show that I should register a new shape: mxCellRenderer.registerShape('customShape', CustomShape); and the mxFloorplan.js file does that.
I then simply added this to the beggining of the file:
// mxFloorplan.js
import Graph, {
mxShape,
mxUtils,
mxCellRenderer,
mxPoint
} from 'mxgraph'
...
But then I get this error:
Then I thought that I needed mxCellRenderer to be linked to my graph instance? So I tried moving one of the shape definitions into App.jsx to test:
// App.jsx
const mx = factory({
mxBasePath: './models'
})
let graph: mxGraph
function mxFloorplanWall(bounds: any, fill: any, stroke: any, strokewidth: any)
{
mx.mxShape.call(this); <-- Error: "Expected 2 args, but got one"
this.bounds = bounds;
this.fill = fill;
this.stroke = stroke;
this.strokewidth = (strokewidth != null) ? strokewidth : 1;
};
/**
* Extends mxShape.
*/
mx.mxUtils.extend(mxFloorplanWall, mxShape); <-- Error: "Property 'extend' does not exist on type mxUtils
// ... more code
mx.mxCellRenderer.registerShape(mxFloorplanWall.prototype.cst.WALL, mxFloorplanWall); <-- Error: mxFloorplanWall type not compatible with expected.
Really don't know how to solve these ones. On my research I only find references to
mxCellRenderer.registerShape('name', CustomShape), so not really sure on the rest.
How it looks
Here is how the diagram looks like (ignore the arrow and labels, please):
Here is what I'm actually rendering (the "black boxes" have shape=shape=mxgraph.floorplan.wallU):
As described in https://jgraph.github.io/mxgraph/docs/js-api/files/shape/mxShape-js.html, you must pass a constructor to mxCellRenderer.registerShape
function CustomShape() { }
CustomShape.prototype = new mxShape();
CustomShape.prototype.constructor = CustomShape;
// To register a custom shape in an existing graph instance,
// one must register the shape under a new name in the graph’s cell renderer
// as follows:
mxCellRenderer.registerShape('customShape', CustomShape);
}
I guess your issues come from a wrong port of drawio code (that use a very old Javscript syntax) and is not related to React at all. It is currently unclear to me what you are exactly have implemented. Here are some hints.
If you use TypeScript, the mxCellRenderer.registerShape signature is enforced by the mxgraph types https://github.com/typed-mxgraph/typed-mxgraph/blob/v0.0.5-0/view/mxCellRenderer.d.ts#L83.
When porting the mxFloorplanWall code to Typescript you should have a constructor like in the following (please avoid any!)
export class mxFloorplanWall extends mxShape { // or extends mx.mxShape depending how you manage mxgraph imports
public constructor(bounds: mxRectangle, fill: string, stroke: string, strokewidth: number) {
super(bounds, fill, stroke, strokewidth);
}
...
}
Calling super directly set the arguments in super class and avoid the errors
// mx.mxUtils.extend(mxFloorplanWall, mxShape); <-- Error: "Property 'extend' does not exist on type mxUtils
// avoid mx.mxShape.call(this); <-- Error: "Expected 2 args, but got one"
Same if you use Javascript, prefer the ES6 class syntax to declare the mxFloorplanWall class.

Extending Array in Typescript breaks constructor

while playing around with typescript I ran into then following interesting behavior:
class ExtArray<U> extends Array<U> {
constructor(...args : U[]) {
super(...args);
}
public contains(element : U) : boolean {
var i = this.indexOf(element);
return i !== -1;
}
}
var test : ExtArray<string> = new ExtArray("a", "b", "c");
test.push("y");
console.log(test.length); // 1
console.log(test[0]); // y
console.log(test[1]); // undefined
console.log("Has a: " + test.contains("a")); // Has a: false
console.log("Has y: " + test.contains("y")); // Has y : true
I've added the output of the console.log statements as comments.
See this typescript playground for an executable example and the javascript code.
As you can see it seems as if the elements passed to the constructor are not added to the array.
The section about extending expression in Whats new in Typescript suggests that it should be possible to extend the native Array type like that in typescript 1.6.
Also I didn't find anything in the typescript language reference,
that explains this behavior.
Most of the other questions about extending Arrays I found here are at least one year old and usually talk about a pre-1.0 version of typescript and therefore suggest to set up the prototype chain directly.
I seriously don't see what is going wrong here and I'm starting to suspect a typescript bug.
Or at least some kind of undocumented restriction for extending Arrays.
What goes wrong here?
It's a little easier to understand what's going on if you JSON.stringify() your object:
var test : ExtArray<string> = new ExtArray("a", "b", "c");
test.push("y");
// outputs {"0":"y","length":1}
document.writeln(JSON.stringify(test));
If you instead new-up a native Array, the resulting object is quite a bit different:
var test : Array<string> = new Array("a", "b", "c");
test.push("y");
// outputs ["a","b","c","y"]
document.writeln(JSON.stringify(test));
I agree with you that the documentation seems to imply that the subclass's constructor should behave the way you're expecting. Even stranger, I seem to get inconsistent results when testing whether or not the subclass is an Array using the methods described here:
test.constructor === Array // false
test instanceof Array // true
Array.isArray(test) // false
I would suggest opening an issue on the TypeScript GitHub repository. Even if this is the expected behavior, the official documentation is misleading and should clarify what exactly is expected when native objects are subclassed.

Resources