My html code can't reach my vue component - vue.js

This is my second day with vue. I was already using webpack and vue-cli, but I would like to understand how to make everything working within one file. I developed a code which works well, but I would like to refactor the code to have a component which I could later use to generate screen full of color changing tiles.
I tried Vue.component('name', {}), but with no result, because in the console I'm seeing [Vue warn]: The "data" option should be a function that returns a per-instance value in component definitions. and [Vue warn]: Unknown custom element: <brick> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
This code works well:
<html>
<head>
<title>v pavle</title>
<script type="text/javascript" src="https://vuejs.org/js/vue.js"></script>
</head>
<body>
<div id="app"></div>
<script type="text/javascript">
var vm = new Vue({
el: "#app",
template:
'<div v-bind:style="styleobj" v-on:mouseover="changebgcolor" v-on:mouseout="changebgcolor"></div>',
data: {
styleobj: {
width: "100px",
height: "100px",
backgroundColor: "white"
}
},
methods: {
changebgcolor: function() {
this.styleobj.backgroundColor = Math.floor(
Math.random() * 16777215
).toString(16);
}
}
});
</script>
</body>
</html>
And that code gives everything, but not what I want to see :(
<html>
<head>
<title>v pavle</title>
<script type="text/javascript" src="https://vuejs.org/js/vue.js"></script>
</head>
<body>
<div id="app">
<brick></brick>
</div>
<script type="text/javascript">
var vm = new Vue({
el: "#app"
});
var brick = Vue.component("brick", {
template:
'<div v-bind:style="styleobj" v-on:mouseover="changebgcolor" v-on:mouseout="changebgcolor"></div>',
data: {
styleobj: {
width: "100px",
height: "100px",
backgroundColor: "white"
}
},
methods: {
changebgcolor: function() {
this.styleobj.backgroundColor = Math.floor(
Math.random() * 16777215
).toString(16);
}
}
});
</script>
</body>
</html>
It may seem easy for you, but after 7h spent, there is nothing more for me, but just ask you on SO

Okay I will answer your 2 questions. First and about data, it has to be a function. So you have to write it like that:
data() {
return {
styleobj: {
width: "100px",
height: "100px",
backgroundColor: "white"
}
}
}
After that, your forgot to reference your component in your Vue instance. Try that:
var vm = new Vue({
el: "#app",
components: {
brick: brick
}
})
Hope it will work.

Data must be a function like data: function(){ return obj }
Register the component using components: {yourcomponent}
You needed to use # in front of your color.
<html>
<head>
<title>v pavle</title>
<script type="text/javascript" src="https://vuejs.org/js/vue.js"></script>
</head>
<body>
<div id="app">
Hello App!
<brick>Hello Brick</brick>
</div>
<script type="text/javascript">
var brick = Vue.component("brick", {
template:
'<div :style="styl" #click="changebgcolor" #mouseover="changebgcolor" #mouseout="changebgcolor"><slot></slot></div>',
data: function(){
return {
styl: {
width: "100px",
height: "100px",
backgroundColor: "#b6d8a1",
color: "blue"
}
};
},
methods: {
changebgcolor: function() {
console.log('changebgcolor!');
this.styl.backgroundColor = "#"+ Math.floor(
Math.random() * 16777215
).toString(16);
}
}
});
var vm = new Vue({
el: "#app",
components:{brick:brick}
});
</script>
</body>
</html>

When using Vue.component, you need to make sure that you have registered all components once you start rendering your app. At the moment, you first render the main app and then register the component, so swap those around
var brick = Vue.component("brick", {
template:
'<div v-bind:style="styleobj" v-on:mouseover="changebgcolor" v-on:mouseout="changebgcolor"></div>',
data: {
styleobj: {
width: "100px",
height: "100px",
backgroundColor: "white"
}
},
methods: {
changebgcolor: function() {
this.styleobj.backgroundColor = Math.floor(
Math.random() * 16777215
).toString(16);
}
}
});
var vm = new Vue({
el: "#app"
});

The data property on your component should be a function that returns an object. Why? Because otherwise all instances of your component share the same data, meaning all tiles on your app would have the same color.
data() {
return {
styleobj: {
width: "100px",
height: "100px",
backgroundColor: "white"
}
}
},
You should first register the component before you fire up the Vue instance, just reorder your code and it works!

Related

Enable arcgis API JS popups with Vue CLI 3

I am trying to get popups from the ArcGIS API JS to display using the framework Vue-CLI 3.
But even with a simple sample code, I cannot make it work: Here is the code in vanilla JS:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<title>Popup actions | Sample | ArcGIS API for JavaScript 4.17</title>
<style>
html,
body,
#viewDiv {
padding: 0;
margin: 0;
height: 100%;
width: 100%;
}
</style>
<link rel="stylesheet" href="https://js.arcgis.com/4.17/esri/themes/light/main.css" />
<script src="https://js.arcgis.com/4.17/"></script>
<script>
require([
"esri/Map",
"esri/layers/FeatureLayer",
"esri/views/MapView",
"esri/geometry/geometryEngine"
], function (Map, FeatureLayer, MapView, geometryEngine) {
// Create the Map
var map = new Map({
basemap: "gray-vector"
});
// Create the MapView
var view = new MapView({
container: "viewDiv",
map: map,
center: [-117.08, 34.1],
zoom: 11
});
var template = {
// autocasts as new PopupTemplate()
title: "Trail run",
content: "{name}",
};
var featureLayer = new FeatureLayer({
url:
"https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/TrailRuns/FeatureServer/0",
outFields: ["*"],
popupTemplate: template,
});
map.add(featureLayer);
});
</script>
</head>
<body>
<div id="viewDiv"></div>
</body>
</html>
As you can see, when clicking a feature, a popup appears.
If I try to implement this in my vue-CLI project I can not make it work. When clicking on the a feature, it will highlight, but nothing will open. Here is my code .vue:
<template>
<div></div>
</template>
<script>
import { loadModules } from "esri-loader";
export default {
name: "web-map",
mounted() {
// lazy load the required ArcGIS API for JavaScript modules and CSS
loadModules([
"esri/Map",
"esri/views/MapView",
"esri/layers/FeatureLayer",
]).then(([ArcGISMap, MapView, FeatureLayer]) => {
const map = new ArcGISMap({
basemap: "topo-vector",
});
this.view = new MapView({
container: this.$el,
map: map,
center: [-117.08, 34.1],
zoom: 11,
});
var template = {
// autocasts as new PopupTemplate()
title: "Trail run",
content: "{name}",
};
var featureLayer = new FeatureLayer({
url:
"https://services.arcgis.com/V6ZHFr6zdgNZuVG0/arcgis/rest/services/TrailRuns/FeatureServer/0",
outFields: ["*"],
popupTemplate: template,
});
map.add(featureLayer);
});
},
beforeDestroy() {
if (this.view) {
// destroy the map view
this.view.destroy();
}
},
};
</script>
<style scoped>
div {
padding: 0;
margin: 0;
width: 100%;
height: 100%;
}
</style>
Am I missing something? (I followed arcgis api js tutorial to get it work in vue-cli -https://developers.arcgis.com/javascript/latest/guide/vue/ )
Thank you very much for your help!
Julien
Your code is fine, you are just not adding css. You are missing { css: true }, that's all.
loadModules(
["esri/Map", "esri/views/MapView", "esri/layers/FeatureLayer"],
{ css: true } // <-- HERE
).then(([ArcGISMap, MapView, FeatureLayer]) => {
//...
}
HERE code with the fix.

How to use href in Vue and Quill

I am using the Quill editor in Vue.js and it's working great. I have images, etc.
But...the link isn't working. I tried both the "snow" and "bubble" themes.
I type the text, highlight it and then click on the "link". I get the dialog to set the link, but then the link isn't there.
It's working in the JavaScript version, but not the Vue.
Below is my code.
Vue.component('editor', {
template: '<div ref="editor"></div>',
props: {
value: {
type: String,
default: ''
}
},
data: function() {
return {
editor: null
};
},
mounted: function() {
this.editor = new Quill(this.$refs.editor, {
modules: {
toolbar: [
[{ header: [1, 2, 3, 4, false] }],
['bold', 'italic', 'underline'],
['image', 'code-block', 'link']
]
},
//theme: 'bubble',
theme: 'snow',
formats: ['bold', 'underline', 'header', 'italic', 'link'],
placeholder: "Type something in here!"
});
this.editor.root.innerHTML = this.value;
this.editor.on('text-change', () => this.update());
},
methods: {
update: function() {
this.$emit('input', this.editor.getText() ? this.editor.root.innerHTML : '');
}
}
})
new Vue({
el: '#root',
data: {
//model: 'Testing an editor'
model: '',
isShowing: true
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
<link href="https://cdn.quilljs.com/1.3.4/quill.snow.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link href="https://cdn.quilljs.com/1.3.4/quill.core.css" rel="stylesheet"/>
<!DOCTYPE html>
<html>
<head>
<title>Trying to use the Quill Editor in Vue</title>
</head>
<body>
<div id="root">
<div v-if="isShowing">
<editor v-model="model"></editor>
</div>
<p>I need the v-html directive: <span v-html="model"></span></p>
<p>Raw data: <pre>{{ model }}</pre></p>
<button #click="isShowing = !isShowing">Toggle</button>
</div>
</script>
</body>
</html>
Any help is greatly appreciated.
Thanks, D
I had to place a 'link' into the "formats" as well:
formats: ['bold', 'underline', 'header', 'italic', 'link'],
I updated my code snippet with the correct answer in case anyone else is having this problem.
Thanks!

How can I change my c3 chart axis color in vue environment

I want use c3.js in my vue app, it's successful to build a chart but I can't change my c3 chart axis color.
It's not just axis color, all style of c3 charts I can't change and fixed, it's upset for me.
Do you have any idea for it?
<template>
<div id="home">
<div class="block1">
<div id='lineChart'></div>
</div>
</div>
</template>
<script>
import * as d3 from "d3";
import c3 from 'c3';
export default {
mounted(){
this.loadBlock1();
},
methods:{
loadBlock1 () {
let chart = c3.generate({
bindto:'#lineChart',
data: {
columns: [
['data1', 30, 200, 100, 400, 150, 250],
['data2', 50, 20, 10, 40, 15, 25]
],
}
});
}
}
}
</script>
<style scoped>
#import "https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.0/c3.min.css";
#lineChar .c3-line-data2 {
stroke-width: 5px;
}
#lineChart .c3-axis-x line,
#lineChart .c3-axis-x path {
stroke:blue;
}
</style>
Your code is not working because when you use <style scoped> Vue emulates shadow DOM adding a hash on the DOM elements and on the CSS selectors. The elements created by c3 do not contain the hash and the css selector do not match with them. So, add a style tag without the scoped attr for styling the chart.
<template>...</template>
<script>...</script>
<style scoped>...</style>
<style>...</style>
Also, avoid getting the DOM element using query selectors. Vue uses VDOM approach and DOM access should be done through directives and refs:
Vue.directive("c3", {
bind(el, binding, vnode) {
const chart = c3.generate({
bindto: el,
data: binding.value,
});
el.chart = chart;
},
update(el, binding, vnode) {
el.chart.resize();
},
unbind(el, binding, vnode) {
el.chart.destroy();
}
});
const home = new Vue({
el: "#home",
data() {
return {
options: {
columns: [
["data1", 30, 200, 100, 400, 150, 250],
["data2", 50, 20, 10, 40, 15, 25]
],
},
};
},
computed: {
chart() {
return this.$refs.chart.chart;
}
},
methods: {
load(data) {
this.chart.load(data);
},
unload(data) {
this.chart.load(data);
}
},
mounted() {
this.chart.resize();
}
});
setTimeout(() => {
home.load({
columns: [
['data1', 230, 190, 300, 500, 300, 400]
]
});
}, 1000);
setTimeout(function() {
home.load({
columns: [
['data3', 130, 150, 200, 300, 200, 100]
]
});
}, 1500);
setTimeout(function() {
home.unload({
ids: 'data1'
});
}, 2000);
#home .c3-line-data2 {
stroke-width: 5px;
}
#home .c3-axis-x line,
#home .c3-axis-x path {
stroke: blue;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.0/c3.min.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/c3/0.7.0/c3.min.js"></script>
<div id="home">
<div class="block1">
<div ref="chart" v-c3="options"></div>
</div>
</div>

Vuejs: autofit div according to remaining space in window

Within vueJs (2.5.16) I'm trying to set the style property of a div so it auto fit the remaining space of a window depending of its size:
I intended to use a computed value which would give me live the correct height and bind it into the style property of the wanted div:
Vue.component('menus', {
template: '<div id="menu-div">MY MENU</div>'
});
Vue.component('expandable', {
template: '<div id="expandable-div" :style="{height:expandableHeight}">EXPANDABLE<div>{{expandableHeight}}</div></div>',
computed: {
expandableHeight() {
return ($(window).height() - $("#expandable-div").position().top) + 'px'
}
}
});
var vm = new Vue({
el: '#app'
});
fiddle
Using $(window).height() and $("#expandable-div").position().top from jQuery I thought I could achieve a result since it works in my console.
Unfortunately I have an error:
TypeError: Cannot read property 'top' of undefined
Why not use CSS's flexbox to achieve that?
Vue.component('menus', {
template: '<div id="menu-div">MY MENU</div>'
});
Vue.component('expandable', {
template: '<div id="expandable-div">EXPANDABLE<div>foo</div></div>',
computed: {}
});
var vm = new Vue({
el: '#app'
});
body {
margin: 0;
}
#app {
display: flex;
flex-direction: column;
height: 100vh;
}
#menu-div {
height: 50px;
background: #768ffb;
margin-bottom: 5px;
}
#expandable-div {
background: #76fbc1;
flex-grow: 1;
}
<script src="https://unpkg.com/vue"></script>
<div id="app">
<menus></menus>
<expandable></expandable>
</div>

Can't change button text inside setTimeout function

I have got follow Vue-js App:
<html>
<head>
<script src="https://cdn.jsdelivr.net/vue/1.0.26/vue.min.js"></script>
<style>
.mydiv
{
border: 1px black dashed;
font-size: 2em;
}
</style>
<script>
var App = null; // it's global because function behind will overwrite it's with Vue App instance
window.onload = function()
{
new Vue(
{
el: '#app',
data:
{
btntext: "OK"
},
methods:
{
change: function()
{
this.btntext = "cancel";
setTimeout(function() {console.log("test"); this.btntext = "text changed";},1000);
}
}
})
}
</script>
</head>
<body>
<div id="app">
<div class="mydiv">
<button v-on:click="change">{{btntext}}</button>
</div>
</div>
</body>
</html>
After running I am getting "test" on console, but button do not change it's text to text changed. Why?
The function given to setTimeout does not have the same "this" as your Vue. You could use the bind function:
new Vue({
el: '#app',
data: {
btntext: "OK"
},
methods: {
change: function () {
this.btntext = "cancel";
setTimeout(function () {
console.log("test");
this.btntext = "text changed";
}.bind(this), 1000);
}
}
})
.mydiv{
border: 1px black dashed;
font-size: 2em;
}
<script src="https://cdn.jsdelivr.net/vue/1.0.26/vue.min.js"></script>
<div id="app">
<div class="mydiv">
<button v-on:click="change">{{btntext}}</button>
</div>
</div>
You have to understand the context of this keyword. When in setTimeout callback function, this refers to different object that this before it. To solve this issue, you should solve reference to this before the callback or if you're going to use ES2015, you can change function () {...} with arrow function () => {...}, which will automatically save reference to outer this and use it instead of actual this inside the function. But if you're going to use that, make sure it's supported across all your target browsers, or alternatively use a compiler to ES5, most popular of which is Babel.