jmstoh jmstoh - 1 month ago 207
TypeScript Question

Angular2 and Web Midi

I'm new to Typescript and I'm trying to use Angular2 to create a Web Midi app, but I'm having some troubles understanding certain errors. I believe I should be putting the Midi functions inside a Service, but do correct me if I'm wrong.

The example below works, when the midi variable and onMIDIMessage function is outside

var midi:any;

function onMIDIMessage(event) {
console.log("msg received", event);
}

export class MidiService {

onMidiInit() {
if (navigator.requestMIDIAccess) {
navigator.requestMIDIAccess({
sysex: false
}).then(this.onMIDISuccess, this.onMIDIFailure);
} else {
alert("No MIDI support in your browser.");
}
}

onMIDISuccess(midiAccess) {
console.log('MIDI Access Object', midiAccess);
midi = midiAccess;
console.log(midi);

var inputs = midi.inputs.values();
for (var input = inputs.next(); input && !input.done; input = inputs.next()) {
input.value.onmidimessage = onMIDIMessage;
}

}

onMIDIFailure(e) {
console.log(e);
}
}


All is good and I can print out incoming MIDI messages with this. However, what I do not understand is that when the onMIDIMessage function and midi variable is inside the MidiService class, Chrome throws an error. Why is that happening?


midi.service.ts:24 Uncaught (in promise) TypeError: Cannot read property >'onMIDIMessage' of undefined at MidiService.onMIDISuccess (http://localhost:3000/app/midi.service.js:27:57)


var midi:any;

// Code that does not work
export class MidiService {

onMidiInit() {
if (navigator.requestMIDIAccess) {
navigator.requestMIDIAccess({
sysex: false
}).then(this.onMIDISuccess, this.onMIDIFailure);
} else {
alert("No MIDI support in your browser.");
}
}

onMIDISuccess(midiAccess) {
console.log('MIDI Access Object', midiAccess);
midi = midiAccess;
console.log(midi);

var inputs = midi.inputs.values();
for (var input = inputs.next(); input && !input.done; input = inputs.next()) {
input.value.onmidimessage = this.onMIDIMessage;
}

}

onMIDIMessage(event) {
console.log("msg received", event);
}

onMIDIFailure(e) {
console.log(e);
}
}


---EDIT

The methods are called in the app.component.ts file.

import {Component} from 'angular2/core';
import {MidiService} from './midi.service';

@Component({
selector: 'my-app',
template: '<h1>My First Angular 2 App</h1>',
providers: [MidiService]
})
export class AppComponent {
constructor(midiService: MidiService) {
midiService.onMidiInit();
}
}

Answer

Looks like this doesn't point to the current class instance.

Add .bind(this) when you pass methods of the current class as callbacks:

input.value.onmidimessage = this.onMIDIMessage.bind(this);
Comments