Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problems in bindings using Labels with ContainerDataBinding #847

Open
raudjcholo opened this issue Jun 4, 2020 · 4 comments
Open

Problems in bindings using Labels with ContainerDataBinding #847

raudjcholo opened this issue Jun 4, 2020 · 4 comments

Comments

@raudjcholo
Copy link
Contributor

I have discovered a bug in bindings in a very specific case.

I use Crux and Jewel.

The bug appears when it's used Labels and ContainerDataBinding.

The text variable of Label has to be bound with a variable from an object declared in the model. And this object is updated by going through an array declared also in the model.

As we update the object, many listeners are created which slow down the update. If we use a ViewDataBinding, the problem disappears. And this does not happen in other components such as TextInputs.

I have created a small example so that it can be reproduced. Yo have to click in Next button and update slows down as you click the button. If you pause debugging, you can check all listeners in listenermap.js:

bug-binding

View:

<?xml version="1.0" encoding="utf-8"?>
<j:ApplicationResponsiveView xmlns:fx="http://ns.adobe.com/mxml/2009"
        xmlns:j="library://ns.apache.org/royale/jewel"
        xmlns:js="library://ns.apache.org/royale/basic"
    >
 <fx:Script>
        <![CDATA[
        import com.events.PersonalEvent;
        import com.models.PersonalModel;


        [Bindable]
        [Inject(source="personalModel", required="true")]
        public var personalModel:PersonalModel;

        [PostConstruct]
        public function initialize():void{
            var evt:PersonalEvent = new PersonalEvent(PersonalEvent.LOAD_DATA,null,this);
            dispatchEvent(evt);
        }

             
        private function navigateToNext():void
        {
            var evt:PersonalEvent = new PersonalEvent(PersonalEvent.NEXT_ITEM,null,this);
            dispatchEvent(evt);
        }
        
        

    ]]>
    </fx:Script>
    
    
    <j:beads>
        <js:ContainerDataBinding/>
    </j:beads>

     <j:VGroup width="400" gap="10">
            <j:HGroup>
                <j:Button localId="btlanzar2" text="Next" click="navigateToNext()"/>
                <j:Label localId="txtproc" text="{personalModel.item.codigo}" width="100"/>
            </j:HGroup>
        </j:VGroup>

</j:ApplicationResponsiveView>

Model:

package com.models {

    import com.Model;
    import org.apache.royale.collections.ArrayList;
    import com.dto.vo.TestItem;

    [Bindable]
    public class PersonalModel extends Model {

        private static var _instance:PersonalModel;

        public static function get instance():PersonalModel {
            return _instance || (_instance = new PersonalModel());
        }

        public function PersonalModel() {
            super();
            if (_instance) {
                trace('PersonalModel error');
                throw new Error("singleton");
            }
            _instance = this;
        }
public var data:ArrayList = new ArrayList();

        public var item:TestItem = null;

        public var itemIndex:int = -1;
}
}

Controller:

package com.controllers {

    import com.beads.controllers.Controller;
    import com.models.PersonalModel;
    import com.events.PersonalEvent;

    import org.apache.royale.core.IStrand;
    import org.apache.royale.collections.ArrayList;
    import com.dto.vo.TestItem;

    public class PersonalController extends Controller {

        public function get model():PersonalModel {
            return _model as PersonalModel;
        }

        [Inject]
        public function setModel(value:PersonalModel):void {
            _model = value;
        }

        /**
         * Constructor.
         */
        public function PersonalController() {
            super();
        }

        /**
         *  @copy org.apache.royale.core.IBead#strand
         *
         *  @langversion 3.0
         *  @playerversion Flash 10.2
         *  @playerversion AIR 2.6
         *  @productversion Royale 0.9.4
         */
        override public function set strand(value:IStrand):void {
            super.strand = value;
        }
[EventHandler(event = "PersonalEvent.LOAD_DATA", scope = "global")]
        public function loadData():void {
            var item:String;
            var dp:Array = [];
			var items:Array = [
				"Item1",
				"Item2",
				"Item3",
				"Item4",
				"Item5",
				"Item6",
				"Item7",
				"Item8",
				"Item9",
				"Item10",
				"Item11",
				"Item12",
				"Item13",
				"Item14",
			];
			for (var i:int = 0; i < 2000; i++)
			{
                var aux:TestItem = new TestItem();
				aux.codigo = getRandomArrayItem(items),
				dp.push(aux);
			}
            
            model.data = new ArrayList(dp);
        }

        public function getRandomArrayItem(array:Array):String {
			var idx:int=Math.floor(Math.random() * array.length);
			return array[idx];
		}

        [EventHandler(event = "PersonalEvent.NEXT_ITEM", scope = "global")]
        public function nextItem():void {
            model.itemIndex++;
            var aux:TestItem = model.data.getItemAt(model.itemIndex) as TestItem;
            model.item = aux; 
        }
}
}

TestItem Class:

package com.dto.vo {

	[Bindable]
    public class TestItem {
        public function TestItem() {
		}

		public var codigo:String = "";
		
    }

}

Thanks!!

@carlosrovira
Copy link
Contributor

Hi Raul,

I recreated this example and I think this is right at the moment. You have a View (ApplicationResponsiveView) that must use ViewDataBinding (not ContainerDataBinding).
Maybe using ContainerDataBinding should throw some kind of error instead to make the app hang.

Let me know if I could be wrong in something but with the info provided I can't see a real problem.

Thanks

@carlosrovira
Copy link
Contributor

I uploaded here the project I recreated with the problem, so we can go over it if I missed something: https://royale.codeoscopic.com/bindingproblem.zip

@raudjcholo
Copy link
Contributor Author

Hi Carlos,

The problem is the same if you have a container, for example a Group. If you use a container, you should use a ContainerDataBinding, but you would have the same problem. Then you have to use ViewDataBinding to make it work.

@carlosrovira
Copy link
Contributor

Today while doing some jewel docs for views and responsive views I notice that in TDJ I used ContainerDataBinding in the responsive view instead of ViewDataBinding bead. Maybe that helped to not find this bug before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants