I'm kinda new to Vue.js but today I am trying to setup some sort of map to show data. I ended up picking Highmaps since it seemd like the best alternative of the bunch and also because I already used it (Highcharts) for other projects.
Now the problem arises because I am developing a component driven webapp but I want to import maps from Highmaps. Since they just use CDN paths I don't really know how to implement them by using the import statement. Below is some code to make you understand better.
--- main.js ---
import Vue from 'vue'
import App from './App'
import MapComponent from './components/MapComponent.vue'
import Highcharts from 'highcharts';
import HighMaps from '../node_modules/highcharts/highmaps.js'
import VueHighcharts from 'vue-highcharts'
import loadMap from 'highcharts/modules/map';
loadMap(Highcharts);
Vue.use(VueHighcharts, { Highcharts });
Vue.use(HighMaps);
Vue.component('app-map', MapComponent)
new Vue({
el: '#app',
router: router,
components: { App },
template: '<App/>'
})
------------------------
--- MapComponent.vue ---
<template>
<div>
<highmaps :options="chartOptions"></highmaps>
</div>
</template>
<script>
import Element from 'element-ui';
import axios from 'axios';
import HighCharts from 'vue-highcharts';
export default {
data () {
return {
chartOptions: {
chart: {
map: 'countries/it/it-all'
},
...
}
},
}
</script>
This is what you can see from the browser, the errors appear when I try to press the + / - or when I scroll inside the map's borders
As you can see inside the script tag I already imported some libraries but I can't undestand how to import Highmaps too.
I can see in the image you have an error:
Uncaught ReferenceError, HighCharts is not defined at ...
This is because, whenever you import a library for Vue, you should provide it as a component.
So, you have to add this:
import HighCharts from 'vue-highcharts';
export default {
//...
components: { HighCharts },
//...
}
The problem here it's that the CDN imports VueHighcharts, you can register it globally as
Vue.use(VueHighcharts, { Highcharts: Highcharts })
and then use it everywhere
<highmaps :options="options"></highmaps>
Take a look at the examples on the bottom of the Lib Readme
Also, it's better to install it via npm to have a better modular structure to work with webpack (or whatever you use)
Right now I have found a way (probably cheesy) to force the map data into the map itself by copy pasting the object inside a variable and then referencing it into the chart.map
I understand that this is probably very bad since Vue needs to go and compile all of that object right inside the component but I hope it is a temporary solution.
<template>
<div>
<highmaps :options="chartOptions"></highmaps>
</div>
</template>
<script>
import Element from 'element-ui';
import axios from 'axios';
import HighCharts from 'vue-highcharts';
export default {
data () {
var country= {"title":"Italy","version":"1.1.2","type":"FeatureCollection","copyright":"Copyright...}
return {
chartOptions: {
chart: {
map: country
},
...
}
</script>
You can find the map data at this url (choose the GeoJSON option)
EDIT
I have finally found a good way of doing this by just saving the raw json data of the map into a local .json file and importing it as follows:
<template>
<div>
<highmaps :options="chartOptions"></highmaps>
</div>
</template>
<script>
import HighCharts from 'vue-highcharts';
import json from '../map.json'
export default {
data () {
return {
chartOptions: {
chart: {
map: json,
},
...
}
</script>
Related
So, I've set up my rails 7 application by doing the following.
rails new .
To add bootstrap I've implemented it with importmap (no webpacker) as following
./bin/importmap pin bootstrap
which loaded these lines (I added the preload: true)
pin 'bootstrap', to: https://ga.jspm.io/npm:bootstrap#5.1.3/dist/js/bootstrap.esm.js', preload: true
pin '#popperjs/core', to: 'https://ga.jspm.io/npm:#popperjs/core#2.11.2/lib/index.js', preload: true
then on my application.js, I added
import "bootstrap"
import "#popperjs/core"
and I was able to use the toast element by doing as follow
# toast_controller.js
import { Controller } from "#hotwired/stimulus"
import * as bootstrap from 'bootstrap'
// Connects to data-controller="toast"
export default class extends Controller {
connect() {
const toast = new bootstrap.Toast(this.element, {
delay: 5000,
animation: true,
autohide: true
})
toast.show()
}
}
and it was working well, But I started facing issues with bootstrap when trying to use the tooltip on my menu
# layout_controller.js
import { Controller } from "#hotwired/stimulus"
import * as bootstrap from 'bootstrap'
// Connects to data-controller="toast"
export default class extends Controller {
connect() {
[].slice.call(document.querySelectorAll('[data-bs-togle-secondary="tooltip"]'))
.map(function (tooltipTriggerEl) {
return new bootstrap.Tooltip(tooltipTriggerEl, {placement: "right"})
})
}
}
the reason for it is because popperjs uses process.env.NODE_ENV which doesn't exist since I didn't set up webpacker
so I had to do something ugly on my application layout and add it like this
<script>
const process = {}
process.env = {}
process.env.NODE_ENV = "<%= Rails.env %>"
</script>
Is there a better approach/fix for this kind of issue?
At the moment of writing this 11/04/2022 there is not a clear solution for now and your mentioned approach with defining in const process in tag works, one issue with that is that with importmaps+turbolink approach it will rise "Uncaught SyntaxError: redeclaration of const process".
Probably for now it's best to just follow this thread https://github.com/rails/importmap-rails/issues/65 as this issue is mentioned in the comments there. One of the quick fixes mentioned there is similar to yours: https://github.com/rails/importmap-rails/issues/65#issuecomment-999939960. With a combined solution of yours and the one in the comments, it seems that this works best for now and there is no redeclaration error.
<script>window.process = { env: { NODE_ENV: "#{Rails.env}" } }</script>
If the solution is introduced for this issue either on importmaps or popperjs side, then please update this comment or introduce a new answer.
Material UI (React) uses a theaming solution where the theme object is created in JS then passed into the top level component. Creating the theme object in Opal can be complicated as the Material component expects a JS function to be passed in which actually creates the theme on the fly.
Has anyone got an example of this working well?
After some experimentation, I got this working well by mixing JS and Opal code so here is the solution in case anyone else comes up with this. (There may be a better 'more Opal' solution, so if there is please do post an alternative answer, but the one below does work well.
First import the JS libraries with webpack:
import { MuiThemeProvider, createMuiTheme } from '#material-ui/core/styles';
import indigo from '#material-ui/core/colors/indigo';
import pink from '#material-ui/core/colors/pink';
import red from '#material-ui/core/colors/red';
global.createMuiTheme = createMuiTheme;
global.MuiThemeProvider = MuiThemeProvider;
global.indigo = indigo;
global.pink = pink;
global.red = red;
Add the following to your Javascript assets:
// app/assets/javascripts/my_theme.js
const my_theme = createMuiTheme(
{ palette: {
primary: { main: pink[500] },
secondary: { main: indigo[500] }
}
});
Then provide the theme in your top-level Component code:
class MyRouter < HyperComponent
include Hyperstack::Router
render(DIV) do
MuiThemeProvider(theme: `my_theme` ) do
CssBaseline do
...
end
end
end
end
I'm using one of the skeleton-navigation, skeleton-typescript.
I'm trying to import Electron.remote so I can close the electron window from within the JS. This is what I have in config.js:
paths: {
"*": "dist/*",
"github:*": "jspm_packages/github/*",
"npm:*": "jspm_packages/npm/*",
"node_modules:*": "node_modules/*"
},
map: {
"electron": "node_modules:electron/index.js",
}
and in my JS file I import like this:
import * as electron from 'electron';
but I get error regarding fs.js not found in path:
Error: (SystemJS) XHR error (404 Not Found) loading http://localhost:9000/dist/fs.js
Can someone help on how I can fix this issue?
depends on the loader/bundler strategy you picked
electron has nodes require() defined.
you want to redefine that before booting up your app that relies on AMD require
https://github.com/electron/electron/issues/303
TL;DR
you want to assign nodes require to another variable
window.node_require = require
and then delete the original
delete require
only after this you reference a script with your app
and inside your app you use node_require() to load node modules
here is the relevant comment on: supporting electron modules in aurelia
This is how I fixed my issue for Aurelia Skeleton Typescript with JSPM & SystemJS: I put in index.html head which is my entry:
<script type="text/javascript">
window.node_require = require;
delete window.require;
delete window.exports;
delete window.module;
</script>
Then I set nodeIntegration: true for BrowserWindow.
And in my TS file:
declare global {
interface Window {
node_require: any;
}
}
var remote: any;
if (typeof window.node_require == "function") {
remote = window.node_require('electron').remote;
}
closeApp() {
var window = remote.getCurrentWindow();
window.close();
}
I'm trying to use VueStrap in a VueJS project, it looks like webpacker is loading it fine, I can see this in the terminal output, however, when I try use a component from vue-strap I get this error:
[Vue warn]: Property or method "input" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by initializing the property. See: https://v2.vuejs.org/v2/guide/reactivity.html#Declaring-Reactive-Properties.
I tried including the VueStrap as a component in the Vue instance but couldn't get it to work. How do I include the VueStrap into as a component correctly?
Thanks!
This is my application.js:
import Vue from 'vue/dist/vue.js'
import App from '../components/app.vue'
import VueStrap from 'vue-strap'
document.addEventListener('DOMContentLoaded', () => {
document.body.appendChild(document.createElement('app'))
const app = new Vue({
el: 'app',
template: '<App/>',
components: { App }
})
console.log('app')
})
This is my app.vue file
<template>
<div id='app'>
<p> {{ message }} </p>
<bs-input :value.sync="input" label="Username" help="Only allows lowercase letters and numbers."
error="Insert username" placeholder="Username can't start with a number." pattern="^[a-z][a-z0-9]+$"
:mask="mask" minlength="5" readonly required icon>
</bs-input>
</div>
</template>
<script>
export default {
data: function () {
return {
message: "Hello World"
}
}
}
</script>
<style scoped>
p {
font-size: 2em;
text-align: left;
}
</style>
Please see the documentation on complication scope, notably:
Everything in the parent template is compiled in parent scope; everything in the child template is compiled in child scope.
Your template includes input and mask properties but your data function does not set those up. They need to be set up and reactive so if they change, Vue can pass them down to the child component (which it looks like your bs-input component exposes an input and mask properties).
The registration was working fine with the default HelloWorld app, but once I deleted the folder and created my own, it stopped working.
I made a new folder under app/bundles called posts with a startup folder.
In the startup folder, I'm registering the components like so:
import ReactOnRails from 'react-on-rails';
import PostContainer from '../containers/PostContainer';
ReactOnRails.register({
PostContainer
});
The PostContainer.jsx file is in the containers folder and it looks like this:
import React, { PropTypes, Component } from 'react';
export default class PostsContainer extends React.Component {
render() {
return (
<div>
<Header />
<PostList posts={this.props.posts} />
</div>
)
}
}
My webpack.config.js file looks like this:
entry: [
'es5-shim/es5-shim',
'es5-shim/es5-sham',
'babel-polyfill',
'./app/bundles/HelloWorld/startup/registration',
],
I tried changing the HelloWorld to posts or Posts, but it did not work.
Am I supposed to have a file called webpack.configure.build.js? Or is the webpack.config.js the file I need to edit?
Any help would be appreciated!
Did you add the component to the erb view file with the associated props passed in? You would need to add the props within your Posts controller or whichever controller is rendering your Posts view. I'm pretty sure you would then need to add a line in your webpack config:
config: {
'webpack-bundle': [
'...',
'./app/bundles/Posts/startup/registration'
]
}
Then in your view:
<%= react_component("PostsContainer", props: #posts_props, prerender: false) %>
Also make sure in your layout file you have:
<%= javascript_pack_tag 'webpack-bundle' %>
Note: PropTypes should be imported from the prop-types package now. The react team plucked that package out of the react core as of recent.