2

I need the text in an input TLF text field to be modified when the user changes it. As for example, I'm trying to make it uppercase every time the user adds or deletes a character:

import fl.text.TLFTextField;
import flashx.textLayout.formats.TextLayoutFormat;
import flashx.textLayout.elements.TextFlow;

var myTLFTextField:TLFTextField = new TLFTextField();
addChild(myTLFTextField); 
myTLFTextField.x = 10;
myTLFTextField.y = 10;
myTLFTextField.width = 200
myTLFTextField.height = 100;
myTLFTextField.text = "This is my text";

var myFormat:TextLayoutFormat = new TextLayoutFormat();
myFormat.textIndent = 8;
myFormat.color = 0x336633;
myFormat.fontFamily = "Arial, Helvetica, _sans";
myFormat.fontSize = 24;

var myTextFlow:TextFlow = myTLFTextField.textFlow;
myTextFlow.hostFormat = myFormat;
myTextFlow.flowComposer.updateAllControllers();

//--

myTLFTextField.addEventListener(Event.CHANGE, this.onTextFieldChange);
function onTextFieldChange(event:Event):void
{
    myTLFTextField.text = myTLFTextField.text.toUpperCase();
}

The code that goes before //-- is taken from the TLFTextField documentation, the very first example on the page.

When I try to edit the text, it does become uppercase, but after that the text field stops responding to any input and the output says

TypeError: Error #1009: Cannot access a property or method of a null object reference. at flashx.textLayout.container::TextContainerManager/getController() at flashx.textLayout.container::TextContainerManager/mouseDownHandler()

When I comment out the addEventListener line, all appears to be working fine.

Does it mean that it's not possible to make changes to the text in a TLF text field on user input event like it is possible with the classic text fields?

Pleo
  • 309
  • 1
  • 11
  • 1
    Could be an infinite loop. Try checking if the case actually needs to be changed in your callback; `if( myTLFTextField.text.toUpperCase() != myTLFTextField.text )` – Dave Apr 17 '13 at 20:25
  • @Dave Well my question is not about uppercase (there's a built-in feature to keep text uppercase anyways) but more about making changes to the text on user input events. If you try making changes in some other way, like adding a letter "A" to the text's end instead of making it uppercase, you run into the same kind of problem. – Pleo Apr 17 '13 at 20:28
  • well ok but my point still stands; it could be that by changing the text you trigger the callback, which changes the text, which (...). I'm not *sure* that's the problem, but you can check by breaking that loop. If it turns out it is the problem, you can try to change the event you listen to or use a variable marker (set to `true` if already in the callback, for example). – Dave Apr 17 '13 at 20:31
  • @Dave What would be the best way to break the loop then? Sorry if I didn't get what you meant by variable marker.. – Pleo Apr 17 '13 at 20:35
  • Nevermind, seems I'm wrong about that: http://stackoverflow.com/a/979281/1180785 – Dave Apr 17 '13 at 21:39
  • Back to your problem, the error message doesn't make sense for this problem; are you sure it isn't an issue somewhere else? You could also try rearranging the code to have `addEventListener` below your function (technically the function doesn't exist there so it might be undefined; I can't remember how AS3 behaves in that situation). Also to help you debug you should turn debug mode on and as many warning options as you can find. – Dave Apr 17 '13 at 21:41
  • try to remove the this in myTLFTextField.addEventListener(Event.CHANGE, this.onTextFieldChange); – RafH Apr 17 '13 at 22:10
  • @Dave Yes, I'm sure of it. Tried moving `addEventListener` below the function, made no difference. The debug mode didn't help a bit. – Pleo Apr 18 '13 at 07:41
  • @RafH Tried that, same thing. – Pleo Apr 18 '13 at 07:42
  • @Dave Just checked it on another computer with a separate installation of Flash CS6, same problem. I suspect that TLFTextField was designed so that, unlike the regular TextField, it doesn't expect the text to get changed when sending `Event.CHANGE` events, then how I'm supposed to change the text in response to user input into a TLFTextField instance? – Pleo Apr 18 '13 at 07:52
  • @Pleo debug mode should have given you line numbers and a better stack trace with the error message. Maybe you don't have the developer version of flash player installed? Although even with it, debugging runtime errors is pretty hard; Flash doesn't have the best debugging capabilities. – Dave Apr 18 '13 at 10:04
  • @pleo your posted error has nothing to do with the code you posted. You are not posting enough code for anyone to make a reasonable answer for you. However, I will take a guess and say you are using the wrong event. try this myTextFlow.addEventListener(FlowOperationEvent.FLOW_OPERATION_COMPLETE, onFlowComplete) – The_asMan Apr 18 '13 at 13:07
  • 2
    @The_asMan That is not true. Anyone with a Flash CS6 can create an empty AS3 document, copy/paste the code into the first frame, and get the very same error in the output panel. I already tried `FLOW_OPERATION_COMPLETE`, problems persisted. – Pleo Apr 18 '13 at 14:37
  • @Dave Maybe it should have given the line numbers, but it didn't (was debugging in Flash CS6, Debug menu > Debug Movie > Debug). – Pleo Apr 18 '13 at 14:40

3 Answers3

0

Can't try your code right now so this is a wild guess, but the controllers seem to disappear when you set the text. what happens if you symply do this :

private var m_dontupdate:Boolean;
function onTextFieldChange(event:Event):void
{
  if(m_dontupdate) return;
  m_dontupdate = true;
  myTLFTextField.text = myTLFTextField.text.toUpperCase();
  myTLFTextField.textFlow.flowComposer.updateAllControllers();
  m_dontupdate = false;
}

? (I can't try it because I use FB 4.7 and TLFTextField is nowhere to be found).

Boris
  • 1,161
  • 9
  • 20
  • If I'm right you may have to keep a reference to myFormat, and re-set the format in `onTextFieldChange` – Boris Apr 22 '13 at 12:33
  • Unlike the original, this one really seems to be causing an infinite loop with a waterfall of errors. So, it didn't work.. – Pleo Apr 23 '13 at 07:49
0

Why? Because TLF has got problems. As others have pointed out, changing TLF text inside an Event.CHANGE handler causes the change handler to be called a second time. At that point, things break down.

I had come up with a solution that's similar to the one @Abe posted, but it's more general – it doesn't rely on checking for upper case characters. You listen for TextEvent.TEXT_INPUT, then toggle an Event.CHANGE listener inside the text input handler.

import fl.text.TLFTextField;
import flashx.textLayout.formats.TextLayoutFormat;
import flashx.textLayout.elements.TextFlow;
import flash.text.TextFieldType;
import flash.events.TextEvent;

var myTLFTextField:TLFTextField = new TLFTextField();
addChild(myTLFTextField); 
myTLFTextField.x = 10;
myTLFTextField.y = 10;
myTLFTextField.width = 500
myTLFTextField.height = 100;
myTLFTextField.text = "This is my text";
myTLFTextField.border = true;
myTLFTextField.multiline = true;
myTLFTextField.type = TextFieldType.INPUT;

var myFormat:TextLayoutFormat = new TextLayoutFormat();
myFormat.textIndent = 8;
myFormat.color = 0x336633;
myFormat.fontFamily = "Arial, Helvetica, _sans";
myFormat.fontSize = 24;

var myTextFlow:TextFlow = myTLFTextField.textFlow;
myTextFlow.hostFormat = myFormat;
myTextFlow.flowComposer.updateAllControllers();

myTLFTextField.addEventListener(TextEvent.TEXT_INPUT, onTextInput);

var selectionIndex:uint;
function onTextInput(e:TextEvent):void
{
    trace("onTextInput");
    selectionIndex = myTLFTextField.selectionEndIndex;
    myTLFTextField.addEventListener(Event.CHANGE, onTextChanged);
}

function onTextChanged(e:Event):void
{
    trace("onTextChanged");
    myTLFTextField.removeEventListener(Event.CHANGE, onTextChanged);

    // Do whatever you need to do here:
    myTLFTextField.text = myTLFTextField.text.toUpperCase();
    myTLFTextField.setSelection(selectionIndex + 1, selectionIndex + 1);
}
T Graham
  • 1,329
  • 10
  • 14
  • Thanks but, with this code, the blinking caret disappears all the time and when a character is deleted, the change is ignored. – Pleo Apr 29 '13 at 13:06
-1

First - you doing infinite loop in event listener! Your code in event handler invokes it selves! TLF.text = VALUE produce event like TLF.dispatch(new Event(Event.CHANGE));

So add event listener to user actions not text change! E.g. for KEY_UP

Second - correct formatting code so it will be applied to new text:

myTLFTextField.text = NEW_VALUE;

myTextFlow = myTLFTextField.textFlow;
myTextFlow.hostFormat = myFormat;

Edit: For more clarity I add full code:

import fl.text.TLFTextField;
import flashx.textLayout.formats.TextLayoutFormat;
import flashx.textLayout.elements.TextFlow;
import flash.events.KeyboardEvent;

var myTLFTextField:TLFTextField = new TLFTextField();
addChild(myTLFTextField);
myTLFTextField.x = 10;
myTLFTextField.y = 10;
myTLFTextField.width = 400;
myTLFTextField.height = 100;
myTLFTextField.text = "This is my text";
myTLFTextField.type = "input";
//allow user to wirte in filed

var myFormat:TextLayoutFormat = new TextLayoutFormat();
myFormat.textIndent = 8;
myFormat.color = 0x336633;
myFormat.fontFamily = "Arial, Helvetica, _sans";
myFormat.fontSize = 24;

var myTextFlow:TextFlow = myTLFTextField.textFlow;
myTextFlow.hostFormat = myFormat;
myTextFlow.flowComposer.updateAllControllers();

//--;

myTLFTextField.addEventListener(Event.CHANGE, wrongHandler);
myTLFTextField.addEventListener(KeyboardEvent.KEY_UP, goodHandler);
myTLFTextField.text = 'TEXT';
//this invoke CHANGE and trace '-' in console

setTimeout(function(){  myTLFTextField.text = 'text';}, 500);
//this invoke CHANGE and trace '-' in console

function wrongHandler(event:Event):void
{
    //myTLFTextField.text = myTLFTextField.text.toUpperCase();
    //myTextFlow = myTLFTextField.textFlow;
    //myTextFlow.hostFormat = myFormat;
    // above code will run infinity loop of changing text! test it by uncomment and comment KEY_UP listener!
    trace('-'); // to see in console when and how many event was triggered
}

function goodHandler(event:Event):void
{
    myTLFTextField.text = myTLFTextField.text.toUpperCase();
    myTextFlow = myTLFTextField.textFlow; // reasign formating
    myTextFlow.hostFormat = myFormat;
    var i:uint = myTLFTextField.text.length;
    myTLFTextField.setSelection(i,i); // move carret to last sign
    trace('+'); // to see in console when and how many event was triggered
}

Output:

  1. -
  2. -

Output after writing 'a' character in field:

  1. -
  2. -
  3. -
  4. -
  5. +
  6. -

Result on stage: TEXTA

Konrad
  • 345
  • 3
  • 8
  • It does not cause any infinite loops. This can be easily confirmed by trying to change the `text` property of the text field right after adding a listener for the `Event.CHANGE` event, the `onTextFieldChange` function is not being called, it's only called on user input. – Pleo Apr 23 '13 at 07:57
  • You wrong in my opinion. See changes in my answer. Code is tested so don't tell it won't work. – Konrad Apr 23 '13 at 12:30
  • @Pleo If you disagree show tested code that prove your right. – Konrad Apr 23 '13 at 12:42
  • I've just tested it. `wrongHandler` function in your code is called twice but I don't see how being called twice qualifies for an infinite loop. And even if it was infinite loop, it would NOT be the first line in `wrongHandler` to cause it because, even with that line commented out, the `wrongHandler` is still called twice on every user input. And btw there are ways of user input other than key pressing, that's why `Event.CHANGE` event, which causes no problems with classic text fields, needs to be used. – Pleo Apr 23 '13 at 14:43
  • If you want to use Event.CHANGE use stopImmediatePropagation when you apply changes on your text. – Konrad Apr 29 '13 at 20:21