Using leaflet.markercluster with a Nuxt 3 app - leaflet

I'm using Leaflet with Nuxt3, TypeScript and Composition API on a production website.
As we're getting more and more markers, I'd like to use leaflet.markercluster but I can't get how to make it work properly
Here's my setup :
leaflet.client.ts
import {
LIcon,
LMap,
LMarker,
LPopup,
LTileLayer,
} from "#vue-leaflet/vue-leaflet";
import L from "leaflet";
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.component("LMap", LMap);
nuxtApp.vueApp.component("LTileLayer", LTileLayer);
nuxtApp.vueApp.component("LMarker", LMarker);
nuxtApp.vueApp.component("LIcon", LIcon);
nuxtApp.vueApp.component("LPopup", LPopup);
return {
provide: {
L,
},
};
});
Map.vue
<client-only>
<l-map
ref="locationsMap"
:min-zoom="leafletOptions.minZoom"
:max-zoom="leafletOptions.maxZoom"
:zoom-animation="true"
:zoom="leafletOptions.zoom"
:center="leafletOptions.center"
:useGlobalLeaflet="false"
:options="{ tap: false }"
#ready="onLeafletReady">
<l-tile-layer :url="leafletOptions.url"/>
<template v-for="location in locations"
:key="location.id">
<l-marker
:lat-lng="[location.attributes.lat, location.attributes.long]"
v-if="location.attributes.active">
<div v-if="location.attributes.lat && location.attributes.long">
<l-popup class="text-center flex flex-col gap-y-4">
...
</l-popup>
<l-icon>
...
</l-icon>
</div>
</l-marker>
</template>
</l-map>
...
</client-only>
<script setup lang="ts">
import {LIcon, LMap, LMarker, LPopup, LTileLayer} from "#vue-leaflet/vue-leaflet";
import "leaflet/dist/leaflet.css";
const leafletOptions = ref({
url: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png",
minZoom: 5,
maxZoom: 13,
zoom: 5.5,
map: null,
center: [47.040182, 2.536054],
bounds: null,
overlayLocation: false,
colors: ["#ED722E", "#F6BE00", "#979B0B", "#DA2C81"],
});
// Setup and api calls to get locations
</script>
package.json
{
...,
"depencencies": {
"#vue-leaflet/vue-leaflet": "^0.7.0",
"leaflet": "^1.9.3",
"leaflet.markercluster": "^1.5.3",
},
"devDependencies": {
"nuxt": "^3.0.0",
"typescript": "^4.9.4"
"#types/leaflet.markercluster": "^1.5.1",
}
}
The thing is, now I try to group my markers by adding leaflet.markercluster. So I added something like this :
leaflet.client.ts
...
import "leaflet.markercluster";
import "leaflet.markercluster/dist/MarkerCluster.css";
import "leaflet.markercluster/dist/MarkerCluster.Default.css";
export default defineNuxtPlugin((nuxtApp) => {
...
return {
provide: {
L,
},
};
});
But now I don't know what to do next. Using L.markerClusterGroup() as the official documentation says does not work as we get a 500 error for using a client-side method with ssr.
I also tried to directly import in my component with import :
Map.vue
import { MarkerClusterGroup } from 'leaflet.markercluster';
const markersGroup = ref(null);
...
const onLeafletReady = async () => {
markersGroup.value = new MarkerClusterGroup() // NOT WORKING
await nextTick();
leafletObject.value = locationsMap.value;
leafletReady.value = true;
leafletObject.value.addLayer(markersGroup.value)
}
But we got the same problem as using L.anyMethod() by getting a 500 error.
I saw that Sam85 on this question has the package installed, but that was not the same problem. :/
Has anyone ever tried to make it work with Nuxt 3 ?

Related

SvelteKit console error "window is not defined" when i import library

I would like to import apexChart library which using "window" property, and i get error in console.
[vite] Error when evaluating SSR module /src/routes/prehled.svelte:
ReferenceError: window is not defined
I tried use a apexCharts after mount, but the error did not disappear.
<script>
import ApexCharts from 'apexcharts'
import { onMount } from 'svelte'
const myOptions = {...myOptions}
onMount(() => {
const chart = new ApexCharts(document.querySelector('[data-chart="profit"]'), myOptions)
chart.render()
})
</script>
I tried import a apexCharts when i am sure that browser exist.
import { browser } from '$app/env'
if (browser) {
import ApexCharts from 'apexcharts'
}
But i got error "'import' and 'export' may only appear at the top level"
I tried disable ssr in svelte.config.js
import adapter from '#sveltejs/adapter-static';
const config = {
kit: {
adapter: adapter(),
prerender: {
enabled: false
},
ssr: false,
}
I tried to create a component in which I import apexChart library and I created a condition that uses this component only if a browser exists
{ #if browser }
<ProfitChart />
{ /if }
Nothing helped.
Does anyone know how to help me please?
The easiest way is to simply include apexcharts like a standalone library in your webpage like this:
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
And then simply use it in the onMount:
onMount(() => {
const chart = new ApexCharts(container, options)
chart.render()
})
You can add this line either in your app.html or include it where it's required with a <svelte:head> block.
An alternative way would be to dynamically import during onMount:
onMount(async () => {
const ApexCharts = (await import('apexcharts')).default
const chart = new ApexCharts(container, options)
chart.render()
})
As an extra: use bind:this instead of document.querySelector to get DOM elements, that would be the more 'svelte' way.
I have found the last option with the Vite plugin to work best with less code in the end but will lose intellisense in vscode and see import highlighted as error (temp workaround at end): https://kit.svelte.dev/faq#how-do-i-use-x-with-sveltekit-how-do-i-use-a-client-side-only-library-that-depends-on-document-or-window
Install vite plugin: npm i -D vite-plugin-iso-import
Add plugin to svelte.config.js:
kit: {
vite: {
plugins: [
isoImport(),
],
Add plugin to TypeScript config (if you use TS):
"compilerOptions": {
"plugins": [{ "name": "vite-plugin-iso-import" }],
Use as normal but note the "?client" on the import:
<script context="module">
import { chart } from 'svelte-apexcharts?client';
import { onMount } from 'svelte'
let myOptions = {...myOptions}
onMount(() => {
myOptions = {...updated options/data}
});
</script>
<div use:chart={myOptions} />
Debugging note:
To have import not highlighting as an error temporarily, just:
npm run dev, your project will compile fine, then test in browser to execute at least once.
remove ?client now, save and continue debugging as usual.
For all of you trying to import dynamically into a js or ts file, try the following:
Import your package during on mount in any svelte component.
onMount(async () => {
const Example = await import('#creator/examplePackage');
usePackageInJSOrTS(Example.default);
});
Use the imported package in your js/ts function. You need to pass the default value of the constructor.
export function usePackageInJsOrTs(NeededPackage) {
let neededPacakge = new NeededPackage();
}

The bootstrap-vue <b-modal> does not appear

I need to create a modal that pop-ups when the button is clicked; i tried with bootstrap-vue, following the documentation but it didn't worked.
I put in my vue project but it doesn't work. The button is there, but when i click the modal doesn't appear. When i go to the console, it says that the directive is not recognized. I will put the code and the error below
<template>
...
<c-card>
<div>
<b-button v-b-modal.exclude class="center" size="lg" variant="danger">Excluir conta</b-button>
<b-modal id="exclude" title="bootstrapVue">
<p class="my-4">Are you sure that you want to exclude your account?</p>
</b-modal>
</div>
</c-card>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex'
import cCard from '#/components/Card'
import pStatusAchievements from './_partials/StatusAchievements'
import pStatusApps from './_partials/StatusApps'
import pStatusNetwork from './_partials/StatusNetwork'
import pStatus from './_partials/Status'
import pStatusPublication from './_partials/StatusPublication'
import pMyAccount from './MyAccount'
import pPowerUp from './_partials/PowerUp'
import {BModal, VBModal} from 'bootstrap-vue'
const cContentHeader = () => import('#/components/ContentMiddleHeader')
export default {
name: 'Perfil',
components: {
cContentHeader,
cCard,
pStatusPublication,
pStatusNetwork,
pStatusApps,
pMyAccount,
pStatusAchievements,
pStatus,
pPowerUp,
BModal,
},
data () {
return {
pubStatus: 1200,
networkApps: [
{ name: 'network', title: 'rede' },
{ name: 'appsUsage', title: 'uso dos apps' }
]
}
},
directives: {
'b-modal': VBModal
},
That is the vue-warn
[Vue warn]: Unknown custom element: <b-modal> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
found in
---> <Perfil> at src/views/perfil/Perfil.vue
<MFeed> at src/views/mobile/mFeed.vue
<SlideXLeftTransition>
<NavbarContent> at src/views/mobile/mContent.vue
<NavbarContent> at src/layouts/main/MainLayout.vue
<FadeTransition>
<App> at src/App.vue
<Root

Angular 4 Data table implementation into my APP

I have created custom component DisplayTableComponent in my project. I want to incorporate Angular 4 Data table on my data for display purpose.
DisplayTableComponent.TS is as follows
import { Component, OnInit } from '#angular/core';
import { DataTableResource } from 'angular-4-data-table';
import { DataTableModule } from 'angular-4-data-table';
import persons from './data-table-demo1-data';
#Component({
selector: 'app-display-table',
templateUrl: './display-table.component.html',
styleUrls: ['./display-table.component.css']
})
export class DisplayTableComponent implements OnInit {
itemResource = new DataTableResource(persons);
items = [];
itemCount = 0;
constructor() {
this.itemResource.count().then(count => this.itemCount = count);
}
ngOnInit() {
}
reloadItems(params) {
// this.itemResource.query(params).then(items => this.items = items);
}
// special properties:
rowClick(rowEvent) {
console.log('Clicked: ' + rowEvent.row.item.name);
}
rowDoubleClick(rowEvent) {
alert('Double clicked: ' + rowEvent.row.item.name);
}
rowTooltip(item) { return item.jobTitle; }
}
My Html Template is as follows
<p>
display-table works!
</p>
<div style="margin: auto; max-width: 1000px; margin-bottom: 50px;">
<data-table id="persons-grid"
headerTitle="Employees"
[items]="items"
[itemCount]="itemCount"
(reload)="reloadItems($event)"
(rowClick)="rowClick($event)"
(rowDoubleClick)="rowDoubleClick($event)"
[rowTooltip]="rowTooltip"
>
<data-table-column
[property]="'name'"
[header]="'Name'"
[sortable]="true"
[resizable]="true">
</data-table-column>
<data-table-column
[property]="'date'"
[header]="'Date'"
[sortable]="true">
<ng-template #dataTableCell let-item="item">
<span>{{item.date | date:'yyyy-MM-dd'}}</span>
</ng-template>
</data-table-column>
<data-table-column
property="phoneNumber"
header="Phone number"
width="150px">
</data-table-column>
<data-table-column
[property]="'jobTitle'"
[header]="'Job title'"
[visible]="false">
</data-table-column>
<data-table-column
[property]="'active'"
[header]="'Active'"
[width]="100"
[resizable]="true">
<ng-template #dataTableHeader let-item="item">
<span style="color: rgb(232, 0, 0)">Active</span>
</ng-template>
<ng-template #dataTableCell let-item="item">
<span style="color: grey">
<span class="glyphicon glyphicon-ok" *ngIf="item.active"></span>
<span class="glyphicon glyphicon-remove" *ngIf="!item.active"></span>
</span>
</ng-template>
</data-table-column>
</data-table>
</div>
Now, The temporary source data file (data-table-demo1-data.ts) is as
export default [
{ 'name': 'Aaron 2Moore', 'email': 'aaa#aa.com', 'jobTitle': 'Regional Configuration Producer',
'active': true, 'phoneNumber': '611-898-6201', 'date': '2015-11-06T07:21:25.510Z' },
{ 'name': 'Yvonne Conroy Mrs.', 'email': 'sss#ssss.com', 'jobTitle': 'Global Mobility Orchestrator',
'active': false, 'phoneNumber': '115-850-0969', 'date': '2014-12-20T00:48:40.276Z' },
]
My app.Module.TS is as follows
import { BrowserModule } from '#angular/platform-browser';
import { NgModule,CUSTOM_ELEMENTS_SCHEMA } from '#angular/core';
import { Routes, RouterModule} from '#angular/router';
import { DataTableModule } from 'angular-4-data-table';
import { AppComponent } from './app.component';
import { HomeComponent } from './home/home.component';
import { MovieComponent } from './movie/movie.component';
import { DisplayTableComponent } from './display-table/display-table.component';
const appRoute: Routes =[
{ path: '', redirectTo: 'home', pathMatch: 'full' },
{path:'home', component:HomeComponent},
{path:'Movie', component:MovieComponent},
{path:'table', component:DisplayTableComponent},
];
#NgModule({
declarations: [
AppComponent,
HomeComponent,
MovieComponent,
DisplayTableComponent
],
imports: [
BrowserModule,
RouterModule.forRoot(appRoute)
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Could you please help me. I am getting below error
ERROR in ./node_modules/angular-4-data-table/src/index.ts
Module build failed: Error: C:\projects\Handson\website1\node_modules\angular-4-data-table\src\index.ts is missing from the TypeScript compilation. Please make sure
it is in your tsconfig via the 'files' or 'include' property.
The missing file seems to be part of a third party library. TS files in published libraries are often a sign of a badly packaged library. Please open an issue in the library repository to alert its author and ask them to package the library using the Angular Package Format
at AngularCompilerPlugin.getCompiledFile (C:\projects\Handson\website1\node_modules\#ngtools\webpack\src\angular_compiler_plugin.js:656:23)
at plugin.done.then (C:\projects\Handson\website1\node_modules\#ngtools\webpack\src\loader.js:467:39)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
# ./src/app/display-table/display-table.component.ts 13:29-60
# ./src/app/app.module.ts
# ./src/main.ts
# multi webpack-dev-server/client?http://0.0.0.0:0 ./src/main.ts
It seems you are using angular 5 cli and need to integrate Angular 4 Data table on to your project.
My advice is to use angular5-data-table instead of version 4 if you are using angular 5.You can find it on https://www.npmjs.com/package/angular5-data-table

PrimeNG new Chart Release in R.C.1

I have update my primeNG to version to RC.1.
While doing so, I have made all the necessary changes required to run the application. Its been running fine.
Problem is that in this updated version, the Chart implementation has been changed.
Rather than using we have to use
After doing this change, I am not getting the component rendered on my browser. It is not giving any error in the console.
following is my code:
app.component.ts File:
import {Component} from '#angular/core';
import {HTTP_PROVIDERS} from '#angular/http';
import {InputText,DataTable,Button,Dialog,Column,Header,Footer} from 'primeng/primeng';
export class AppComponent {
data :any;
constructor(private carService: CarService) {
this.data = {
labels: ['A','B','C'],
datasets: [
{
data: [300, 50, 100],
backgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
],
hoverBackgroundColor: [
"#FF6384",
"#36A2EB",
"#FFCE56"
]
}]
};
}
}
app.conponent.html:
<div>
<p-chart type="pie" [data]="data"></p-chart>
</div>
Please help.
Thanks in Advance.

Meteor does not display collection that exists in db

A Meteor/React noob here, going through the Meteor-React tutorial and got stuck on step 3. My problem is that the data is not being displayed in the browser, although it exists in the db.
Here is my imports/ui/App.jsx:
import React, { Component, PropTypes } from 'react';
import { createContainer } from 'meteor/react-meteor-data';
import { Tasks } from '../api/tasks.js';
import Task from './Task.jsx';
class App extends Component {
renderTasks() {
return this.props.tasks.map((task) => (
<Task key={task._id} task={task} />
));
}
render() {
return (
<div className="container">
<header>
<h1>Todo List</h1>
</header>
<ul>
{this.renderTasks()}
</ul>
</div>
);
}
}
App.propTypes = {
tasks: PropTypes.array.isRequired,
};
export default createContainer(() => {
return {
tasks: Tasks.find({}).fetch(),
};
}, App);
No errors show up in console.
Basically this.props.tasks returns empty array. But db.tasks.find({}) in console shows records. Without changing much around, if I hardcode Tasks records, they display alright, so the issue isn't with Task component. Anyone can help here? Would much appreciate.
client/main.jsx:
import React from 'react';
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
import App from '../imports/ui/App.jsx';
Meteor.startup(() => {
render(<App />, document.getElementById('render-target'));
});
package.json:
{
"name": "simple-todos",
"private": true,
"scripts": {
"start": "meteor run"
},
"dependencies": {
"meteor-node-stubs": "~0.2.0",
"react": "^15.1.0",
"react-addons-pure-render-mixin": "^15.1.0",
"react-dom": "^15.1.0"
}
}
npm version 3.3.12
node version 5.6.0
As of your description from, it seems that your database is not accessible on both server & client. May be you forgot to add the reference of your database in the server side. try to import your tasks main.js file of your server.
Make sure your server/main.js has the following line:
import '../imports/api/tasks.js';