Search code examples
arraysactionscript-3flash

How can i update the already exsistant array that is outputed in the textArea with info given by the user?


I have 2 seperate arrays declared, where the corresponding index of each array is "information" about a person.

var alderArr: Array = [45, 34, 18, 12, 27];
var navnArr: Array = ["N. Linjesæter", "P. Kurverud", "O. Sirkelstad", "J. Rektangelsen", "M. Ellipsen"];

Then i also have 2 different input fields where the user can input information that will get added to the array when the button btnLeggTill is pressed. And the arrays seem to update based on the trace(alderArr + "\n" + navnArr)

btnLeggTil.addEventListener(MouseEvent.CLICK, leggTil);
function leggTil(evt:MouseEvent) {

    var nyttNavn: String = txtNavn.text;
    var nyAlder: int = int(txtAlder.text);
    //trace(nyttNavn + nyAlder);                            Debug
    alderArr.push(nyAlder);
    navnArr.push(nyttNavn);
    trace(alderArr + "\n" + navnArr);                                   
}//leggTil()

for (var i:int = 0; i < alderArr.length; i++) {

    textArea.text += navnArr[i] + ", Alder: " + alderArr[i] + "\n";
}//for

But the information does not seem to update in the textArea. This is basically what I want to accomplish. I want to make it so that when the user inputs new information and new things are added in the array, the textArea will also be updated so it displays this information to the user.


Solution

  • I have 2 seperate arrays declared

    While it certainly gets the job done, it's far from ideal. Splitting data that belongs together over several data structures means that you have to keep both arrays in sync.

    A better way to model your data is to create a class for it. It's not too difficult, an obvious name would be Person. According to your code, a person has two properties: age and name. Save the following into a file named Person.as to get started.

    package
    {
        public class Person
        {
            private var name:String;
            private var age:int;
            
            public function Person(name:String, age:int)
            {
                this.name = name;
                this.age = age;
            }
        }
    }
    

    The advantages are that you can perform all kinds of sanity checks (on the given parameters and that you can add all kinds of functionality to it.

    Speaking of functionality, add a toString() method, which returns a String representation of the object.

    package
    {
        public class Person
        {
            private var name:String;
            private var age:int;
            
            public function Person(name:String, age:int)
            {
                this.name = name;
                this.age = age;
            }
            
            public function toString():String
            {
                return name + ", Alder: " + age;
            }
        }
    }
    

    You can use that class to create objects, which can be passed to trace() to output them as a String according to the above function:

    var person:Person = new Person("Jack", 35);
    
    trace(person);   //Jack, Alder: 35
    

    Now you could have a single Array of Person objects. That's much more intuitive. But there's a problem with Array...

    But the information does not seem to update in the textArea

    That's true. The TextArea is a rather simple component. Just to be clear here, we are talking about Flash's fl.controls.TextArea.

    It's more or less just a TextField. It has no way of asking an array if it was updated (an element added, for example) and an Array has no way of telling anybody that it was updated.

    The problem is usually solved by having something other than Array, which can tell if it just got changed. One class capable of doing that is DataProvider, specifically fl.data.DataProvider.

    Instead of storing Person objects in an Array, you store them in a DataProvider on your main timeline:

    var people:DataProvider = new DataProvider();
    
    people.addItem(new Person("Jack", 35));
    people.addItem(new Person("Jane", 20));
    people.addItem(new Person("Charlie", 25));
    
    for (var i:int = 0; i < people.length; ++i)
    {
        trace(people.getItemAt(i));
    }
    

    This adds some dummy data and uses a for loop to trace() all items. To join the elements to a string more easily, you can also get an Array representation from the DataProvider and call its join() method:

    var people:DataProvider = new DataProvider();
    
    people.addItem(new Person("Jack", 35));
    people.addItem(new Person("Jane", 20));
    people.addItem(new Person("Charlie", 25));
    
    trace(people.toArray().join("\n"));
    

    To inform others about the change of data, the DataProvider dispatches a fl.events.DataChangeEvent of type DATA_CHANGE. Add a listener for that event to update the TextArea accordingly:

    var people:DataProvider = new DataProvider();
    
    people.addEventListener(DataChangeEvent.DATA_CHANGE, onDataChange);
    
    function onDataChange(e:DataChangeEvent):void
    {
        textArea.text = people.toArray().join("\n");
    }
    
    people.addItem(new Person("Jack", 35));
    people.addItem(new Person("Jane", 20));
    people.addItem(new Person("Charlie", 25));
    

    Whenever you add (or remove) something from the DataProvider, the event fires and textArea is updated. In your code, this could look like this:

    var people:DataProvider = new DataProvider();
    people.addEventListener(DataChangeEvent.DATA_CHANGE, onPeopleDataChanged);
    
    function onPeopleDataChanged(e:DataChangeEvent):void
    {
        textArea.text = people.toArray().join("\n");
    }
    
    addPersonButton.addEventListener(MouseEvent.CLICK, addPerson);
    function addPerson(e:MouseEvent):void
    {
        people.addItem(new Person(nameInput.text, int(ageInput.text)));
    }
    

    I changed your variable names. ALWAYS use English identifiers in your programming. It's a major pain to read your code without knowing what a leggTil is. If you ask people on the internet for help, use English. If I first have to come up with the elvish word for friend before understanding your code, chances are I'll be eaten by a giant octopus before being able to help you. It is in your own interest to make your code as easy to digest as possible.

    Also note that I removed the local variables. There's no real need for them and they only bloat the code. With functionality in the Person class, the code is really slim now. It almost reads like human lanugage: "add an item to people which is a new person with given name and age"


    The DataProvider works even better with other classes than TextArea. In my answer, I only demonstrate how to make the Array smarter. But there are other things similar to TextArea that are smarter, too. Some components can be passed a DataProvider directly. They add the listener to themselves and wire up the functionality to update their text when the DataProvider changes. If you do not explicitly have to useTextArea, I recommend using ComboBox, DataGrid, List or TileList component. Here's an article on how to make them work with a DataProvider