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 ? :-)
Related
I have a custom component with an input property as follows:
export class MyComponent{
#Input() value:number;
}
So that I can plop one on a parent component:
<my-component [(value)]="someValueAtParentComponent"></my-component>
Note that I did not provide #Component decorator and the class for the parent component because I don't think those are relevant.
Now, things happen internally in MyComponent that can change the value of value.
From inside MyComponent's template, I display {{value}}, and it displays the correct value throughout its lifetime.
From the parent component's template, I display {{someValueAtParentComponent}}, but it doesn't update with MyComponent's value. I thought [(value)] will automatically do the job, but I guess not.
I don't want to create an #Output event on MyComponent for the parent component to handle the event where it would set someValueAtParentComponent explicitly.
I believe Angular wants to emit an event for a parent component to handle, but that seems very tedious. Is there something we can do in our own components so that we may use the syntactic sugar [(value)] instead of [value]="..." (onValueChanged)="onValueChangedHandler($event)"?
In gwt how to get a widget's default style(CSS Selector).For example, gwt button has style name "gwt-button" which is referenced in gwt theme css file.
How to got that programmatically.
Is there any,
DOM.getStyleAttribute();
to accomplish this. GWT experts please help.
In your example of button (or any object that is a child of UIObject) can call getStyleName()
UIObject documentation
String com.google.gwt.user.client.ui.UIObject.getStyleName()
Gets all of the object's style names, as a space-separated list. If you wish to retrieve only the primary style name, call getStylePrimaryName().
Now as to why you need this information is the real question. It is my guess that you want to change the styling of an object (add or remove). This would best be done by either of the following methods.
1) Supplying a custom resources file to the object that has your styling
2) creating a class that extends Composite and create a custom UIBinder class with all of your styles within it.
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.
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 3 question:
I trying here to avoid having to bind resources to all my components labels ( ie a button) and find a way to have this automated.
Problem:
It corrupts the layout in design mode to bind directly in the mxml label="{resourceManager.getString('myResources', 'submit')}" and makes the design view useless. but when declaring bindings elsewhere, in actionScript or via a bind tag, it is counter productive and prone to many errors and miss.
Proposition:
I would like to create my own button that automatically invoke resources to localize a button label. So the author puts "Submit" in the mxml description of my button, and when running it would take the value of the label ie "submit" and use resourceManager.getString('myResources', 'submit').
but I can't find the way to override the set label function, Is it possible if yes how? else how can I go about it?
Maybe I am missing an essential process here that would make the use of resources more elegant, as well as how to override such thing as a button's label.
Thanks for your advices.
Create a component called MyButton, extending Button. Then use this:
override public function set label(value:String):void {
super.label = resourceManager.getString('myResources', value) || value;
}
Assuming the resource manager returns "null" or "undefined" this will work, and will only replace the value if it exists in "myResources".
If you don't want to override every component you need to do this with, then you can add a FlexEvent.CREATION_COMPLETE event on every component. Then use a single generic function to do your label localization.