ESLint: "'L' is not defined" at init with single file components - vue2leaflet

I'm ready to be told that I'm doing something plain stupid, because while I've prior experience with VueJS and with Leaflet, this is my first project using single file components for Vue, the first time I've used vue2-leaflet, and a fresh setup of node, npm and VueCLI, with none of which I'm very practiced - plenty of room for mistakes! However, I've been going round and round this all day, and it doesn't seem to make much sense.
Currently, the app is not far beyond the VueCLI created project. In main.js, I have put:
import { LMap, LTileLayer, LMarker } from 'vue2-leaflet';
import 'leaflet/dist/leaflet.css';
Vue.component('l-map', LMap);
Vue.component('l-tile-layer', LTileLayer);
Vue.component('l-marker', LMarker);
which is now right at the top of that file, in case my problems were to do with order of declaration and instantiation, but that doesn't seem to be the case.
I then have a 'mapiface.vue' file under src/views with associated route defined in index.js. Other than style informatin, the content of 'mapiface.vue' is:
<template>
<div id="mapview">
<l-map id="themap" :zoom="zoom">
<l-tile-layer :url="url" :attribution="attribution"></l-tile-layer>
</l-map>
</div>
</template>
<script>
module.exports = {
data() {
console.log(L); //Let's see whether L exists, then
return {
zoom:3,
center: L.latLng(47.413220, -1.219482),
url:'http://{s}.tile.osm.org/{z}/{x}/{y}.png',
attribution:'© OSM contributors',
//marker: L.latLng(47.413220, -1.219482),
}
}
}
</script>
As soon as I save this file, or refresh the output page, I get the following:
25:17 error 'L' is not defined no-undef
29:15 error 'L' is not defined no-undef
In the file, those line numbers correspond to my console.log and center lines.
However, in the console, right there under the above error, I get:
{…}
​
Bounds: function Bounds()​
Browser: Object { ie: false, ielt9: false, edge: false, … }
​
CRS: Object { latLngToPoint: latLngToPoint(), pointToLatLng: pointToLatLng()
, infinite: false, … }
​
Canvas: function NewClass()​
Circle: function NewClass()​
CircleMarker: function NewClass()​
Class: function Class()​
Control: function NewClass()​
DivIcon: function NewClass()​
DivOverlay: function NewClass()​
DomEvent: Object { on: on(), off: off(), stopPropagation: stopPropagation()
, … }
​
DomUtil: Object { TRANSFORM: "transform", TRANSITION: "webkitTransition", TRANSITION_END: "webkitTransitionEnd", … }
​
Draggable: function NewClass()​
Evented: function NewClass()​
FeatureGroup: function NewClass()​
GeoJSON: function NewClass()​
GridLayer: function NewClass()​
Handler: function NewClass()​
Icon: function NewClass()​
ImageOverlay: function NewClass()​
LatLng: function LatLng()​
LatLngBounds: function LatLngBounds()​
Layer: function NewClass()​
LayerGroup: function NewClass()​
LineUtil: Object { simplify: simplify(), pointToSegmentDistance: pointToSegmentDistance(), closestPointOnSegment: closestPointOnSegment()
, … }
​
Map: function NewClass()​
Marker: function NewClass()​
Mixin: Object { Events: {…} }
​
Path: function NewClass()​
Point: function Point()​
PolyUtil: Object { clipPolygon: clipPolygon()
}
​
Polygon: function NewClass()​
Polyline: function NewClass()​
Popup: function NewClass()​
PosAnimation: function NewClass()​
Projection: Object { LonLat: {…}, Mercator: {…}, SphericalMercator: {…} }
​
Rectangle: function NewClass()​
Renderer: function NewClass()​
SVG: function NewClass()​
SVGOverlay: function NewClass()
...
so L looks pretty defined to me!
I have tried moving declarations and import statements about, but to no avail. At this point, I'm lost and any help would be hugely welcome.

Solution:
import L from "leaflet";

Related

How to override local module interface in TypeScript?

I have a "library framework" nested inside my Next.js project (for now, as I don't want to go through the process of making it a standalone package yet). In that project I declare a few types, interfaces, and variables in one module, and then I try to override one of the interfaces from outside that module at the top-level of my app. So I have basically this:
components/
styles.ts // define interface here
package.d.ts // override module interface here
In package.d.ts I have this:
type AppFont = {
amharic: true
arabic: true
armenian: true
bengali: true
burmese: true
chinese: true
georgian: true
hebrew: true
hindi: true
inuktitut: true
japanese: true
kannada: true
khmer: true
korean: true
latin: true
malayalam: true
persian: true
tamil: true
text: true
thai: true
tibetan: true
}
declare module './components/styles' {
interface Font extends AppFont {}
}
In component/styles.ts I have this (amongst other variables and types):
export interface Font {
arial: true
}
export interface Theme {}
Also in my outer app I have this:
import { Font } from 'components/styles'
const fonts: Record<keyof Font, string> = {
amharic: 'Amharic',
arabic: 'Arabic',
armenian: 'Armenian',
bengali: 'Bengali',
burmese: 'Burmese',
chinese: 'Chinese',
georgian: 'Georgian',
hebrew: 'Hebrew',
hindi: 'Hindi',
inuktitut: 'Inuktitut',
japanese: 'Japanese',
kannada: 'Kannada',
khmer: 'Khmer',
korean: 'Korean',
latin: 'Latin',
malayalam: 'Malayalam',
persian: 'Persian',
tamil: 'Tamil',
text: 'text',
thai: 'Thai',
tibetan: 'Tibetan',
}
export const theme = {
fonts
}
export type AppTheme = typeof theme
So my final attempt at module override in package.d.ts looks like this:
declare module './components/styles' {
interface Font extends AppFont {}
interface Theme extends AppTheme {}
}
I then have a component like this inside the "nested library" (components/MyComponent.tsx):
type ComponentPropsType = {
font: keyof Font
}
export default function Component({
font,
}: ComponentPropsType) {
...
}
Since this component is in the library, it only has access to arial font. But since I overrode it, it should now accept all the fonts in the list. However, I am getting an error when I try and reference "tamil" font for example. So it's not picking it up.
What am I doing wrong? I am referencing the links here.

Tailwind ignoring darkMode: "class", not paying attention to class="dark" on html tag

Using tailwind and react, I am using a config file as follows:
/** #type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{html,js,jsx,ts,tsx}"],
darkMode: "class",
important: "#app",
theme: {
colors: {
...
},
fontFamily: {
...
},
extend: {},
},
plugins: [],
corePlugins: {
preflight: false,
},
};
and setting the class as follows
darkMode
? document.documentElement.classList.add("dark")
: document.documentElement.classList.remove("dark");
Inspecting the top element, it is indeed adding and removing a class="dark" to the top element. However, two elements like
text-grey-300 dark:text-grey-700
aren't changing when the class changes, at all. When the darkMode: Class is removed, it accurately follows OS preference however. Whats going on?
I have tried changing the class selector manually, tried placing the dark on other elements, moving the declaration around in my config file, none of it seems to help.

Remove Lines from MapboxGL map

I have a React function like the following. When a button is clicked, this function places a square on a map of the world at the specified coordinates (see code). However, I want to be able to press a different button and have the square removed. How can I do this? Is there a way to delete things from MapboxGL maps? If so, what function can I use?
The square is rendered using a function from MapboxGL and the web app is made using React JS.
React.useEffect(() => {
if(props.show) {
console.log(props);
var northEast = [131.308594, 46.195042];
var southEast = [117.597656, 8.233237];
var southWest = [79.101563, 32.842674];
var northWest = [86.847656, 44.715514];
// Add bounding box to the map
// Defines bounding box
globalMap.addSource('newroute', {
'type': 'geojson',
'data': {
'type': 'Feature',
'properties': {},
'geometry': {
'type': 'LineString',
'coordinates': [
northEast, southEast, southWest, northWest, northEast
]
}
}
});
// Draws bounding box
globalMap.addLayer({
'id': 'newroute',
'type': 'line',
'source': 'newroute',
'layout': {
'line-join': 'round',
'line-cap': 'round'
},
'paint': {
'line-color': '#ff0000',
'line-width': 5
}
});
}
});
Mapbox-GL has a remove layer method.
// If a layer with ID 'target-layer' exists, remove it.
if (map.getLayer('target-layer')) map.removeLayer('target-layer');
Another way to approach the issue is to keep the old layer, and update the data of the source with the new data (if your use-case allows for it).
"Remove layer" by setting the data of the source to an empty dataset:
map.getSource('target-source').setData({ type: "FeatureCollection", features: [] });
You can then set the data to a populated GeoJSON object if and when you have new data...

How to call function within component property?

When I try to call a method or set a state inside a property of a component in this case Sortablejs the method returns an undefined error.
<Sortable options={{
animation: 150,
onAdd: function(/**Event*/ evt) {
this.testFunction();//this doesnt seem to work??
},
group: {
name: "clone2",
pull: true,
put: true
}
}}
className="block-list A"
tag="ul"
>
{cloneControlledTarget}
</Sortable>
<Sortable
options={{
animation: 150,
sort: false,
group: {
name: "clone2",
pull: "clone",
put: false
}
}}
className="block-list"
tag="ul"
>
{cloneControlledSource}
</Sortable>
I think issue is in the following code. Use arrow function instead of traditional anonymous function
onAdd: function(/**Event*/ evt) {
this.testFunction();//this doesnt seem to work??
}
Use like this
onAdd: (/**Event*/ evt) => {
this.testFunction();
}
This should work if testFunction is available in your component.
You are passing an object
{
animation: 150,
onAdd: function(/**Event*/ evt) {
this.testFunction();
},
group: {
name: "clone2",
pull: true,
put: true
}
}
to the options attribute. So inside the function onAdd the value of "this" refers to the object properties. Since there is no testFunction inside the object, it will throw a reference error. Use arrow function instead.
onAdd: () => { this.testFunction() }

Why do I get TypeError: _this.data.forEach is not a function

I am trying to retrieve data from the backend. These are the relevant parts of my code:
API call
getData(PrimaryId:number):Observable<DataDto[]>{
return this.httpClient.get(`${this.prefix}/<xyz>/${PrimaryId}/xyz`) as Observable<DataDto[]>
}
Component TypeScript
onRetrieveClicked() {
this.xyzService.getData(this.PrimaryId).subscribe(
(xyz: DataDto[]) => {
this.xyz = xyz
console.log(this.xyz)
console.log(this.xyz.forEach((data)=>data.name)
})
}
First console.log output
{content: Array(1), pageable: {…}, totalPages: 1, totalElements: 1, last: true, …}
content: Array(1)
0: {name: max, name: null, asset: null, …}
length: 1
..........
But when I try to print only the name in the second console, it says that forEach is not a function. How can I solve this
edit
Dto model
export interface DataDto {
name: string
asset: abcDto
status: StatusDto
tasks: efgDto[]
nextDate: string
}
The xyz variable that you type as DataDto[], an array, is actually an object. This can be seen in your console.log, an array would be enclosed in [], not {}
is an object --> {
content: Array(1), pageable: {…}, totalPages: 1, totalElements: 1, last: true, …}
content: Array(1)
0: {name: max, name: null, asset: null, …}
length: 1
}
The data you are looking for is most likely the response object's content so add an import for import {map} from 'rxjs/operators'; and transform the data you've gotten from the response:
this.xyzService.getData(this.PrimaryId).pipe(
map((xyzResponse: any) => xyzResponse.content)
).subscribe(
(xyz: DataDto[]) => {
this.xyz = xyz;
console.log(this.xyz);
let dataNames = xyz.map(data => data.name);
console.log(dataNames);
}
I've typed xyzResponse as any but you could ofcourse create a reusable type for it if the API always returns the object with content, pageable, totalPages, ...
Rxjs is the library that Angular uses to handle asynchronous programming, such as HTTP calls or component events. Rxjs chains asynchronous manipulations together in a pipe (hence the .pipe call). Inside of this pipe rxjs expects a chain of operators that will perform operations on the asynchronous data, one by one. The map operator takes the input value and returns a new value so that the value you subscribe to has been transformed from the HTTP response to the .content field of the HTTP response.
Working in this way fixes all TypeScript compiler errors and allows you to chain additional calls later, like retrying if the API times out, or catching errors, or merging in other HTTP calls.
It seems that your this.xyz is not an array, but has an array property called content, you should modify your response object in order to accept it.
You can check if your objects are arrays with the following method
Array.isArray(obj)
Update your code to this.
this.xyzService.getData(this.PrimaryId).subscribe(
(xyz: NewObject) => {
this.xyz = xyz
console.log(this.xyz)
//If you have doubts of what is comming is nice to check if your property is an array
if(Array.isArray(this.xhy.content) {
console.log(this.xyz.content.forEach((data)=>data.name) });
}
}
Create a new object in order to support your response
class NewObject {
content: Array<DataDto>
// other values here
}
Another approach is like #Robin says in the comment
this.xyzService.getData(this.PrimaryId).subscribe((xyz: {content: DataDto[]}) =>
{
this.xyz = xyz
console.log(this.xyz)
//If you have doubts of what is comming is nice to check if your property is an array
if(Array.isArray(this.xhy.content) {
console.log(this.xyz.content.forEach((data)=>data.name) });
}
}
It's because you are trying to loop through an object instead of array
I think you can try this:
console.log(this.xyz.content.forEach((data)=>data.name) })

Resources