[Vue.js] How to Fix Mouse position relative to parent of canvas? Subscribe to RSS

when trying to use the Vuejs Draw Canvas of this Codepen as a component. Everything works great but the mouse position is relative to the window I think. So when drawn it works perfectly fine only if the canvas is window size ( width, height) if not there is a huge difference in the cursor and draw position.

there is tried setting the canvas width and height to offset instead of window like

setSize() {
this.c.width = this.c.offsetWidth;
this.c.height = this.c.offsetHeight - 60;
}

and mouse positions with below code as in this SO answers

function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: (evt.clientX - rect.left) / (rect.right - rect.left) * canvas.width,
y: (evt.clientY - rect.top) / (rect.bottom - rect.top) * canvas.height
};
}

but it did not change the result. So reverted back and added in code sandbox. If anyone can help me find out what the issue here? I know it’s with mouse position but not sure exactly where.

Here is codesandbox link of the demo im trying to fix.

Solution :

I use these two methods (not sure without further digging why they are not the same):

canv = document.getElementById(“id-of-canvas-object”)

function mouseLocation(e)
{
if (e.preventDefault)
e.preventDefault();
var x = e.PageX; var y = e.PageY;
// in one instance
var relativeX = x - canv.offsetLeft;
var relativeY = y - canv.offsetTop;
// in another instance
var rect = canv.getBoundingClientRect();
relativeX = x - rect.left;
relativeY = y - rect.top;
}

Solution 2:

On the example you shared you are not taking in count the offset when re positioning the cursor and you’re substracting a 60px offset that is unnecessary because of the fixed positioning of the controls.

There are just 2 differences on lines: 234 & 239

setSize() {
this.c.width = this.c.offsetWidth;
this.c.height = this.c.offsetHeight; // <— HERE i removed the -60px offset
}

moveMouse(e) {
let x = e.offsetX;
let y = e.offsetY + 60; // <— HERE i added the 60px offset
// the e.offsetY is relative to the canvas but you have an offset
// for the controls that is moving the cursor (the little dot) to the top

var cursor = document.getElementById(“cursor”);

cursor.style.transform = `translate(${x}px, ${y}px)`;
}

Heres the example fixed: Fixed codesandbox

Note: I recommend to change the fixed positioning of the controls and manage everything with fixed height and width values or use flexbox to grow the canvas as it needs to.

[Vue.js] Getting CORS error when using variable in api call Subscribe to RSS

Good day.

When i do the following api call with axios it works just fine but when i try to use a variable in said api call i get a cors error. What am i doing wrong?

When i use it without a variable, this works just fine:

somecall({state}){
axiosB
.get(“/lmao/10.0.0.190”)
.then(res =>
state.response = res.data);
console.log(state.response)
}

When i use a variable to perform the api call, this gives me a CORS error:

somecall({state, ip}){
axiosB
.get(“/lmao/“, ip)
.then(res =>
state.response = res.data);
console.log(state.response)
}

The value when trying to pass is 10.0.0.190 in this case.

Solution :

Assuming you’re using Vuex (are you?), the syntax should be:

somecall({state}, ip){
axiosB
.get(“/lmao/“ + ip)
.then(res =>
state.response = res.data);
console.log(state.response)
}

Note that the payload comes as a second argument after the deconstructed context, rather than together with it.

Or the problem may be with this line:

.get(“/lmao/“, ip)

and may need to be changed as above.

[Vue.js] Vue prop item seems to be empty? Subscribe to RSS

I’m attempting to write a todo app as my first ever vue.js project. It seems it’s not showing my items in the TodoItem component — inside the h3 tag.

I’ve double-checked everything but I just can’t see anything wrong. Why are my items not appearing?

App.vue:

<template>
<div id=”app”>
<Todos v-bind:todos=”todos” message=”Here are the daily tasks”/>
</div>
</template>

<script>
import Todos from ‘./components/Todos.vue’

export default {
name: ‘app’,
components: {
Todos
},
data: {

todos: [
{
id: 1,
title: “Todo one”,
completed: false,
},
{
id: 2,
title: “Todo two”,
completed: false,
},
{
id: 3,
title: “Todo three”,
completed: true,
}
]

}
}
</script>

<style>

#app {
font-family: ‘Avenir’, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>

Todos:

<template>
<div class=”hello”>
<h1>{ message }</h1>
<div v-bind:key=”todo.id” v-for=”todo in todos”>
<TodoItem v-bind:todo=”todo” />
</div>
</div>
</template>

<script>

import TodoItem from ‘../components/TodoItem.vue’

export default {
name: “Landing”,
components: {
TodoItem
},
props: [“message”, “todos”],
data: {
}
};
</script>

<!– Add “scoped” attribute to limit CSS to this component only –>
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

TodoItem:

<template>
<div class=”todo-item”>
<h3>ITEM: test</h3>
</div>
</template>

<script>

export default {
name: “TodoItem”,
props: [“todo”],
data: {
}
};
</script>

<!– Add “scoped” attribute to limit CSS to this component only –>
<style scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

Solution :

data must be a function for a component. the code renders the items if you make the following changes:

export default {
name: ‘App’,
components: {
Todos,
},
data() {
return {
todos: [
{
id: 1,
title: ‘Todo one’,
completed: false,
},
{
id: 2,
title: ‘Todo two’,
completed: false,
},
{
id: 3,
title: ‘Todo three’,
completed: true,
},
],
};
},
};

I highly recommend integrating eslint along with eslint-plugin-vue.js into the editor to avoid these kinds of common errors.

Solution 2:

As previously stated, data in a vue.js component must be a function.

Here’s a working version to help you out:
https://codesandbox.io/s/vue-template-ds5up?fontsize=14

[Vue.js] select/deselect single element in v-for Subscribe to RSS

I’m trying to make an option list with v-for, where you can choose only one option at a time. It works great except I can’t unselect the option.

<div id=”main”>
<ul>
<li
v-for=”l in list”
id=”l.key”
@click=”selectone(l.key, l.isSelected)”
v-bind:class=”{ selected : l.isSelected, notselected : !l.isSelected }”
\> { l.tec } </li>
<ul>
</div>

The JS

new Vue({
el:”#main”,
data: {
list: [
{key:”0”, tec:”html”, isSelected:false},
{key:”1”, tec:”css”, isSelected:false},
{key:”2”, tec:”JS”, isSelected:false},
{key:”3”, tec:”Git”, isSelected:false},
{key:”4”, tec:”NodeJS”, isSelected:false},
{key:”5”, tec:”Postgres”, isSelected:false}
]
},
methods: {
selectone: function(k, o) {
for( i = 0; i < this.list.length; i ++ ) {
if(this.list[i].isSelected == true ) {
this.list[i].isSelected = false
}
}
this.list[k].isSelected = !this.list[k].isSelected;
}
}
})

CSS

.selected {
background:lightpink;
}
.notselected {
background:lightblue;
}

Shouldn’t my loop deactivate all options every time I click an element?

Solution :

In selectone(), you’re setting isSelected=false for all list items, and then attempting to toggle the selected list item’s isSelected, which was just previously set to false (i.e., the “toggle” would always set isSelected=true for the selected item).

The loop should exclude the key of the selected item:

selectone(key) {
for (let i = 0; i < this.list.length; i++) {
if (this.list[i].key !== key) {
this.list[i].isSelected = false
}
}

// this.toggleSelection(key)
}

But the toggling code itself needs a bug-fix to properly lookup the list item. The first argument to selectone() is the key property of the list item. In order to get the item by key from the list array, you have to search the list, e.g., using Array.prototype.find():

toggleSelection(key) {
const listItem = this.list.find(item => item.key === key)
if (listItem) {
listItem.isSelected = !listItem.isSelected
}
}

new Vue({
el: ‘#app’,
data: {
list: [
{key:”0”, tec:”html”, isSelected:false},
{key:”1”, tec:”css”, isSelected:false},
{key:”2”, tec:”JS”, isSelected:false},
{key:”3”, tec:”Git”, isSelected:false},
{key:”4”, tec:”NodeJS”, isSelected:false},
{key:”5”, tec:”Postgres”, isSelected:false}
]
},
methods: {
selectone(key) {
for (let i = 0; i < this.list.length; i++) {
if (this.list[i].key !== key) {
this.list[i].isSelected = false
}
}

this.toggleSelection(key)
},
toggleSelection(key) {
const listItem = this.list.find(item => item.key === key)
if (listItem) {
listItem.isSelected = !listItem.isSelected
}
}
}
})
.selected {
background:lightpink;
}
.notselected {
background:lightblue;
}
<script src=”https://unpkg.com/vue@2.6.10"></script>

<div id=”app”>
<ul>
<li
v-for=”l in list”
id=”l.key”
@click=”selectone(l.key, l.isSelected)”
v-bind:class=”{ selected : l.isSelected, notselected : !l.isSelected }”
\> { l.tec } </li>
<ul>
</div>

Alternatively, you could track the selected index, set it in the item’s click-handler, and set the class binding based on the item’s index matching the selected index:

// template
<li
v-for=”(l, index) in list”
id=”l.key”
@click=”selectedIndex = index”
v-bind:class=”{ selected: index === selectedIndex, notselected: index !== selectedIndex }”
\> { l.tec } </li>

// script
export default {
data() {
return {
selectedIndex: -1,

}
}
}

new Vue({
el: ‘#app’,
data: {
selectedIndex: -1,
list: [
{key:”0”, tec:”html”, isSelected:false},
{key:”1”, tec:”css”, isSelected:false},
{key:”2”, tec:”JS”, isSelected:false},
{key:”3”, tec:”Git”, isSelected:false},
{key:”4”, tec:”NodeJS”, isSelected:false},
{key:”5”, tec:”Postgres”, isSelected:false}
]
}
})
.selected {
background:lightpink;
}
.notselected {
background:lightblue;
}
<script src=”https://unpkg.com/vue@2.6.10"></script>

<div id=”app”>
<ul>
<li
v-for=”(l, index) in list”
id=”l.key”
@click=”selectedIndex = index”
v-bind:class=”{ selected : index === selectedIndex, notselected : index !== selectedIndex }”
\> { l.tec } </li>
<ul>
</div>

Solution 2:

the close. try this: (un tested)

<div id=”main”>
<ul>
<li
v-for=”(l,index) in list”
id=”l.key”
@click=”selectone(l, index)”
v-bind:class=”{ selected : l.isSelected, notselected : !l.isSelected }”
\> { l.tec } </li>
<ul>
</div>

The JS

new Vue({
el:”#main”,
data: {
list: [
{key:”0”, tec:”html”, isSelected:false},
{key:”1”, tec:”css”, isSelected:false},
{key:”2”, tec:”JS”, isSelected:false},
{key:”3”, tec:”Git”, isSelected:false},
{key:”4”, tec:”NodeJS”, isSelected:false},
{key:”5”, tec:”Postgres”, isSelected:false}
]
},
methods: {
selectone:function(l, index){

for( i = 0; i < this.list.length; i ++ ) {
this.list[i].isSelected = false
}
l.isSelected = true;
}
}
}
})

to explain you were miss using the variable k in the function. that should be the entire object not the index

[Vue.js] Pass slots to self referenced node recursively in vue Subscribe to RSS

there is created self referencing component as following using name property.
It is using slots. which I need to pass to child node as well. there is looped child node as following.

<template>
<div>
<slot name=”filters”></slot>
<template v-if=”node.children && node.children.length”>
<node v-for=”child in node.children” :node=”child”>
</node>
</template>
</div>
</template>

<script lang=”ts”>
import { Component, Vue, Prop } from ‘vue-property-decorator’;

@Component({
name: ‘node’,
})
export default class TreeNode extends vue.js {

@Prop({ default: [] })
public node: any;
}
</script>

when using it as below.

<node-tree :node=”treeData”>
<template v-slot:filters>
<h1>Here might be a node content</h1>
</template>
</node-tree>

<script lang=”ts”>
import { Component, Vue, Prop } from ‘vue-property-decorator’;
import NodeTree from ‘./TreeNode.vue’;

@Component({
components: {
NodeTree,
})
export default class Tree extends vue.js {

//TODO: Following data is only for demo. Remove it. and set appropriate.
public treeData = {
label: ‘A cool folder’,
children: [
{
label: ‘A cool sub-folder 1’,
children: [
{ label: ‘A cool sub-sub-folder 1’ },
{ label: ‘A cool sub-sub-folder 2’ },
],
},
{ label: ‘This one is not that cool’ },
],
};
}
</script>

But child nodes are not displaying slot content. How do I pass them recursively.

Solution :

Following in treenode worked for me

<template v-if=”node.children && node.children.length”>
<node v-for=”child in node.children” :node=”child”>
<template v-for=”(_, slot) in $slots”>
<template :slot=”slot”>
<slot :name=”slot”></slot>
</template>
</template>
</node>
</template>

[Vue.js] How do I use fragments on union in Vue.js? Subscribe to RSS

Does anyone have any idea how do I use fragments on unions? I’ve seen the documentation for React (https://www.apollographql.com/docs/react/advanced/fragments/#fragments-on-unions-and-interfaces) but not much on Vue. there is a query that returns two fragments, both with __typename.

query {
search(queryString: “lin”) {
… on Professor {
__typename
name
}
… on Course {
__typename
name
moduleCode
}
}
}

When the vue.js app runs, I received the error “You’re using fragments in the queries, but either don’t have the addTypename: true option set in Apollo Client, or you are trying to write a fragment to the store without the __typename.” This is the code from my vue.js app.

data() {
return {
result: []
};
},
apollo: {
// Query with parameters
result: {
// gql query
query: gql’
query search($queryString: String!) {
… on Professor {
__typename
name
}
… on Course {
__typename
name
moduleCode
}
}
‘,
// Static parameters
variables() {
return {
queryString: ‘lin mei’
}
}
}
},

// In my apollo client options
// Override default cache
cache: new InMemoryCache(
{ addTypename: true }
}

The error messages I got are

You’re using fragments in the queries, but either don’t have the addTypename:
true option set in Apollo Client, or you are trying to write a fragment to the store without the __typename.
Please turn on the addTypename option and include __typename when writing fragments so that Apollo Client
can accurately match fragments.
DEPRECATION WARNING: using fragments without __typename is unsupported behavior and will be removed in future versions of Apollo client. You should fix this and set addTypename to true now.
GraphQL error: Fragment on Professor can’t be spread inside Query; GraphQL error: Fragment on Course can’t be spread inside Query; GraphQL error: Variable $queryString is declared by search but not used
GraphQL error: Fragment on Professor can’t be spread inside Query; GraphQL error: Fragment on Course can’t be spread inside Query; GraphQL error: Variable $queryString is declared by search but not used

Is anyone able to provide an example of grabbing two fragments from a query in vue?

Solution :

the query is not correct. You’ve named the operation search, but you probably meant to query this field on the root type instead. Something like:

query ($queryString: String!) {
search(queryString: $queryString) {
… on Professor {
__typename
name
}
… on Course {
__typename
name
moduleCode
}
}
}

Note: Because I don’t know the schema, I can’t say for the sure the above is a valid query either. If the server you are querying exposes a GraphiQL or GraphQL Playground interface, you should use that to verify the queries since both of those tools use schema-specific syntax highlighting.

You may wish to add an id or _id field to each fragment to ensure correct caching behavior. If neither field exists, you’ll need to provide a custom dataIdFromObject function. See the docs for additional details.

[Vue.js] Vue watch providing wrong this context Subscribe to RSS

when using lodash to debounce a function call but when wondering why my this value is not inheriting the scope like I expect.

These are are the relevant parts of my vue.js component.

import debounce from ‘lodash/debounce’;

watch: {
query: debounce(() => {
this.autocomplete();
}, 200, {
leading: false,
trailing: true
}),

The above case does not work because my this value does not point to the vue.js component but rather shows an Object like this:

Object
__esModule: true
default: Object
__proto: Object

Isn’t my arrow syntax suppose to inherit the context of this?

The following seem to works fine:

query: debounce(function test() {
this.autocomplete();
}, 200, {
leading: false,
trailing: true
})

There is probably an easy answer for this but when hoping someone can help me out here.

Solution :

This is only an additional answer to explain the misunderstanding of this in arrow functions.

How does this work in arrow functions?

this in lexical functions always refers to the surrounding scope. That can either be:

The nearest surrounding function
The nearest surrounding module
The global scope

If we have a look at the code, and we assume you’re using ES6 modules (judging from the import/export statements):

import debounce from ‘lodash/debounce’;

export default {
watch: {
query: debounce(() => {
this.autocomplete();
}, 200, {
leading: false,
trailing: true
}),
}
};

Let’s go through the list:

1. The nearest surrounding function

There is no surrounding function for the arrow function. An example would be:

var obj = {
a: function() {
return () => {
console.log(this);
}
}
};

obj.a()(); // `this` refers to `obj`, because `this` refers to `obj` in the surrounding function `a`

2. The nearest surrounding module

Since we are in a (fake) module in this case, this is defined in the module scope as pseudo module object (probably a babel or webpack object?).

Object
__esModule: true
default: Object
__proto: Object

It seems because vue.js binds these properties, methods and events by default

That’s true and it’s a very useful feature of vue. But it doesn’t help us in this case, because this cannot be overridden in an arrow function, it always refers to the surrounding scope.

Have a look at the following link for a deeper understanding of arrow functions: http://exploringjs.com/es6/ch\_arrow-functions.html#\_variables-that-are-lexical-in-arrow-functions

Solution 2:

See https://vuejs.org/v2/guide/instance.html#Properties-and-Methods

Dont use arrow functions on an instance property or callback (e.g. vm.$watch(‘a’, newVal => this.myMethod())). As arrow functions are bound to the parent context, this will not be the vue.js instance as youd expect and this.myMethod will be undefined.

As the same limitation applies to watchers, you have to use something like this:

watch: {
query: function() {
return debounce(() => {
this.autocomplete();
},
200,
{
leading: false,
trailing: true
});
}
}

[Vue.js] How to access Vue component data from component method Subscribe to RSS

I’m a beginner to Vue, and I’m confused about why I cannot access a data property from within a method both on the same component. Every time I try to access my data by using ‘this.items’, it returns that ‘items is undefined’.

I’ve tried changing the syntax of how I write the methods (I initially used an arrow function, but learning that it changes ‘this’, switched to a regular function definition), but it is still returning items as undefined.

Here is my full component with template:

<template>
<div>
<ul>
<li v-for=”(item, index) in items” :key=”index”>
</li>
</ul>
</div>
</template>

<script>

export default {
data() {
return {
‘items’: []
};
},
methods: {

addItem: function(t) {

this.items.push(t)
}
},
}
</script>

This is just a simple todo list, and there is another component calling this function and passing the parameter to ‘addItem()’.

Thanks!

Solution :

Here’s a working version of the code, demonstrating how to display items and add a new element to the items array from the UI:

https://codesandbox.io/embed/vue-template-7j0xj?fontsize=14

Or if you prefer, the vue.js component code is also attached below:

<template>
<div id=”app”>
<div>Hello</div>
<ul v-if=”items”>
<li v-for=”(item, index) in items” :key=”index”>
<div>{item}</div>
</li>
</ul>
<div @click=”addItem(‘Something More’)”>Click to Add Something</div>
</div>
</template>

<script>

export default {
name: “App”,
data() {
return {
items: [‘foo’,’bar’,’baz’]
};
},
methods: {
addItem: function(t) {
this.items.push(t)
}
},
};
</script>

Solution 2:

The easiest way to communicate between components is to use emit.

For example: This is the parent or child component it doesnt matter for this method.

<template>
<div>
<ul>
<li v-for=”(item, index) in items” :key=”index”>
</li>
</ul>
</div>
</template>

<script>

export default {
data() {
return {
‘items’: []
};
},

mounted(){
this.eventHub.$emit(‘add_item:method’, this.addItem);
},

methods: {

addItem: function(t) {

this.items.push(t)
}
},
}
</script>

and the listen to event method other component for this way.

<template>

</template>

<script>

export default {

mounted(){
this.eventHub.$on(‘add_item:method’);
},
}
</script>

[Vue.js] Splitting up Vuex store into separate files gives commit false Subscribe to RSS

when using Vuex in Vue.js.

First, if I put my store inside the main.js. It worked.

But when I split my store into a file called store.js it is not working.

src/store.js

src/main.js

store.js

import vue.js from ‘Vue’
import Vuex from ‘Vuex’

Vue.use(Vuex);

export const store = new Vuex.Store({
state: {
title: ‘Hello from the Vuex Store’,
}
});

main.js

import { store } from ‘./store.js’;

new Vue({
el: ‘#app’,
store: store,
)};

I tried to console.log(store)

and I got a commit false, that is why I know it is not working.
Anything else is correct so I do not include in the codes.

Here is a screenshot of what I console.log:
enter image description here

Solution :

Try it this way instead it has worked for me in the past.

store.js

import vue.js from ‘Vue’
import Vuex from ‘Vuex’

Vue.use(Vuex);

window.store = new Vuex.Store({
state: {
title: ‘Hello from the Vuex Store’,
}
});

main.js

require(‘store.js’);

let vm = new Vue({
el: ‘#app’,
store,
)};

Solution 2:

Somehow magically, I needed to add:

import Vuex from ‘Vuex’
Vue.use(Vuex);

in the main.js for Vuex to work. Anyway, I hope this question helps someone else who is a beginner of Vuex.

[Vue.js] Root Vue instance not receiving events Subscribe to RSS

I cannot receive any events from a child component in the root vue.js instance.

there is a simple child component which emits a ‘hello’ event when clicked or mounted:

<template>
<div v-on:click=”clicked”></div>
</template>

<script>
export default {
name: ‘ChildComponent’,
mounted() {
this.$emit(‘hello’);
},
methods: {
clicked() {
this.$emit(‘hello’);
}
}
};
</script>

In my root vue.js instance I’ve tried everything to receive the event, but none of the handlers seem to be receiving the event. I’m not sure what I’m doing wrong.

const comp = () => import(‘./components/SomeVueWhichHasChild.vue’);

const v = new Vue({
store,
render: h => h(comp, {
on: {
hello: () => {
console.log(‘vue.js INSTANCE HELLO’);
}
},
nativeOn: {
hello: () => {
console.log(‘NATIVE HELLO’);
}
}
}),
});
v.$on(‘hello’, () => {
console.log(‘ON HELLO’);
});

v.$mount(‘#app’);

Solution :

Seems like this is a dup of:

How to bubble events on a component subcomponent chain with vue.js js 2?

Only a direct parent of a component can listen for events. I used native JS events instead:

this.$el.dispatchEvent(new CustomEvent(‘hello’, {
detail: { … },
bubbles: true,
composed: true
}));

Solution 2:

As @Decade Moon said, the div should have some content to be able to be clickable. For example:

<div v-on:click=”clicked”>Test content</div>

You can check my demo on Codepen