I have a bit of a problem, in that I have a tree:
<mx:Tree iconField="#icon" />
That's been fine for a while, but now I want parts of the tree to have their default icons. Now, for reasons I haven't figured out yet, the icon member of the source XML is ignored for branch nodes, and the default is used But for leaf nodes, I must have a valid icon member, or I get an exception. icon="" doesn't work.
Taking a look under the hood, I ran:
trace('The default tree icon: ' + tree.itemToIcon(tree.selectedItem).toString());
which revealed the default to be:
class _TreeStyle__embed_css_Assets_swf_TreeNodeIcon_770392128
which is way too magic string. No thanks. I didn't even try assign that to icon.
Rather than do a screen cap, Gimp edit, and then make it into a custom icon, how do I simply reference the default icon that the platform provides?
Flex 3.5 SDK here.
I think you do over think & with that over complicate everything!
I have not worked with this a long time, but maybe this still could help you a little.From memory I had more complex once as well but have not looked at any of it quiet awhile! One Link of many I used with Tree setup
gallery icon="iconSymbol0AG"
gallery label=" AR - ARGENTINA" src="com/assets/images/countriesFlagsRoundLarge/ar.png"
gallery label=" Mauricio Photography" src="com/assets/images/PageOne/PhotographyBlogs/BlankArtists/AR/TheMauricioBlog.swf"
file label=" Web Site" icon="iconSymbolAR" src="com/assets/images/PageOne/PhotographyBlogs/WebSites/AR/TheCollazosBlog.swf"
gallery
Following Amy's suggestion, I tried:
public var m_icoDefaultLeaf:Class;
private static var m_oDummyTree:Tree;
private static var m_xmlDummy:XML;
...
m_oDummyTree = new Tree;
m_xmlDummy = <dummynode />;
m_oDummyTree.dataProvider = m_xmlDummy;
m_oDummyTree.addEventListener(FlexEvent.CREATION_COMPLETE,
function (evt:FlexEvent):void {
m_icoDefaultLeaf = m_oDummyTree.itemToIcon(m_xmlDummy);
removeChild(m_oDummyTree);
m_oDummyTree = null;
m_xmlDummy = null;
}
);
addChild(m_oDummyTree);
Then I just used icon="m_icoDefaultLeaf" in the XML for the leaves and amazingly, it worked!
Yes, it does have to be that complicated. I had to handle that event, and I had to add the tree as a child of something.
And another thing I tried, was to erase all that code and just use
public var m_icoDefaultLeaf:Class = null;
But that just made a blank icon, not a default.
Related
I am developing a custom attribute on aurelia to let user select from a list while typing in a textarea. For example, the usage will be something like this:
<textarea value.bind="description" placeholder="your description here" auto-complete></textarea>
and as you probably noticed, the auto-complete is the attribute. Now when I want to show the hints, I want to do this in a custom-element to keep it simple. So the attached method of the attribute will be something like this:
attached() {
this.containerElement = document.createElement('div');
this.containerElement.style.position = 'relative';
const ce = document.createElement('autocomplete-menu');
this.containerElement.appendChild(ce);
const ceView = this.templatingEngine.enhance(ce);
ceView.attached();
const currentParrent = this.element.parentElement;
currentParrent.replaceChild(this.containerElement, this.element);
this.containerElement.appendChild(this.element);
}
now it opens and shows the hint area successfully. The screen-shot:
The problem gets started when I want to communicate to the generated element from the attribute view-model. For example, I want to send a data to its view-model or bind some object to a bindable property of that. For this issue I have found these solutions:
https://discourse.aurelia.io/t/dynamically-add-custom-attribute-to-element/1400/6
https://ilikekillnerds.com/2016/01/enhancing-at-will-using-aurelias-templating-engine-enhance-api/
and also read the last part of this:
https://aurelia.io/docs/binding/how-it-works#abstract-syntax-tree
and figured out that, I have to introduce an object for the element's view-model as its bindingContext or overrideContext. So if I am right, I have tested the solutions below:
this.containerElement.appendChild(ce);
let vm = { test: 1 }
const ceView = this.templatingEngine.enhance({ element: ce, bindingContext: vm });
ceView.addBinding(vm);
ceView.attached();
and
this.containerElement.appendChild(ce);
let vm = { test: 1 }
const ceView = this.templatingEngine.enhance(ce);
ceView.bind(vm);
ceView.attached();
console.log(ceView);
but on the attached lifecycle-hook of the element, I have logged the view-model and noticed that the bindingContext properties are not present on this.
Now there are two questions:
What's the problem with the above solutions and how can I send this kind of data to an enhanced element?
Is there a way to do this with the known method of bindables? I mean defining a bindable property on the element view-model and bind to it after the enhance method is done. Instead of working with bindingContext and overrideContext?
Fortunately the problem has been solved. The solution was not that much complex but 1. it is very very useful for me (as I will describe next) 2. the lack of aurelia documentation made this simple issue hard to solve.
The problem was about I was misunderstanding the meanings of bindingContext and container. I was thinking that bindingContext will refer to view-model of the child element and I must point its container to the parent context (which is the attribute). But I found that I should point the bindingContext to the context of attribute. I still don't know enough about those two meanings but the solution is as simple and beautiful as the following sample:
this.containerElement = document.createElement('div');
this.containerElement.style.position = 'relative';
this.containerElement.style.display = 'flex';
this.containerElement.style.flexDirection = 'row-reverse';
this.ce = document.createElement('autocomplete-menu');
this.ce.setAttribute('filter.bind', 'filter');
this.ce.setAttribute('show.bind', 'showMentionPicker');
this.ce.setAttribute('parent-height', '${element.clientHeight}px');
this.ce.setAttribute('view-model.ref', 'mentionPickerViewModel');
this.ce.setAttribute('on-select.call', 'complete(mentionPickerViewModel.getRemainingOfHint())');
const ceView = this.templatingEngine.enhance({ element: this.ce, container: this.container });
ceView.bind(this);
ceView.attached();
this.containerElement.appendChild(this.ce);
const currentParrent = this.element.parentElement;
currentParrent.replaceChild(this.containerElement, this.element);
this.containerElement.appendChild(this.element);
and the bindings are referring to the attribute's this context which has the following properties:
filter = '';
showMentionPicker = false;
mentionPickerViewModel;
If the sample is not enough for your problem ask me for more information.
I am working on an application which has quite a bit of field-validation in it. The validation works great and I am 1000000% sure the validation message popups were appearing earlier. Now I did quite a bit of work and refactoring. One of the things I changed was the way I open up Popups/Dialog. In order to have these centered over the entire application instead of the opening component I refactored the way I open dialogs. I used the source of the Alert as a base for this but extended it quite a bit as I was having other issues (Focus Manager etc.) (I am just mentioning this as I am assuming that my missing popups are related to this).
Here comes the code responsible for opening popups in my application:
public function show(realParent:Sprite,
displayParent:Sprite = null,
closeHandler:Function = null,
moduleFactory:IFlexModuleFactory = null):Dialog {
// Get the parent ...
// If none is set, use the top-level-application.
if (!displayParent) {
var sm:ISystemManager = ISystemManager(FlexGlobals.topLevelApplication.systemManager);
// no types so no dependencies
var mp:Object = sm.getImplementation("mx.managers.IMarshallPlanSystemManager");
if (mp && mp.useSWFBridge())
displayParent = Sprite(sm.getSandboxRoot());
else
displayParent = Sprite(FlexGlobals.topLevelApplication);
}
// Register for close-events, making sure the pop-up is closed.
if (closeHandler != null) {
this.addEventListener(CloseEvent.CLOSE, closeHandler);
}
// Setting a module factory allows the correct embedded font to be found.
if (moduleFactory) {
this.moduleFactory = moduleFactory;
} else if (realParent is IFlexModule) {
this.moduleFactory = IFlexModule(realParent).moduleFactory;
} else {
if (realParent is IFlexModuleFactory) {
this.moduleFactory = IFlexModuleFactory(realParent);
} else {
this.moduleFactory = FlexGlobals.topLevelApplication.moduleFactory;
}
// also set document if parent isn't a UIComponent
if (!parent is UIComponent) {
this.document = FlexGlobals.topLevelApplication.document;
}
}
// Make the dialog center itself relative to the parent.
PopUpManager.addPopUp(this, displayParent, true);
PopUpManager.centerPopUp(this);
return this;
}
What could be responsible for the Validation popups not showing up any more? Where should I look?
Chris
Ok ... so I figgured this out by myself again. I coould bang my head at the wall for taking so long for finding it though.
If I use the Spart forms, the FormItems and Forms themselves can define error text areas in order to output error messages. So as soon as the FormItem posesses a skin part with the id "errorTextDisplay" the error messages go there. I was now expecting that if there was no such part, the old notifications would be used ... nope.
After about 2-3 Hours of messing around with the code of FormItem and it's skins, I noticed that the "contentGroup" explicitly defined an attribute to suppress error tooltyips by setting showErrorTip to false. Simply removing the "errorTextDisplay" from the skin and changing the showErrorTip to true made my popups appear nicely :-)
Hopefully this post might help someone with the same problems.
I have a quite large Flex application with a large set of views and I ceratain views I'd like to add shortcuts.
And i'm looking for something like:
<mx:Vbox>
<foo:Shortcut keys="ctrl+s" action="{bar();}"/>
....
</mx:VBox>
Is there any framwork or component already done that does something like this? I guess it should be too difficult to build? When building this I only want the shortcuts to be active when the view is visible. How do I detect this? What base class is best to inherit from when working with non visual components?
I don't know of any framework component that does that already, but the examples above should get you started if you try to build your own.
There's no need to inherit from any component for a non-visual component like the one you've described here (your "foo" class needs no parents.) There's nothing in the Flex framework you need to inherit from for this.
However you architect it, your foo class is going to have to take in and parse keyboard codes to listen for and accept one or more methods to call. All you have to do is figure out when to add and remove the event listeners that will call the passed-in methods.
To handle turning your keyboard events on and off based on visibility, just have your foo component bind to the "visible" property of it's parent and add/remove event listeners accordingly.
You might also consider having the listeners added when the component that foo is nested in is on the display list rather than just visible. To do this, simply added and remove your event listeners in one of the component lifecycle methods - probably commitProperties is the most appropriate.
I don't think this solution answer your question directly but anyway, to help solve your problem here is an example.
For instance, I've extended the TextArea component like so. This is the best I can do so far, it can definitely be improved upon. Like, I don't know how to make the cursor go to the end after the next shortcut is pressed.
public class TextArea extends mx.controls.TextArea
{
// the keysmap is an example dictionary holding keycodes
private var keysmap:*={
112 = "some text for F1"
,113 = "the text for F2!"
//etc, etc
}
public var handleKeyDown:Boolean =false;
public function TextArea(){
if(handleKeyDown ==true){
this.addEventListener(KeyboardEvent.KEY_DOWN,this.keydownHandler);
}
}
public function keydownHandler(e:KeyboardEvent):void{
if(e.keyCode >= 112 && e.keyCode <= 123){
e.currentTarget["text"] += String(keysmap[e.keyCode]) +" ";
}//focusManager.setFocus(this);
}
}
I can't give you a solution using MXML, however my first thought would involve a singleton static class with a Dictionary that contains a list of objects as its keys and dynamically created dictionaries as the value pairing that contain keys denoting the desired key press with a function reference as the value.
So, say you had a Sprite and you wanted to capture ctrl+s for save when focus is on that object, I would get the instance of that Singleton, and call a function such as registerKeyBinding passing in the Sprite, the keyCode you want, and your pre-defined callback:
private var registeredObjects:Dictionary = new Dictionary(true);
public function registerKeyBinding(targetObject:Object, keyCode:int, callback:Function) {
if (registeredObjects[targetObject]) {
Dictionary(registeredObjects[targetObject])[keyCode] = callback;
}
else {
registeredObjects[targetObject] = new Dictionary();
Dictionary(registeredObjects[targetObject])[keyCode] = callback;
targetObject.addEventListener(KeyboardEvent.KEY_DOWN, keyDownListener);
}
}
private function keyDownListener(e:KeyboardEvent):void {
if (e.ctrlKey == true) {
//calls the function if that key exists.
Dictionary(registeredObjects[e.target])[e.keyCode];
}
}
Can't say I've tested this, but it was just the first thing that popped into my head. You could then setup functions to deregister and delete keys from the dictionaries, check states of the objects in addition to the keyCodes, remove old listeners, and delete entire dictionaries when there is no longer a need for them. Hopefully this is at least a tiny bit helpful.
I've reviewed all the documentation and Google results surrounding this and I think I have everything setup correctly. My problem is that the symbol is not appearing in my app. I have a MovieClip symbol that I've embedded to my Flex Component. I need to create a new Image control for each item from my dataProvider and assign this embedded symbol as the Image's source. I thought it was simple but apparently not. Here's a stub of the code:
[Embed(source="../assets/assetLib.swf", symbol="StarMC")]
private var StarClass:Class;
protected function rebuildChildren():void {
iterator.seek( CursorBookmark.FIRST );
while ( !iterator.afterLast ) {
child = new Image();
var asset:MovieClipAsset = new StarClass() as MovieClipAsset;
(child as Image).source = asset;
}
}
I know the child is being created because I can draw a shape and and that appears. Am I doing something wrong? Thank you!
You should be able to simply set child.source to StarClass:
child = new Image();
child.source = StarClass;
See the MovieClipAsset Language Reference for more details:
you rarely need to create MovieClipAsset instances yourself
because image-related properties and
styles can be set to an
image-producing class, and components
will create instances as necessary.
For example, to set the application
background to this animation, you can
simply write the following:
<mx:Application backgroundImage="{backgroundAnimationClass}"/>
We are creating a LinkButton programmatically and would like to set it's icon to an image retrieved from the remote server rather than something embedded within the SWF. The .icon property expects a Class but I can't figure out how to create one equivalent to an #Embed but from a dynamically generated URLRequest or URL String.
var myImage:Image = new Image();
myImage.source = "http://www.domain.com/img/1234.png";
myImage.width = 16;
myImage.height = 16;
myImage.scaleContent = true;
var myButton:LinkButton = new LinkButton();
myButton.label = "Some text"
// This is what I'm trying to figure out.
myButton.setStyle("icon", ???)
I'm probably missing something obvious - I've tried passing in the URL and myImage separately but both throw errors. Stepping into the setStyle() method shows that the code is expecting a Class - so what do I pass in place of the ???
I can't embed the image itself because it's dynamic - the URL is different each time the software runs.
Thanks for any assistance!
Why not just set the buttonMode of a mx:Image to true then add a click event?
<mx:Image source="{imageSource}" buttonMode="true" click="action()" />
I'm not sure its possible without using an embedded images with a linkButton
This might be worth a read
Edit... in AS3:
var img:Image = new Image();
img.source = "...";
img.buttonMode = true;
img.addEventListenever(MouseEvent.CLICK, funcName);
I think that instead of trying to set the style, you need to change the child object that holds the icon. You can access it by something like:
Var:Bitmap icon = myButton.getChildByName("upIcon") as Bitmap
It should be easy to replace the bitmapData in there with the one from a Loader.
If memory serves, you'll want to use button.setStyle('icon', img), where img is an image loaded via Loader class.
for laalto,
this may be too late of an answer but somebody might find it useful or as a starting point to a solution to your problem. Have you tried referencing your image icon as a class? I don't know if this will work for an image which is in a dynamic URL but this worked for me:
[Embed("assets/LinkButton.png")]
private const linkButtonIcon:Class;
Then in your code:
myButton.setStyle("icon", linkButtonIcon);
See this example here:
http://blog.flexexamples.com/2008/09/03/setting-the-icon-on-a-linkbutton-control-in-flex/
<mx:Button id="example" label="Example" icon="{IconUtility.getClass(example, 'http://www.exampledomain.com/image.jpg')}" />
http://blog.benstucki.net/?p=42