Reputation: 361
I have a Stimulus controller inside which I have a setSegments function and then this code in the connect() method:
connect() {
const options = {
overview: {
container: document.getElementById('overview-container'),
waveformColor: 'blue',
},
mediaElement: document.querySelector('audio'),
dataUri: {
arraybuffer: document.getElementById('normal-audio-button').dataset.waveform
},
emitCueEvents: true,
};
Peaks.init(options, function (err, peaks) {
window.instance = peaks;
window.speed = "normal";
setSegments()
instance.on('segments.enter', function (segment) {
const segmentCard = document.getElementById(segment.id)
segmentCard.focus({preventScroll: true})
window.currentSegment = segment
});
});
}
setSegments() {
alert("segment set up)
}
I'm tryng to call setSegments() inside the Peaks.init function but it doesn't work because of the function's scope. I'm just not sure how to get around this. I tried calling this.setSegments() instead but it doesn't help.
What's the correct way of accessing the function in this case?
Thanks
Upvotes: 1
Views: 6473
Reputation: 5186
The problem is that this
is a bit confusing when working with JavaScript, however a way to think about it that it is the current context.
For example, when your code is running in the browser console or not in another function this
is the global window
object. When you are directly in the controller's connect
method this
is the controller's instance.
However, when you pass a function to Peaks.init
that function creates it's own new context where this
is the function's context and no longer the controller instance.
There are three common workarounds to calling this.setSegments
;
As per your solution, const setSegments = this.setSegments;
works because you are creating a reference outside the function scope and functions have access to this.
connect() {
const options = {}: // ... Options
// this is the controller's instance
const setSegments = this setSegments;
Peaks.init(options, function (err, peaks) {
// this is the peaks init handler context
window.instance = peaks;
// this.setSegments(): - will not work
setSegments();
instance.on('segments.enter', function (segment) {
// this is the event (usually)
});
});
}
this
You can pull your function out to a variable and then add .bind(this)
to it so that when the function is called it will use the this from the controller instance instead.
connect() {
const options = {}: // ... Options
// this is the controller's instance
const myFunction = function (err, peaks) {
// this is the BOUND this provided by the bind command and will be the controller's instance
window.instance = peaks;
this.setSegments():
instance.on('segments.enter', function (segment) {
// this is the event (usually)
});
};
myFunction.bind(this);
Peaks.init(options, myFunction);
}
You should be able to use an arrow function in modern browsers or if you have a build tool running it may transpiled this for older browsers.
Instead of function() {}
you use () => {}
and it grabs the this
from the parent function context instead.
connect() {
const options = {}: // ... Options
// this is the controller's instance
Peaks.init(options, (err, peaks) => {
// this is now the controller's instance and NOT the peak handler context
window.instance = peaks;
this.setSegments():
instance.on('segments.enter', function (segment) {
// this is the event (usually) and is NOT the controller instance as arrow function not used here.
});
});
}
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this for more details
Upvotes: 3
Reputation: 361
I don't know if it's the best way to do it but adding the following right after the beginning of the connect method did the trick:
let setSegments = this.setSegments
Upvotes: 0