[SOLVED] Can't get text changed event

I’d like to be notified when a text changes.
In a script attached to the text element, I tried to register in many ways but none of them worked:

this.on('attr:text', ...)
this.entity.on('attr:text', ...)
this.entity.element.on('attr:text', ...)

Any hint?

The attr: event only trigger when the script attributes change… That is:

var MyScript = pc.createScript('myScript');

MyScript.attributes.add('a', { type: 'number' });
MyScript.attributes.add('b', { type: 'string' });

When the a or b of MyScript instance change, the attr:a or attr:b will trigger.

Yes and this is the way I use it. But how to be notified when an element property changes?
Wouldn’t be better to unify the logic?
From the user point of view they look like attributes.

Yes, I think it is a good way to listen attributes change.

this.on('attr:text', ...)  // the script attribute `text` change
this.entity.on('attr:text', ...) // as entity don't have `text` attribute, this should not work
this.entity.element.on('attr:text', ...) // the element component attribute `text` change

@dave @will
There is a way to get this notification?
I’m building a set of script around the text element, and I can’t code them in a nice way because of this.
I had to expose another text attribute in my script, and add a setText() method so that I can do something once the text changes.

But having multiple scripts doing individual effects (shadow, scaling background, auto size of the font, etc…) is a problem. I had to create a main script just to set the text that will raise a custom event, so that my other scripts can be notified. It works, but if I can avoid it and use the element.text property itself would be nicer.

How is the text changed in your use case? AFAIK, the attr:* events are only fired if you change it in the editor and the app is running in the launch window.

really? are you 100% sure?

From the manual:


yes ok, but this doesn’t exclude that if I change an attribute by code it should not fire the event.

I did a test and it works as expected:

var Text = pc.createScript('text');

Text.attributes.add('text', {
    type: 'string', 
    default: '', 
    title: 'Text'

// initialize code called once per entity
Text.prototype.initialize = function() {
    this.on('attr:text', function(){
    }, this);
    this.text = 'hello';

when I hit play, it prints “hello” in the console

My bad, you are right.

Had a quick look at the code in the engine. The TextElement is not a script component so it doesn’t have any attributes and also doesn’t fire any attr:* events.

When the text is updated in the TextElement, no events are fired but you can monkey patch the text property to fire an event to your liking: https://github.com/playcanvas/engine/blob/18bdc36d108031beca3fbfab948feb911eea2159/src/framework/components/element/text-element.js#L376

There is no event fired when the text of a text element changes at the moment. This is on purpose at the moment because firing events is not cheap and you can imagine having text elements changing text every frame like scores / timers etc…

It sounds like what you did with a custom setText method is a good solution, otherwise like @yaustar said you could maybe monkey patch the text property although that’s not recommended…

Thank you both. I’ll go with my custom text script then.

I didn’t know that firing not registered event could be a problem. I thought that you have some sort of array of function pointers to cycle, but if the array is null should be just the cost of an if to skip the whole event firing process.

I’ll take a look to the source code to see how is implemented.