What is Flex good practice to change another component's state? - apache-flex

I currently use: Flexglobals.toplevelapplication.component1.compnent2.currentState = 'something';
is there a better way of doing do? Can I bind the state of a components to variable in my model?

Ideally, components should be self contained little pieces of your application. One component shouldn't have any effect (including changing the state) on any component, except possibly it's children.
The "Encapsulation proper" approach to change the state of an unrelated component is to dispatch an event from the component. The component's parent (or some component higher up in the hierarchy chain) is going to execute an event listener and change that state of the appropriate component, by either calling a method on the component that needs a state change or changing a property on the component that needs a state change.
If you have a complicated hierarchy, this approach can lead to a lot of tedium, creating events up the chain, and creating properties / methods down the chain in order to preserve encapsulation. Some frameworks, such as Cairngorm introduce a global singleton to avoid this tedium. In Cairngorm that singleton is the ModelLocator.
The ModeLlocator is, basically, a global dependency in your application. You can give any component access to it, and through the use of binding if a property is changed in one place, it an be automatically updated elsewhere. To change the state using binding, use an approach like this:
In the ModelLocator, create a variable to hold the state for the view in question:
[Bindable]
public var comp1State : String = 'defaultState';
In comp1 do something like this:
<mx:Container currentState="{model.comp1State}" otherComponentProperties>
<!-- other component code including defining the states -->
</mx:Container>
Then in the component where you want to change the state, do something like this:
model.comp1State = 'nextState'
Binding will take it from here. I wouldn't use his approach lightly though. It depends on the component you're trying to create and how much you car about reuse. The most common way I've seen this implemented is not with states, but with the selectedIndex in a ViewStack. But, the approach would be the same.

Yes. I usually bind the sate of my component to a property in my model.
As long as you are making the properties on your model bindable you should be able to bind
directly to you model in your view. You sitl have to set the state in you model. Id look into using a framework like [swiz][http://swizframework.org/] or or mate.

Related

Angular2 Change Detection with Zones

I am wondering if all asynchronous events and callbacks can be traced back to a specific source component by wrapping all component logic (including logic of non-component directives inside component) in a zone, then only that source component needs to be checked for changes along with any child components with changed inputs from the source component, assuming all changes are following the uni-directional flow.
Is this understanding sound?
Is this change detection strategy available in Angular2?
Why is Angular2 detecting changes on all the components after any asynchronous (XHR) event?
One whole Angular application runs in a single zone. Angular uses the zone to patch async APIs and uses notifications from these patched APIs to run change detection every time some async event happened.
The uni-directional flow is for [prop]="value" bindings that works only from parent to child.
Angular runs change detection from root to leafs.
If ChangeDetectionStrategy.OnPush is configured for a component, change detection skips these components (and their descendants) until some binding (inputs) have changed.
There are other strategies to optimize CD.
For example observables and promises, that actively notify about changes and don't need change detection.
Immutable objects which are guaranteed to not change their propery values.
Update
Angular doesn't know what values an event handler has changed. Properties of a component, of a global service, of object references that were passed around, .... It just assumes that when an event handler was called that probably something has changed and then runs a complete change detection cycle to propagate all bindings from parent to child.
Child do parent bindings are events anyway and therefore aren't updated during change detection.
... by wrapping all component logic (including logic of non-component directives inside component) in a zone, then only that source component needs to be checked for changes along with any child components with changed inputs from the source component, assuming all changes are following the uni-directional flow. Is this understanding sound?
When an template-bound event fires – e.g., (click)="doSomething()" – the doSomething() method is free to alter any component or application data. Template statements, such as our doSomething() event handler, are not bound by the unidirectional flow rule, as per the Angular docs:
Responding to events is the other side of Angular's "unidirectional data flow". We're free to change anything, anywhere, during this turn of the event loop.
This is why, by default, Angular's change detection has to check every template binding in every component after an event fires. (Well, after an event within the Angular zone fires.) Angular doesn't know what might have changed... it has to discover what has changed.
The unidirectional flow rule applies to template expressions such as {{some expression}} or [childInputProperty]="parent expression" or if you implement an input property setter method: #Input() set childInputProperty(variableName:type) { ... }.
Is this change detection strategy available in Angular2?
No, because it would severely limit what an event handler could do. Dirty-checking every template binding may not be the most efficient way to detect changes, but it makes it much easier for us to write our event handlers (i.e., to write our applications).
Why is Angular2 detecting changes on all the components after any asynchronous (XHR) event?
Angular doesn't want to limit what we can do in our event handlers. An event handler bound in ComponentA's template can change data that is local to ComponentA, but it can also change data that is in a service (and hence it can change data that is visible to other components), and it can change data in other components, e.g., by calling public APIs/methods on other components.

Is there a reliable way to "refresh" a component?

By "refresh" I am completely disposing it and then introducing it again in the application (without closing the application itself - that is). Other than than I think the question is self-explanatory.
Example:
Say I have a component named myComponent. I add that component to the application using MXMl in the standard way <components:myComponent id="myID" />. Say that when a user clicks a button (the button may be in another state), the component with id myID should be garbage-collected and a new instance of it added to the application.
How do I go about doing that? If there are multiple solutions which one is the optimal performance-wise?
I am new to Flash and Flex so excuse me if any incorrect terminology were used.
Remove all the event listeners from the old component; whatever they are using the removeEventListener method:
myButton.removeEventListener(someEvent, someEventHandlerMethod);
Then all variables that refer to the component should be set to null. If created in an MXML file, like this:
<s:Button id="myButton" />
Then all you have to do is set that value to null:
myButton = null;
Once there are no references to the component, it can safely become eligible for garbage collection.
If you want to re-created, then just re-created it. You'll have to re-create it in ActionScript, but the code isn't hard. Conceptually something like this:
myButton = new myButton();
myButton.properties = propertyValues;
myButton.addEventListener(someEvent, someEventHandlerMethod);
parentContainer.addChildAt(myButton, whateverPositionYouWantToADdTheComponentAt);
I'm not sure I see the benefit of doing this. I suspect it'll be much more efficient to tweak the existing button instance in the way you need to as opposed to destroying it and trying to replace it with the exact same thing.

Exposing properties to a Spark Skin class

I am having trouble wrapping my head around the spark skin class in relation to it's host component. Basically, from what I've seen with most every skin that comes in the Flex 4 framework they don't directly expose the properties that are dynamically being set in the host component. Instead, they define states that get exposed to the skin class to define when a component should look different. This is all fine and dandy when you have a very simple component with a standard set of states, but when you have twenty different properties (hypothetically) to set in your host component that should change how the skin looks it could get very complicated very fast.
The way that I've seen that they have used to get around this is by overriding the commitproperties and invalidate functions in the skin class, grabbing the values for the properties they want from there, and then setting them to a locally instantiated variable inside the skin class. This is fine, but I feel like that is just a patch workaround to it which makes things a lot more complicated than it needs to be.
HERE'S MY QUESTION:
Is there any way to directly expose a bindable property from the host component class so when you define your skin class it is directly ready to be read from? Let's say you have custom button with a boolean property of 'selected'. In the skin class, you want to add in a get and set function for the property 'selected' so you can perform some action upon your skin whenever it's set. How do you tell the skin class that this is an available property for you to work with from the host component?
This question exists at a very theoretical level. I'm not clear what you're trying to accomplish, nor what sort of properties you're setting on your component class. I suspect, there is an architecture problem if you have 20 properties and each one needs to correlate to a different skin states somehow.
However, I can try to answer your specific questions.
Is there any way to directly expose a bindable property from the
host component class so when you define your skin class it is directly
ready to be read from?
When building Flex MobileSkins, they recommend creating a property named hostComponent which gives the skin class a reference to the component class. MXML skins already have a similar property. If you're using a custom skin, this property is created automatically using the HostComponent metadata. Therefore from the skin class you can access properties on the component class using the hostComponent property.
Let's say you have custom button with a boolean property of
'selected'. In the skin class, you want to add in a get and set
function for the property 'selected' so you can perform some action
upon your skin whenever it's set.
I'm not envisioning the situation where you would want to do this. Generally you would not define any properties on the skin class which you intend to explicitly change on the instance of the skin class.
You could dispatch an event from the component class when the property changes. [This is very common]. Then listen for that event in the skin class using the hostComponent property and change things there.
There is also a way to access the skin class instance from within the component class. So you could change properties directly on the skin class using the skin property.
I wouldn't follow either approach without thinking it through. Ideally the component class and skin class should be encapsulated from each other; and each approach would provide dependencies.
When you affect a skin to a component, you can use metatags to store a reference to the skin part you actually use :
[SkinPart(required="false")]
public var resizeHandle:UIComponent;
Then, when overriding the partAdded and partRemoved methods, you will be able to set or unset whatever you want in these skin parts, from the basic properties to event listeners.
override protected function partAdded( partName:String, instance:Object):void
{
super.partAdded(partName, instance);
if (instance == resizeHandle) {
resizeHandle.addEventListener(MouseEvent.MOUSE_DOWN, resizeHandle_mouseDownHandler);
}
}
override protected function partRemoved(partName:String, instance:Object):void
{
if (instance == resizeHandle) {
resizeHandle.removeEventListener(MouseEvent.MOUSE_DOWN, esizeHandle_mouseDownHandler);
}
super.partRemoved(partName, instance);
}
Furthermore, since you have stored a reference to your skin parts, you can still access it whenever you want in your host component and update it. Am I clear ? :-)

call flex initComplete at a specific time

Below is the overriden on complete function for a preloader in Flex.
private function initComplete(e:Event):void
{
//dispatchEvent(new Event(Event.COMPLETE));
cp.status.text="Configuring... Please Wait";
}
What I want to do is when the app has finsihed loading I want to change the preloaders text to "configuring".
Then I want to go and do a bunch of setup stuff in my code.
Once I've done all the setup I wanted how can I get the Preloader to dispatch its Event.complete from else where in my code?
I tried Application.application.preloader but it comes up null.
So I guess my question really is how to access a preloader from anywhere in my application.
Would a better approach be to have all setup classes as members of my preloader class?
One thing that might help is a Model-View-Controller pattern. Are you using a framework for your application like Mate, Swiz, or Cairngorm?
If you were using Mate, for example, you could do something like this:
Create an AppStateManager class with a property (e.g. applicationState)
Create an EventMap with an EventHandler for the FlexEvent.INITIALIZE event. In this handler, set the AppStateManager.applicationState to something like "CONFIGURING"
Your EventMap has an injector that injects the applicationState property into a view. The injector listens for changes to this property and updates the view. In this case it might just be injected into your main view.
In the main view, you have a public bindable property also called applicationState that gets injected by Mate.
In the setter for this property, you can have an if/then or a switch that does different tasks depending on the state. For example, if applicationState == "COMPLETE", then this.preloader.dispatchEvent(Event.COMPLETE) or something like that.
The details are pseudo-sketched out but the idea is to use Flex's bindings to notify view components when changes have been made, and to have shared objects that maintain state. Not sure if that's what you're looking for...
The component LifeCycle does specific stuff in a specific order, and the near final element is to make the component visible.
It sounds to me like you want to defer this setting of visible to true to do other stuff. But, I imaging if you were making use of the component LifeCycle this would be a non-issue.
What sort of app init stuff do you need to do?

Flex component access other component

I have 2 components for example (editor.mxml using mx:windows), when I click an edit button, I want to get the current value from the other component's datafield? (datagrid.mxml using mx:window)
I do know how to access the main MXML's datagrid by parentDocument or Application.application method, but stumped block if I want to access other way as mentioned above. Keep the code as simple as possible.
You could either do dependency injection, that is, give component A a reference to component B so that they can communicate directly (example of tighter coupling,) or have both components communicate through a common mediator using events (example of more loose coupling.)
Both of those options would be implemented wherever it is that you're creating those components (A and B in this example) and adding them to the display list.
This might be more complicated than it deserves, and it smacks of Pattern-Fever, but you could use a mediator class that listens for the CLICK event from the button and knows enough about the other component to query its property. It could even transmit that data using a custom event, which the button listens for.
While this involves three classes instead of two, it often turns out to be easier to have two components that focus on looking good and one that worries about coordination.
Cheers
Try this:
FlexGlobals.topLevelApplication
This points Your root. From the root You can grab every element You want.
You can also add an id to the custom component like this,
<custom:Editor id="myCustomComponent">
</Editor:AddressForm>
and
access your datagrid's value like this,
var data:ArrayCollection = myCustomComponent.DatagridID.dataProvider;

Resources