Nuxt plugin cannot access Vue's 'this' instance in function blocks - javascript

So I have managed to inject hls.js to work with nuxtjs $root element and this
I did so doing it like this (hls.client.js):
import Hls from 'hls.js';
export default (context, inject) => {
inject('myhls', Hls)
}
and nuxt.config.js
plugins: [
'~plugins/hls.client.js',
],
This works great, literally :-) but I can't reference 'this' in the hls events.
playHls() {
this.playing = true
if(this.$myhls.isSupported()) {
this.hls = new this.$myhls();
this.audio = new Audio('');
this.hls.attachMedia(this.audio);
this.hls.loadSource(this.scr_arr[2]);
this.audio.play()
// 'THIS' DOES NOT WORK INSIDE this.hls.on
this.hls.on(this.$myhls.Events.MEDIA_ATTACHED, function () {
console.log(this.scr_arr[2]); // DOES NOT LOG
console.log("ok") // works great
});
// 'THIS' DOES NOT WORK INSIDE this.hls.on
this.hls.on(this.$myhls.Events.MANIFEST_PARSED, function (event, data) {
console.log('manifest loaded, found ' + data.levels.length + ' quality level') // WORKS
console.log("ok") // WORKS
this.audio.volume = 1 // DOES not work
});
}
},
So I in these Events I can't use nuxtjs 'this', cause there seems to be a different scope?
Can I somehow get 'this' nuxt scope inside these Events?

Replace your functions like
this.hls.on(this.$myhls.Events.MANIFEST_PARSED, function (event, data) {
into
this.hls.on(this.$myhls.Events.MANIFEST_PARSED, (event, data) => {
to keep the this context tied to the Vue app, otherwise it will be scoped to the context of the block scope.

Related

How to remove an event in Vue?

On my Vue instance I have this:
async mounted () {
document.addEventListener('paste', this.onPasteEvent)
},
beforeDestroy () {
document.removeEventListener('paste', this.onPasteEvent)
},
methods: {
onPasteEvent () {
return async (event) => {
try {
const items = event.clipboardData.items
const files = await this.getBase64Files(items)
this.transferedItems = files
this.modal = true
} catch (error) {
this.$toast.error('Não foi possível detectar um arquivo na área de transferência.')
}
}
},
I'm trying to destroy the "paste" event when the component is destroyed, but this just doesnt work, I know I need to pass the same reference to removeEventListener, but is this not the same reference?
The only way I found to make this work is placing the onPasteEvent method outside the Vue instance as a constant, but that way I don't have access to this instance, which is important to me, also, I can't pass anything as arguments, if I try to pass something, looks like my function create a new reference on memory, making unable to destroy it using removeEventListener.
Please, I just don't understand how to remove a event in JavaScript, can someone help me with that example? I already saw a lot of similar questions but no one explains:
How to keep the method reference even if it has parameters?
How to remove the event working with Vue instances?
Your code is already removing the event listener correctly, but there's a couple other problems:
onPasteEvent returns a function, so when the paste event occurs, the handler only returns a new function (which does not get executed), so it's basically doing nothing useful.
To fix the paste event handler, convert the returned function into the onPasteEvent function itself:
export default {
methods: {
async onPasteEvent (event) {
try {
const items = event.clipboardData.items
const files = await this.getBase64Files(items)
this.transferedItems = files
this.modal = true
} catch (error) {
this.$toast.error('Não foi possível detectar um arquivo na área de transferência.')
}
}
}
}
And if you're using Vue 3, the beforeDestroy hook from Vue 2 is renamed to beforeUnmount:
export default {
// beforeDestroy() { ❌ renamed in Vue 3
beforeUnmount() { ✅
document.removeEventListener('paste', this.onPasteEvent)
},
}
demo

"Uncaught ReferenceError: window is not defined" p5.js web worker

I have a javascript code where I use the web worker with the p5.js library. it wouldn't allow me to use any of p5's functions so I have to use the importScripts("p5.js") function to import the p5.js library before using any of p5's functions.
onmessage = (e)=>{
importScripts("p5.min.js")
// other scripts
}
But even then it gives me another error that said "Uncaught ReferenceError: window is not defined". I tracked it down and it seemed that p5 is unable to use the global variable named "window". I searched around the internet for a solution but so far found none. I wonder if there is a way around this. Thank you.
The issue here is that web workers run in a very isolated context where many of the standard global variables that would exist for javascript running on a website (window, document, etc) don't exist, and unfortunately p5.js cannot load without these variables. You could try shimming them with fake versions. Here's a basic example:
let loadHandlers = [];
window = {
performance: performance,
document: {
hasFocus: () => true,
createElementNS: (ns, elem) => {
console.warn(`p5.js tryied to created a DOM element '${ns}:${elem}`);
// Web Workers don't have a DOM
return {};
}
},
screen: {},
addEventListener: (e, handler) => {
if (e === "load") {
loadHandlers.push(handler);
} else {
console.warn(`p5.js tried to added an event listener for '${e}'`);
}
},
removeEventListener: () => {},
location: {
href: "about:blank",
origin: "null",
protocol: "about:",
host: "",
hostname: "",
port: "",
pathname: "blank",
search: "",
hash: ""
}
};
document = window.document;
screen = window.screen;
// Without a setup function p5.js will not declare global functions
window.setup = () => {
window.noCanvas();
window.noLoop();
};
importScripts("/p5.js");
// Initialize p5.js
for (const handler of loadHandlers) {
handler();
}
postMessage({ color: "green" });
onmessage = msg => {
if (msg.data === "getRandomColor") {
// p5.js places all of its global declarations on window
postMessage({
color: window.random([
"red",
"limegreen",
"blue",
"magenta",
"yellow",
"cyan"
])
});
}
};
This is only going to work for a limited subset of p5.js functions. Any functions that draw to the canvas are definitely not going to work. And I would be cautious about trying to pass objects back and forth (i.e. p5.Vector, p5.Color, etc) because everything sent via postMessage gets serialized and deserialized.
I've posted a working version of this example on Glitch.

Aframe component can't reference el from event handler

I am trying to write a game using lance-gg library.
I tried to implement a simple aframe component, that print entity's object3D position and rotation in world space.
The problem is that I cannot access this from within the component event listener.
I have tried to search around I've found this [thread] (Aframe unregister component), so I guess the problem is the initialization order. I have tried to include a component directly from the index but it does't worked either.
// aSeparateFile.js
AFRAME.registerComponent(
'custom-component',
{
schema: {
controllerID: {
type: 'string',
default: 'none'
}
},
init: () => {
console.log('componet has been created');
console.log(this);
},
tick: () => {
console.log(this.el.object3D.rotation);
console.log(this.el.object3D.position);
}
}
);
this component was created in a separate file called aSeparateFile.js, I include this file from my AFrameRenderer extension. Like this:
import {AFRAMERenderer} from 'lance-gg';
import './aSeparateFile.js';
I would like to know the best way to register a custom component with lance-gg.
Don't use arrow functions that will bind the methods to the wrong this. Use regular functions instead:
AFRAME.registerComponent(
'custom-component',
{
schema: {
controllerID: {
type: 'string',
default: 'none'
}
},
init: function () {
console.log('componet has been created');
console.log(this);
},
tick: function () {
console.log(this.el.object3D.rotation);
console.log(this.el.object3D.position);
}
});

$log anonymous function angular js not working

I have a problem when I try to log some data inside the function of webtorrent.
I want to log some values of this.client.add but I don't have access.
Some idea of what's going on here?
import Webtorrent from 'webtorrent';
class PlaylistController {
/** #ngInject */
constructor($http, $log) {
this.log = $log;
this.client = new Webtorrent();
$http
.get('app/playlist/playlist.json')
.then(response => {
this.Torrent = response.data;
});
}
addTorrent(magnetUri) {
this.log.log(magnetUri);
this.client.add(magnetUri, function (torrent) {
// Got torrent metadata!
this.log.log('Client is downloading:', torrent.infoHash);
torrent.files.forEach(file => {
this.log(file);
});
});
this.log.log('sda');
this.log.log(this.client);
}
}
export const playlist = {
templateUrl: "app/playlist/playlist.html",
controller: PlaylistController,
bindings: {
playlist: '<'
}
};
Another thing its I use yeoman for the scaffold of my app and its has JSLint with console.log forbidden and its said that you must use angular.$log, but the thing its I don't wanna change that, I wanna understand the problem here.
You either need to refer to this (the class) as another variable to use inside the function(torrent) function or use arrow functions so that this reference remains the class one.
Solution 1, using another variable to ref the class:
addTorrent(magnetUri) {
this.log.log(magnetUri);
var that = this;
this.client.add(magnetUri, function (torrent) {
// Got torrent metadata!
that.log.log('Client is downloading:', torrent.infoHash);
torrent.files.forEach(file => {
that.log(file);
});
});
this.log.log('sda');
this.log.log(this.client);
}
Solution 2, using arrow functions:
addTorrent(magnetUri) {
this.log.log(magnetUri);
this.client.add(magnetUri, torrent => {
// Got torrent metadata!
this.log.log('Client is downloading:', torrent.infoHash);
torrent.files.forEach(file => {
this.log(file);
});
});
this.log.log('sda');
this.log.log(this.client);
}

Understanding this context in RequireJS

normally i would use this to load dependency
main: function() {
require(['views/home'], function(HomeView) {
_pageView.render(HomeView);
});
}
but now am looking of simplifying it by doing this
main: function() {
require(['views/home'], this.homeView);
},
homeView: function(HomeView) {
this.page = _pageView.render(HomeView);
}
but the keyword this is unrecognizable. How to make it recognizable.
Calling require like this:
require(['views/home'], this.homeView.bind(this));
should prevent this from getting set to a different value when RequireJS calls the callback.

Categories

Resources