Flex data binding re-bind when data model not change, possible? - apache-flex

There is a common case that I bind a data model value to a GUI control, say, a TextInput. The data model is retrieve from backend.
If user change the value of the TextInput, then click refresh button to retrieve the data model from backend again, the GUI value will not change back. Re-binding not happen, Since the value of data model not changed, no propertyChanged event fired.
In this case, I must Programmatically set the model value to the GUI after data refreshing done.
I know bi-directional binding can solve this problem(when user change value on GUI, set the new value to data model immediately). But sometimes I cannot use bi-directional binding, for example, the data model is a int, but user input a non-int value, I cannot set the value to data model. So the value in data model do not change, when refresh data, rebinding still not happen.
This will make the data binding useless. How to resolve this?
I put pseudo-code here for now, I will put real code later:
1. retrieve a data model from server, via blazeds or something else.
2. bind the model to a TextInput on GUI.
3. user change the TextInput text.
4. User click a refresh button, triger retrieve the model value again.
5. Now since the model value do not change, no PropertyChanged event fired.
6. GUI value still is the user's input, not the value from the model.
I can clear the model value before set the velue back, make re-binding happen.(but sometimes you do not know how to clean the model value, take int for example, you may do not know the original value and happen set the same value). Or I can manually set the model value to GUI. But both are not good looking.
bi-directional binding not work since if user input a invalid value, I cannot set it to the model. Model value do not change, re-bind will not happen.

Bidirectional binding can be achieved in a variety of ways, not necessarily with the #-symbol. In your particular case you need to use the Binding-tag:
<fx:Binding source="parseInt(someNumberInput.text)"
destination="someModel.someNumberValue"/>
<s:TextInput id="someNumberInput" text="{someModel.someNumberValue}"/>
It's very important not to forget to parseInt() the numeric value.

You can dispatch binding events whenever you want. One way is to simply dispatch a PropertyChangeEvent on all properties you want to update, but another is to add your own binding event in addition to standard binding.
For instance, I think this will work:
[Bindable]
[Bindable (event="allChanged")]//make sure to dispatch this yourself when everything changes
public var myInt:int;
There is a possibility that the custom binding event might prevent Flex from generating the code in the background that does standard binding (I have never done the above, because if I am going to use custom events, I tend to not use the standard binding).
Flash Builder 4.5 has awesome code generation, so you can just convert a public variable to a getter and setter, and it will ask you if you want to fire a custom event for the property. If you check that box, it will write the code for you. Then you add the second metadata tag by hand.
The getter/setter method will perform better, because then each property will have its own event, rather than all of them firing on propertyChange and checking if the property is the correct one. But the other one is less verbose and more maintainable, if it works.

Use a relevant editor to edit a numeric value. Flex can not guess what you want to do.

Related

how to set QLineEdit to readonly if the data mapped by QDataWidgetMapper is readonly?

I have a tree model and use QDataWidgetMapper to map the model data to some widgets.
In the model, some of the data are flagged as read-only, so, what I would like to do is to let the mapped widget, say, a QLineEdit, be able to act upon this flag and set itself to readonly when the model data it points to is readonly.
Any help is appreciated!
Qt's QAbstractDataModel interface doesn't expose writability of a piece of data as an attribute: there's nothing you can read to know whether an item can be modified or not. One could think of some non-general hacks, such as attempting to write back the current value of the item to check if it can be changed. They are but hacks, e.g. a model fulfilling the contract mandated by Qt might return true from setData even on a read-only item if the new value equals old value.
If you're using a model that exposes the writability attribute, you'll need to derive from QDataWidgetMapper and implement that functionality yourself.

Default label value for org.eclipse.swt.widgets.Text control; prevent databinding from persisting value

Hy,
suppose a org.eclipse.swt.widgets.Text control connected via databinding to the model Person. The Text represents the surname of the person.
Now, everytime the model is changed, the value is updated, this is ok. Now I want the following:
If there is no value for surname in the model, i want the text-control to contain a hint label, s.a. "Insert surname" which is not supposed to be persisted!
I could create this behavior by adding a modifyListener to the textcontrol which sets the text if the length of setText is 0, I cannot prevent, however, the databinding then to persist "Insert surname"!
I tried extending Text (to override getText), which is not allowed, and wrapping Text into a "LabeledText" requires me to modify the DataBinding!
Anyone aware of a solution for this?
Thx
org.eclipse.swt.widgets.Text.setMessage() is a method exactly performing the requested task.
I think it is quite hard to simulate such behavior with standard SWT widgets. So, probably, you need to create a custom widget, with validation simulation inside. Your validator should return you a validation status, which can be used afterwards.

Easy way to tell if data is dirty

I am currently using databinding on a group of spark form elements and want to know if the data class I am bound to is dirty.
It might be nice if spark "Form" elements would trigger a change event that bubbled up to and was caught by a spark "Form". Then I could just add an event listener to the form. But I don't see something like that.
So besides comparing a copy of the original data class to the bound data class OR adding a change event to each form element and capturing that event, what's an easy way of knowing a class object has changed?
Make an extension of TextInput or whatever other input elements you'll have in your form then in your components creation complete register a listener for the change event, in the handler dispatch a bubbling event, then in your document that contains the form use your custom elements and add a listener via AS3 to the Form for the event you dispatched and stop it's propagation at that point.
Otherwise I think your second solution of change handler on each wouldn't be too bad. If you have a lot of elements in the form or it's dynamic you could write a function that steps through the form items of the form and checks their children then you just have to write a switch that deals with each class type (you can use http://www.actionscriptdeveloper.co.uk/getting-the-class-of-an-object-in-as3/on each of the child elements to determine what type it is, then if it's a TextInput or whatever register the appropriate event to call your commonly used function, just be sure it has a generic Event as it's parameter since all other Events will be sub-classes thereof).
So far as I know there is no easy way to listen for changes to the underlying data from the ArrayCollection or other wrapper ListCollectionView data structures. Part of the problem is the elements added a collection aren't required to implement any sort of interface to allow for listeners to be registered. That is, the data elements aren't necessarily event dispatchers, the only other way for this information to be communicated to the List would be if the data elements had a handle on all lists that contain that element and they mark something on the lists to indicate "dirty" when any property is set. These are all achievable within the constraints of the language but aren't provided out of the box as the usage for them is probably limited and could potentially unnecessarily bloat the cpu usage of the ListCollectionView in other cases.

Flex: DataGrid and the Command Pattern

I am using a command pattern, so any changes to object state need to happen within a command execution. A normal itemeditor in a DataGrid would just make its changes on the underlying bound object, but I need to intercept that change and make it use a command.
I'm pretty new to flex, so I'm looking for ideas of how to implement this. A basic example is that I have an object with a "date" field. In the datagrid I am using a flex "DateField" component as the itemeditor. When I select a new date, I don't want it to update the datasource, I want it to call a different method where I can access the newly selected value and pass it to a command to execute. Any tips would be greatly appreciated. Thanks in advance.
Use the itemEditBegin and/or itemEditEnd events on the DataGrid and build your command in the handler. This page has a few examples of capturing the edit operation with those events.
In my opinion, you're over-engineering this to hell, to the point that it becomes unusable. Why would you need a command to just change data on the fly? I've been doing Flex for 3 years and I yet to see it done this way. The only time commands are used is for receiving information from the server.
Either way, if you really want to implement it (against my recommendation), you would probably want to do event bubbling with a controller listening higher up the display list for the event, then from there trigger a command. From within the item renderer:
this.dispatchEvent(new Event('someEvent', true));
And then higher up the display list:
dataGrid.addEventListener('someEvent', someEventHandler);
And within the handler you can run the command.

Why should I create my child controls in CreateChildControls() on a CompositeControl?

Ok so the obvious answer is, because the flow of a composite control demands my childcontrols to be created at a certain point in time. I got a problem i think other people must have had as well.
My control is a composite "container/collection" control. It will be fed with an object and based on that objects data it will create a number of childcontrols. So my control will render a header (always) and x-number of, say TextBox controls (based on the object it was fed with).
I'm creating my header in CreateChildControls() obviously, but i can't possibly create my TextBoxes there as well, because i don't know if the object (to base the TextBoxes on) has been fed yet? I thought of exposing a property/method to set/fed the object through, but i'm not sure when it will be called.
So what do i do? I mean i can't possibly create the TextBoxes in CreateChildControls() or can I? I mean - when is CreateChildControls() called - i know i can call EnsureChildControls() (which i already do in a property to set the innerText of the header - since i need the header to be created before setting its innerText obviously).
How about this
var c = new MyContainerControl();
c.Header = "fun";
c.TextBoxObject = myTextBoxes;
That would raise an error (or at best not create any TextBox'es) if i put the building of the TextBoxes in CreateChildControls().
Would it be more sane to instead just store the Header in a member variable and thus not having to call EnsureChildControls() in the exposed method/property setting the Header innerText. I just don't like this aproach much, since it would be complicating things by adding extra logic to store temporarely and later having to figure out when to set it (probably in PreRender).
Also i guess i could make some kind of Databound control, ensuring the data be present at the time of calling .DataBind(). I really don't like this either since last i looked at creating databound controls it got very complicated.
This really should be an easy task to solve - I know I'm missing something somewhere...
what you're describing IS a databound control. And yes, it's somewhat complicated, but it's the proper design paradigm for this type of instance.
That said, had you considered utilizing the repeater control rather than trying to roll out your own composite which behaves in the exact same manner? Rather than passing it a random object, pass it a collection or an iList with the number of text areas you're wanting.

Resources