I have some confusion on what we call "binding" as ?
Is it :
1) Change in [Bindable] Model which leads to an automatic change in View ( bound to that model )
OR
2) Change in View and then an automatic change in the [Bindable] Model ( the View is bound with )
Thanks
The typical use of data binding in Flex is to bind some model object to a view object (#1).
In Flex 4, two way binding was introduced. This does both #1 and #2. That is any change made in the model is reflected in the view. But also, any change made to the value in the view updates the model value.
To use two way binding, add the # symbol to the binding expression in the view:
<s:TextInput text="#{model.someValue}" />
Note that when you make something Bindable, the mxml compiler generates a setter method for your Bindable variable, which dispatches an event anytime the variable changes. The mxml compiler then adds event listeners for this event to the view objects that are bound to the variable. So technically, any object (whether it is a view, model, controller, or something else) can be bound to a variable, as long as it can receive the event.
Related
I have the following code:
onClick="location.href='#Url.Action("StampPdf", "EditPdf", new {pView = currentPdfView})'" />
which when clicked calls a method called StampPdf(PdfView pView) on a controller called EditPdfController. The controller method is called, with the variable pView, but instead pView has all its properties equal to null. It's as if the PdfView class has been instantiated afresh. Within my cshtml razor file, currentPdfView is instantiated and has all properties with values assigned to them, but in the controller the properties are null.
This user here had the same issue, but there is no followup on whether it was resolved or not.
Is there something I need to do to make this work?
It doesn't know how to serialize the model into a query string :)
You need to break your model into multiple properties with simple values, or use a form POST to submit them as a model.
You can also serialize the model into e.g. JSON and pass it as a string.
(This may be too localized an issue but I will try to generalize it)
Question: If a property setteris marked as Bindable, will it not get called if the new value is the same as the old value?
I am seeing the above behavior in a legacy project I have inherited: the setter is not getting called. If I don't declare the setter as Bindable then the setter is called no matter what the new value is.
Can anyone confirm that the above is the way things are designed to work with Binding?
This project uses Binding all over the place and there are no comments in the code so it is hard to tell what the dependencies are and which parts of the code depend on particular bindings. I'm trying to avoid making major changes but I also don't want to waste time trying to work around something which should be refactored.
The property is bound:
[Bindable]
protected var _source:AolMediaFile;
The setter is bound:
[Bindable]
public function set source(file:AolMediaFile):void{
_source = file;
// do some stuff with file
}
The setter should only get called if the event source is [Bindable]. Data binding is basically a chain of events dispatched from source to target in a variety of scenarios. When you declare your property or setter as [Bindable], that will basically change nothing in the behaviour in terms of side effects, as events are dispatched and listeners are generated. For example:
<your:Component source="{any.source.aolMediaFile}" />
Only when any, source and aolMediaFile are declared [Bindable], source would be invoked. Having source declared as a [Bindable] property is only interesting, if a second component would be depending on your component's state
<your:Component id="yourComponent" source="{any.source.aolMediaFile}" />
<s:TextField text="{yourComponent.source}" />
If you would want to bind to a property of AolMediaFile, then the class or the specific property has to be be [Bindable] as well.
Usually the compiler prints warnings, if bindings can't be generated:
warning: unable to bind to property 'source' on class 'Object'
(class is not an IEventDispatcher)
So check the source object, which are the source's host object's dependency and the compiler warnings.
So digging around here a bit more I came across this question: Flex: Help me understand data Binding on getters and setters which describes the code generated by declaring a setter or getter Bindable
So apparently in the generated code there is a check to see if the value is different:
public function set name(value:String)
{
if (_name == value)
return;
_name = value;
dispatchEvent(new Event("nameChanged"));
}
When moving to Flash CC, the following problem occurred in my flash project.
Consider this class definition:
public class Test extends MovieClip {
[Inspectable(type="String", defaultValue="val")]
public var param :String;
public function Test() {
trace(param);
}
}
I have a symbol "Symbol 1" which (via the Library panels Properties) is linked to the class Test and (via the Component Definition) is also set to the class Test, and this dialog box displays the parameter "param" with value "val". I have an instance of Symbol 1 on the Scene.
The parameter "param" appears in the properties of this instance, with the value "val", as expected.
The only problem is that during runtime, the value of the parameter "param" is equal to null, as confirmed during the execution of the classes constructor, which outputs "null".
Does anyone know why this is happening?
The Inspectable tag is needed by Flash to populate the component properties panel in order to set values manually. These parameters, both default and user input, are not available at instantiation, but they are available only at the following frame.
In order to have default values at instantiation you must set the default value also on the variable itself.
[Inspectable(type="String", defaultValue="val")]
public var param :String = "val";
Also, before you go crazy accessing values inserted with property inspector, remember to add an enter frame event before accessing those values.
What I usually do in my components:
1 - Populate default in both inspectable and variable
2 - On instantiation, if a parameters object is received, then I know it's instantiated in code and values are inside the parameters object
3 - If a parameters object is not received, then instantiation is done on timeline visually, therefore I access properties on next frame
Ok, so this might be me being pendantic but I need to know the best way to do something:
(This is psudocode, not actual code. Actual code is huge)
I basically have in my package a class that goes like this:
internal class charsys extends DisplayObject {
Bunch of Variables
a few functions
}
I another class which I intend to add to the timeline I want to create a function like this:
public class charlist {
var list:Array = new Array();
var clock:Timer = new Timer(6000);
var temp:charsys;
function addObj(MC:DisplayObject, otherprops:int) {
temp=MC;
temp.props = otherprops;
list.push(temp)
}
function moveabout(e: event) {
stuff to move the items in list
}
function charlist() {
stuff to initialize the timers and handle them.
}
}
So the question is, is my method of populating this array a valid method of doing it, is there an easier way, can they inherit like this and do I even need to pass the objects like I am?
(Still writing the package, don't know if it works at all)
Yes, you can pass an object into a function, but you should be careful of what you are planning to do with that object inside that function. Say, if you are planning to pass only charsys objects, you write the function header as such:
function addObj(MC:charsys, otherprops:int) {
Note, the type is directly put into the function header. This way Flash compiler will be able to do many things.
First, it will query the function body for whether it refers to valid properties of a passed instance. Say, your charsys object does not have a props property, but has a prop property, this typing error will be immediately caught and reported. Also if that props is, for example, an int, and you are trying to assign a String value to it, you will again be notified.
Second, wherever you use that function, Flash compiler will statically check if an instance of correct type charsys is passed into the function, so if there is no charsys or its subclass, a compilation error is thrown.
And third, this helps YOU to learn how to provide correct types for functions, and not rely on dynamic classes like MovieClip, which can have a property of nearly any name assigned to anything, and this property's existence is not checked at compile time, possibly introducing nasty bugs with NaNs appearing from nowhere, or some elements not being displayed, etc.
About common usage of such methods - they can indeed be used to create/manage a group of similar objects of one class, to the extent of altering every possible property of them based on their corresponding values. While default values for properties are occasionally needed, these functions can be used to slightly (or not so slightly) alter them based on extra information. For example, I have a function that generates a ready-to-place TextField object, complete with formatting and altered default settings (multiline=true etc), which is then aligned and placed as I need it to be. You cannot alter default values in the TextField class, so you can use such a function to tailor a new text field object to your needs.
Hope this helps.
This would work, I think I would assign values to the properties of the charsys object before passing it into the add method though, rather than passing the properties and having a different class do the property assignment. If you have some common properties they could either have defaults in charsys class definition or you could set literals in the addObj method.
Say, I have a datagrid with checkboxes, and each time a checkbox is marked I store the object in the data property of flex ResultEvent
public class MyItemRenderer extends ItemRenderer{
public static var CLICK:String = "CheckBoxClick";
protected function itemRendererClickListener(data:Object):void{
dispatchEvent(new ResultEvent(MyItemRenderer.CLICK, data))
}
}
I handle the result here.
protected function checkbox_clicked(event:ResultEvent):void{
//Here I do everything I want with the data.
Alert.show(event.result.toString());
}
This is what I've been using for months, but I never wondererd if this was a bad practice.
Or let alone bad practice, what is the optimal way to do this?
it's not really 'bad'. But it does create an additional reference to an object that can potentially keep that object in memory longer (or indefinitely if not managed well).
Generally speaking, you should only store data related to the event itself in the event instance. You can use the event.target and event.currentTarget properties to reference back to the object that dispatched the event and get data that way.
In your case, your event is a check box state change. The event itself (being checked) doesn't need any data associated with it besides the item being checked (which you can get with 'target' or 'currentTarget'). So it would be more appropriate in my opinion to do the following:
Alert.show(MyItemRenderer(event.currentTarget).data.toString());
This keeps your events more reusable
Best practice for Events with data is to use a custom event (see http://cookbooks.adobe.com/post_AS3__Creating_and_dispatching_Custom_Events-17609.html) for explanation
btw, another 'best practice' is to avoid the generic Object class in your code - instead, create a value object class