Can't declare custom event in custom component in Flash Builder - events

I am trying to create a datagrid component and want it to dispatch an event to the main application when datagrid is created. However, I got errors saying
"Type was not found or was not a compile-time constant:dataGridComp"
"Call to a posibly undefined methoud dataGridComp"
my component
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx">
<fx:Metadata> //declare my event
[Event(name="dataGridComp", type="flash.events.Event")]
</fx:Metadata>
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function dataGrid_creationCompleteHandler(event:FlexEvent):void
{
// TODO Auto-generated method stub
var e:dataGridComp = new dataGridComp("dataGridComp"); //problem here
dispatchEvent(e); //want to dispatch my event object when the datagrid is created
}
]]>
</fx:Script>
<s:DataGrid id="dataGrid" editable="true" x="51" y="34" width="734" height="153"
creationComplete="dataGrid_creationCompleteHandler(event)" requestedRowCount="4">
........
..........
</s:DataGrid>
</s:Group>
Any idea how to solve this? I appreciate any help. Thanks a lot.

A couple of things that you can change/consider:
1) To dispatch your custom event, you need to use the Event class, or create a custom class that extends Event, so you can dispatch a real Event object. In your case, w/ just a custom event type, use the Event class like this:
dispatchEvent( new Event("dataGridComp") );
2) The creationComplete event you are using, is dispatched before the component is added to the stage. Events dispatched by something that is not on the display list won't necessarily be heard by your main application.

Related

Apache Royale Jewel TabBar / SectionContent onShow or valueCommit Event like in sdk 0.9.8?

I have something similar to this :
<j:states>
<js:State name="login"/>
<js:State name="loggued"/>
</j:states>
...
<j:Group includeIn="loggued" width="100%" height="100%">
<j:TabBar localId="tabbar" width="100%" change="ev_tab_change(event)">
<j:beads>
<js:ConstantBinding sourcePropertyName="tabBarDataSample" destinationPropertyName="dataProvider"/>
<j:AssignTabContent selectedContentProperty="content">
<j:content>
<j:TabBarContent width="100%" y="80" >
<royale:TB_One/>
<royale:TB_Two/>
</j:TabBarContent>
</j:content>
</j:AssignTabContent>
</j:beads>
</j:TabBar>
</j:Group>
<royale:TB_One/> and <royale:TB_Two/> are <j:SectionContent>
I need to trigger an event when TB_One or TB_Two is showing or tabbar selectedIndex was programmatically changed.
I have tried change event on TabBar, but this is not triggered when changing with selectedIndex
Is there an onShow event or valueCommit ?
(for now tabbar.dispatchEvent(new Event("change")); do the trick when programmatically change selectedIndex)
Used sdk is 0.9.8
Regards
you can do the following:
<!-- The TabBar -->
<j:TabBar initComplete="tabbarInitialized(event)"/>
...
<!-- Buttons to change the content programatically -->
<j:Button click="selectContentByIndex(0)" text="0"/>
<j:Button click="selectContentByIndex(1)" text="1"/>
...
<!-- as3 code in script -->
<fx:Script>
<![CDATA[
import org.apache.royale.events.Event;
// when tabbar is initialized make tabbar listen for internal event "selectionChanged"
// this is the event to use for programmatic changes
public function tabbarInitialized(event:Event):void
{
event.target.addEventListener("selectionChanged", contentChanged);
}
// The button change the selection programmatically
public function selectContentByIndex(index:int):void
{
tabbar.selectedIndex = index;
}
// Here run the code you want. I simply trace the new tabbat selected index and the item
// but you can calculate the content and operate over tha visual component
public function contentChanged(event:Event):void
{
trace("index:", tabbar.selectedIndex, "content:", tabbar.selectedItem);
}
]]>
</fx:Script>

Nativescript (tap) event on a custom Angular component

I'm trying to bind a (tap) event on a custom Angular component in nativescript.
I created a custom component called 'ns-custom' and tried to bind the (tap) event to it. But it doesn't work.
In the custom component I'm doing this:
<StackLayout>
<Label text="Title"></Label>
<Label text="some text"></Label>
</StackLayout>
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'ns-custom',
templateUrl: './custom.component.html',
styleUrls: ['./custom.component.css']
})
export class CustomComponent{
constructor() { }
}
And in the parent element I'm doing this:
<ns-custom (tap)="onCustomComponentClick()"></ns-custom>
onCustomComponentClick() {
console.log('custom-component was tapped');
}
I expect the (tap) event to fire when I tap the custom component, but it does not. I built the same structure in pure Angular, and the (click) event does fire if put to a custom component.
I tried to propogate the (tap) event from the custom component like below, but then it fired twice (as expected because the tap event would propogate up to the parent component if I don't use event.stopPropagation()):
<StackLayout (tap)="emitTap()">
<Label text="Title"></Label>
<Label text="some text"></Label>
</StackLayout>
#Component({
selector: 'ns-custom',
templateUrl: './custom.component.html',
styleUrls: ['./custom.component.css']
})
export class CustomComponent{
#Output() tap = new EventEmitter();
emitTap() {
this.tap.emit();
}
}
And then catch the event on the parent component:
<ns-custom (tap)="onCustomComponentClick()"></ns-custom>
onCustomComponentClick() {
console.log('custom-component was tapped');
}
But now the tap event fires twice. I can solve it by changing the EventEmitter name to something other than 'tap' (for ex. #Output() childTapped = new EventEmitter(); and <ns-custom (childTapped)="onCustomComponentClick()"></ns-custom>) or pass the $event object on tap and then use event.stopPropagation(), but this is not elegant at all.
Any idea how to solve this simple problem in an elegant way?
This is basically answered by #mick-morely in the comments but I thought I would write up a more descriptive example and why I think it is a useful way of doing it.
You basically need to create a custom event for your custom component. While it seems tedious not to be able to re-use the tap event, it can actually improve your code quality, making it more descriptive.
So if I have a custom HoleComponent describing a "Hole", it can look like this:
Hole Template
<GridLayout rows="*" columns="*" (tap)="emitTap()">
<Label row="0" text="A very deep hole"></Label>
</GridLayout>
Hole Code
#Output() holeTap = new EventEmitter();
emitTap() {
this.holeTap.emit();
}
This Hole component can then be used by a parent like this:
Parent template
<Hole (holeTap)="onHoleTap()"></Hole>
Making the event explicitly named actually helps to make the code more readable imho. It also forces the developer to think more about the Domain they are working with which helps in conforming to the ubiquitous language if working with DDD is your thing.

Update the view although the model hasn't changed

My app updates the view in response to events dispatched by the model. But what if the model hasn't changed, but I still need to update the view. For example, I've closed and reopened a pop-up. The data to be displayed hasn't changed but the pop-up mediator and the view have to be recreated. My current solution is to force initialization in the mediator's onRegister() method like this:
// Inside of PopUpMediator.as
[Inject]
public var popUpModel:IPopUpModel;
[Inject]
public var popUpView:PopUpView;
override public function onRegister()
{
// Force initialization if the model hasn't changed
popUpView.foo = popUpModel.foo;
// Event based initialization
addContextListener(PopUpModelEvent_foo.CHANGE, foo_changeHandler);
}
Injecting models into mediators isn't a good idea, so I'm wondering What is the best way to init the view when its model hasn't changed?
Well,
I supose you have View1 where you have popup button.
View2 is your popus.
so when View1 button is clicked, you dispatch an event from main mediator that goes to popupCommand where you add popup to contextView, or where you remove it.
You can also have one state inside a model, that will say popupVisible and when you change that property you dispatch a event that is listened in the main mediator and that adds or removes the popup. In that case command would alter the model property instead of adding popup directly to contextView.
Third way is to add popup manually inside the view, and since the stage is being listened to by robotlegs, popup will be mediated automatically.
I've decided to add an event called PopUpViewInitEvent. A command will check if the model was updated while the pop-up was closed. If not it will reinitialize the view by dispatching the PopUpViewInitEvent. The event will contain all the data required to initialize the view. This way I won't have to inject models into my mediator.
[Inject]
public var popUpView:PopUpView;
override public function onRegister()
{
// Batch initialization
addContextListener(PopUpViewInitEvent.INIT, batchInit);
// Gradual initialization
addContextListener(PopUpModelEvent_foo.CHANGE, foo_changeHandler);
addContextListener(PopUpModelEvent_bar.CHANGE, bar_changeHandler);
}
protected function batchInit(event:PopUpViewInitEvent)
{
popUpView.foo = event.foo;
popUpView.bar = event.bar;
}

Flex Mate - PropertyInjector fired twice when mapped between Manager and View

My application uses Flex 4 and Mate framework 0.9.1. I'm facing an issue with the PropertyInjector being fired twice when there's a mapping between a manager and a view.
I have not shared the original code here, but it looks similar to the following:
Based on an event, a property (someData) in MyManager is updated. A property injector updates this new value in a target view (MyView). The issue is - when onDataChanged is invoked and the property someData is updated, the method "set someData" in the view is fired twice. I know that the view is instantiated only once because I have debugged the init and creationComplete events. The source property in MyManager is also updated only once as per the trace.
This would indicate that the property injector is fired twice. Would anyone know under what conditions this can happen? Any pointers would be appreciated!
MyEventMap.mxml
<EventHandlers type="{DataChangedEvent.GET}" debug="true">
<MethodInvoker generator="{MyManager}" method="onDataChanged"
arguments="{[event.x,event.y,event.name]}">
</MethodInvoker>
</EventHandlers>
<Injectors target="{MyView}" debug="true">
<PropertyInjector targetKey="someData" source="{MyManager}"
sourceKey="someData">
</PropertyInjector>
</Injectors>
DataHolder.as
public class DataHolder
{
public function DataHolder()
{
}
public var x:Number;
public var y:Number;
public var name:String;
}
MyManager.as
public class MyManager extends EventDispatcher
{
....
[Bindable] public var someData:DataHolder;
public function onDataChanged(x:Number,y:Number,name:String):void{
trace("dataChanged");
var temp:DataHolder = new DataHolder();
temp.name=name;
temp.x=x;
temp.y=y;
someData = temp;
}
}
MyView.mxml
public function set someData(data:DataHolder):void {
trace("setSomeData x="+data.x+",y="+data.y+",name="+data.name);
}
I found the problem is due to a combination of BabelFX 2.0 and Mate framework 0.9.1. Below is the BabelFX related code. Using MyView as a target of the ResourceInjector causes all PropertyInjector's related to it being fired twice. Is there an issue in the code below?
testLocalization.mxml:
<?xml version="1.0" encoding="utf-8"?>
<LocaleMap enableLog="true"
xmlns="http://l10n.babelfx.org/"
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:factory="mx.core.*" >
<mx:Metadata>
[ResourceBundle("testprop")]
</mx:Metadata>
<ResourceInjector bundleName="testprop" target="{MyView}">
<ResourceSetter property="myButton.label" key="testsomething.title"/>
</ResourceInjector>
MyView.mxml (also the main app)
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" xmlns:local="*"
xmlns:mate="http://mate.asfusion.com/">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
<mate:Debugger level="{Debugger.ALL}" />
<local:testLocalization/>
<local:MyEventMap/>
</fx:Declarations>
<s:Button id="myButton">
</s:Button>
</s:Application>
testprop.properties
testsomething.title = SOMETHING

Flex 4, listen an event from parent

I have the following problem:
Description:
I have a page with a button and a spark list (spark.components.List), when the button is clicked, all the elements in the list should change their label.
The list uses a custom item renderer to display the data (The renderer is a spark item renderer: s:ItemRenderer and the data that will be displayed comes from database).
When I click the button, I dispatch an event "button_clicked", that event should be listened by all the elements in the custom item renderer.
In the renderer, I have this function that should listen to the "button_clicked" event:
public function init():void
{
this.addEventListener("button_clicked", button_clicked);
}
public function button_clicked(event:Event):void
{
mdm.Dialogs.prompt("Button clicked event dispatched");
}
Problem:
The method "button_clicked" is never executed, which means that the event is not listened in the item renderer.
Anyone that can help me to understand how to dispatch an event in a parent and listen to it in the ItemRenderer object.
Thanks
From a related question:
In renderer's init(), you need to add
an event listener not to the renderer,
but to the container which dispatches
the event.
Example:
container.addEventListener(Container.SELECT_ALL_USERS, selectAllHandler, false, 0, true);

Resources