@Output and Cannot read property emit of undefined

Hello, I have a component, which paints with paper.js on a canvas.
I want fire a event, when touchends.T have:

import { Component, Output, EventEmitter } from '@angular/core';

and

export class UipaperComponent {

@Output() strokeAdded = new EventEmitter();

and in

touchendEvent(event: TouchEvent) {
  
    //Clear Mouse Drag Flag
    drag = false;

console.log("touchendEvent: " + "pageX: " + event.changedTouches[0].pageX  + "; pageY" + event.changedTouches[0].pageY );

 this.strokeAdded.emit('strokeadded');
 
  }

and got this error. What is wrong with this code?

ERROR TypeError: Cannot read property ‘emit’ of undefined
at HTMLCanvasElement.touchendEvent (uipaper.ts:279)
at t.invokeTask (polyfills.js:3)
at Object.onInvokeTask (core.es5.js:4140)
at t.invokeTask (polyfills.js:3)
at r.runTask (polyfills.js:3)
at HTMLCanvasElement.invoke (polyfills.js:3)
defaultErrorLogger @ core.es5.js:1084
ErrorHandler.handleError @ core.es5.js:1144
IonicErrorHandler.handleError @ ionic-error-handler.js:63
next @ core.es5.js:4778
schedulerFn @ core.es5.js:3851
SafeSubscriber.__tryOrUnsub @ Subscriber.js:238
SafeSubscriber.next @ Subscriber.js:185
Subscriber._next @ Subscriber.js:125
Subscriber.next @ Subscriber.js:89
Subject.next @ Subject.js:55
EventEmitter.emit @ core.es5.js:3837
NgZone.triggerError @ core.es5.js:4209
onHandleError @ core.es5.js:4170
t.handleError @ polyfills.js:3
r.runTask @ polyfills.js:3
invoke @ polyfills.js:3

Thanks in advance, anna-liebt.

Is ^ this line 279? It looks ok. I think there’s something important that you haven’t posted. Your Output declaration is raw though, Better is:
@Output() strokeAdded: EventEmitter<string> = new EventEmitter<string>();

Yes, this

this.strokeAdded.emit('strokeadded');

throw the error, but I don’t know why.

@Output() strokeAdded: EventEmitter<string> = new EventEmitter<string>();

makes the same error.

There is not more code, that have something to do with @Output().,

I have now tried with Events

import { Events } from 'ionic-angular';

and

constructor(public events: Events) {
    console.log('Hello UipaperComponent Component');

  }

and

touchendEvent(event: TouchEvent) {
    
    //Clear Mouse Drag Flag
    drag = false;

console.log("touchendEvent: " + "pageX: " + event.changedTouches[0].pageX  + "; pageY" + event.changedTouches[0].pageY );

 //this.strokeAdded.emit('strokeadded');
 
this.events.publish('strokeAdded', Date.now());
  }

I got the same error on publish.
ERROR TypeError: Cannot read property ‘publish’ of undefined
at HTMLCanvasElement.touchendEvent (uipaper.ts:283)

Thanks, anna-liebt

The problem lies in code you haven’t posted.

I suspect you are losing execution context. Don’t pass non-static object methods like touchendEvent() by name anywhere. Turn it into a lambda instead.

Hello,
yesterday evening I played a little bit arround with my problem. I tried it with a new component with only a button. On button click I emit the event and it worked as expected. As Aaaron postet, that the problem lies in not posted code, I rebuild my component with minimal code and got the same problem again.

In html

<canvas id="myuibackgroundtextcanvas"  style='background-color: lightpink'></canvas>

<button id='myuibackgroundtextbutton' (click)='testit()'>Test</button>

and in ts

import { Component, Output, EventEmitter } from '@angular/core';

var papercanvas: HTMLCanvasElement;
var b: HTMLButtonElement;

@Component({
  selector: 'uibackgroundtext',
  templateUrl: 'uibackgroundtext.html'
})
export class UibackgroundtextComponent {

  @Output() strokeAdded: EventEmitter<string> = new EventEmitter<string>();

  constructor() {

  }

  ngOnInit() {
    console.log("ngOnInit uibackgroundtext");
    papercanvas = <HTMLCanvasElement>document.getElementById('myuibackgroundtextcanvas');

    papercanvas.addEventListener('touchend', this.touchendEvent);
    b = <HTMLButtonElement>document.getElementById('myuibackgroundtextbutton');
  }

  touchendEvent(event: TouchEvent) {

    console.log("touchendEvent uibackgroundtext");
    this.strokeAdded.emit('strokeadded');
   //this.testit();
    //b.click();
  }

  testit() {
    console.log("testit uibackgroundtext");
    this.strokeAdded.emit('strokeadded');
  }

}

With this code I get the error.

//this.strokeAdded.emit('strokeadded');
   this.testit();
    //b.click();

with this.testit() I get the same error and it seems similar to a proplem i posted before, where I got a problem calling two functions from touchendEvent.

//this.strokeAdded.emit('strokeadded');
  // this.testit();
    b.click();

with b.click(); it is working. As you see in html (click) calls testit() and this.strokeAdded.emit(‘strokeadded’); works as expected.

Lambdas? I don’t know how to do what you suggest. Have you a little bit of code for me? The possibilities of lambdas are new for me.

Thanks in advance, anna-liebt.

I think you are doing too much direct DOM manipulation, and would recommend using @ViewChild for the rare case where you absolutely need it. I don’t think you need it for the button, and should be able to simply let the (click) handler do its job, and this whole problem should go away. If you absolutely insist on using naked event listeners instead, here is what I am talking about with respect to execution context, and this is what I mean by lambdas.

Adding to what @rapropos said, your code looks as though you understand Javascript, but do not understand Angular. For example

<thisIsYourPaperCanvasThing (click)="canvasClicked()">

canvasClicked() {
  Do stuff here
}

That might save you lots of code and if you do that sort of thing – taking advantage of Angular – you might find that your errors just go away.

Hello rapropos,

the button is not my problem. As suggested, I made a new minimal component with only a button and saw that this.strokeAdded.emit(‘strokeadded’); is working. So I extend it with a canvas and touchend and see the same failure as in my real component.

My “real” component has no button, but a canvas. On that canvas the user paint and I want react, if the strokes end. So I use a eventlistener for touchend, but in the method I got an error with this.strokeAdded.emit(‘strokeadded’);

So in the above minimum example you can see, maybe, that this.strokeAdded.emit(‘strokeadded’); seems do not working with touchend, do not work with call testit() from touchend, but works with button.click and with (click).

So what I must do that touchend is working (without the button)?

Best regards, anna-liebt.

Bothering to read the links I gave you in the previous post would be a good start.