Flex - Dispatch custom Event on receipt of standard Event - apache-flex

I am processing a FileReferenceList.fileList[] of multiple files a user selects in the following code..
for (i=0;i < event.currentTarget.fileList.length; i ++){
fileByteData = new ByteArray();
fileByteData = (event.currentTarget.fileList[i].data as ByteArray);
loader = new Loader();
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, checkImageDimensions);
loader.loadBytes(fileByteData);
}
I need to pass i into checkImageDimensions to keep track of which image is which, I can easily enough create a custom event, but I need this to fire at the right time. Ideally I could do something like this..
var myEvent:CustomEvent = new CustomEvent(i);
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, this.dispatchEvent(CustomEvent))
But to be honest, I am unsure of how to proceed...
Can anyone help me out? Thanks!

You need to make a listener function - a function call does not suffice. Passing a class name to dispatchEvent does not work either. Here's how to do it.
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event):void {
dispatchEvent(new CustomEvent(i));
});
Note that you don't necessarily need a custom event class, if all you need in the event is a type string. You can simply use the Event class in this case:
public static const MY_CUSTOM_EVENT:String = "myCustomEvent";
...
loader.contentLoaderInfo.addEventListener(Event.COMPLETE, function(e:Event):void {
dispatchEvent(new Event(MY_CUSTOM_EVENT));
});
Edit: If you're really lazy, but still want to pass values with the event, you can use the DinamicEvent class:
var evt:DynamicEvent = new DynamicEvent(MY_CUSTOM_EVENT);
evt.attr1 = val1;
evt.attr2 = val2;
dispatchEvent(evt);
Of course, it is cleaner and less error prone to declare your own error class.

Related

AFRAME: Event on completion of dynamic adding of component

My use-case is as follows:
In a loop, entities are being created and components are being set up. This is via a json-object that is being passed to the function. The question I have is how best to get an event that the whole set of entities and their components are being initialised. The code is something like this
var parent = document.querySelector('#parent');
var ent = document.createElement('a-entity');
parent.appendChild(ent);
for(var i =0; i = components.length; i++) {
var arr = components[i];
var cl = arr[0]; // class name
var attr = arr[2]; // component name
var attrV = arr[3]; // component data
ent.setAttribute('class', cl);
AFRAME.utils.entity.setComponentProperty(ent, attr, attrV);
//ent.setAttribute(attr, attrV); tried with this too
}
console.log('loop completed')
The loop completed gets logged before the completion of the loading of some of the components. I would like to have some sort of a call back to know that all the components have been completed loaded.
There seems to be an event componentinitialized but it sends a return for only 1 component. My real requirement (not reflected in above code) is that an entity can have multiple components added.
To use the above, I may have to set this event for every component and keep track of whether it has been completed or not. Just wondering if there is a more elegant way to do it. Thanks
Entities emit the "loaded" event. It should be easier than listening for each component initialization within the entity.
Try out:
entity.addEventListener("loaded", (e) => {
console.log(e)
})
like i did here.

Select option value - selectedchoice is not working

I am binding a SELECT HTML tag with some dynamic values using knockout JS. Additionally, i am trying to set a selected choice which is failing. Please suggest where i am going wrong.
self.level1Choices.selectedChoice = ko.observable(2); - this line does not seem to work.
The JSFiddle for this code is at http://jsfiddle.net/oarp7gwj/7/
The dropdown is not loading in the JSFiddle for some reason. I dont think i have referenced the knockout JS correctly. In my local environment, I am able to load the select box with the values. However, i am not able to set the selected value.
#Wayne Ellery, #QBM5 - please advise since you know about this already :)
You should use var to declare your model object to avoid scoping issues
var viewModel = new DataModel();
The main issue was you need to add to the Datamodel by exposing it through the this variable in the Datamodel.
var DataModel = function (client) {
var self = this;
self.level1Choices = ko.observableArray();
};
Take a look at the Helo World example as to how to do this:
http://knockoutjs.com/examples/helloWorld.html
I've scoped this to self as it's a best practice to not worry about this referring to something else mentioned here: http://knockoutjs.com/documentation/computedObservables.html.
I moved the loadAllApprovers method inside the DataModel as this is where it belongs and so that it has access to populate the datamodel.
I added the mobile services client to the constructor so that it can be mocked for testing your model.
var DataModel = function (client) {
var self = this;
self.level1Choices = ko.observableArray();
var loadAllApprovers = function () {
var allAppprovers = client.getTable('TABLE');
var query = allAppprovers.select("ID", "FirstName").read().done(function (approverResults) {
self.level1Choices(approverResults);
}, function (err) {
console.log("Error: " + err);
});
};
loadAllApprovers();
};
You were also missing knockout in your jsfiddle.
http://jsfiddle.net/az4rox0q/6/

How to handle calls to multiple functions in the same web service?

This is a super newbie question on Flex. While I am a seasoned programmer, this is my first ever Flex application; please bear with me for my Flex codes.
I have a web service written in ColdFusion. In this web service, there are two functions; one is to return all the questions in a quiz and the other one is to return all the answer selections to the questions in a quiz.
[Bindable]
private var questionArray:ArrayCollection;
private var cfquiz:RemoteObject;
private function loadQuestions():void {
currentQuestionCounter = 0;
btnPrev.enabled = false;
btnNext.enabled = false;
cfquiz = new RemoteObject("ColdFusion");
cfquiz.source = "CFCertExam.cfquiz";
cfquiz.addEventListener(ResultEvent.RESULT, resultHandler);
}
private function resultHandler(event:ResultEvent):void {
questionArray = event.result as ArrayCollection;
txt1Questions.htmlText = questionArray.getItemAt(currentQuestionCounter).Question_Text;
btnNext.enabled = true;
}
I have the codes above. loadQuestions is called at creationComplete to retrieve the questions. Things are working fine. What I want to do is to call another function within the same web service, returnAnswers, to return the answer options for a question. Since I have cfquiz associated to the web service already, I was using cfquiz to call returnAnswers. However, there is an event listener associated to cfquiz already, resultHandler is being called when returnAnswers comes back with the results.
My questions are, first, is it possible to check which function returns the results within resultHandler? If so, how? And second, what is the best way to handle calls to multiple functions within the same web service?
Thanks in advance,
Monte
Yes you can. You need to specify a handler function for each method which in turn calls a different webservice.
The better way to do this is using AsyncToken and AsyncResponder instead of addEventListener, as following code.
tokenA = cfquiz.methodA();
tokenA.addResponder(new AsyncResponder(onResultForMethodA, onFaultMethodA));
tokenB = cfquiz.methodA();
tokenB.addResponder(new AsyncResponder(onResultForMethodB, onFaultMethodB));
tokenC = cfquiz.methodA();
tokenC.addResponder(new AsyncResponder(onResultForMethodC, onFaultMethodC));
or
tokenA = cfquiz.methodA();
var responderA:IResponder = new AsyncResponder(onResult, onFault, "methodA");
tokenB = cfquiz.methodB();
var responderB:IResponder = new AsyncResponder(onResult, onFault, "methodB");
tokenA.addResponder(responderA);
tokenB.addResponder(responderB);
private function onResult(evt:ResultEvent, token:Object):void {
if(token == "methodA" ) {
//logic for methodA
}
if(token == "methodB" ) {
//logic for methodB
}
}
I'm a little confused as I can't see where you are calling the actual web service function, for example from these examples, I am expecting to see:
cfquiz = new RemoteObject("ColdFusion");
cfquiz.source = "CFCertExam.cfquiz";
cfquiz.addEventListener(ResultEvent.RESULT, resultHandler);
cfquiz.myCFCFunctionCall(); /* where is this? */
Anyway, AFAIK you can create a new instance of the remote object and set that up to have it's own event listener.
Hope that helps.

Unwanted binding

The situation is simple. I have a datagrid that gets its data from a webservice.
When data from the webservice is retrived it calls the following function:
private function onListReg():void
{
arrRegOld = WSAutoreg.list.lastResult as ArrayCollection;
arrReg = WSAutoreg.list.lastResult as ArrayCollection;
dgReg.dataProvider = autoreglist;
}
dgReg is the Datagrid. the arr variables are ArrayCollections defined like so:
private var arrRegOld:ArrayCollection = new ArrayCollection;
[Bindable]
private var arrReg:ArrayCollection = new ArrayCollection;
The intent is when I hit a update button, it compares arrRegOld with arrReg and see if any values have changes. The problem is whenever I change values on the Datagrid it changes on both the dataProvider and on both ArrayCollections.
Does anyone know why is this happening? What should I do so that the binding applies only to one ArrayCollection?
Appreciate any tip.
- Mike
Your lists are sharing the same objects, if you modify the first element from arrReg you will see the modification also in arrRegOld - it is not related to binding. You need to clone the objects. You have several choices:
a) Implement a clone method for your objects (recommended)
b) Use a generic method like this one:
private function clone(source:Object):*
{
var array:ByteArray=new ByteArray();
array.writeObject(source);
array.position=0;
return(array.readObject());
}
and call arrRegOld = clone (arrReg); after arrReg = WSAutoreg.list.lastResult as ArrayCollection;

Ideas on making a javascript object name unique in ASP.Net?

I've created an ASP.Net user control that will get placed more than once inside of web page. In this control I've defined a javascript object such as:
function MyObject( options )
{
this.x = options.x;
}
MyObject.prototype.someFunction=function someFunctionF()
{
return this.x + 1;
}
In the code behind I've created MyObject in a startup script --
var opts = { x: 99 };
var myObject = new MyObject( opts );
When a certain button in the control is pressed it will call myObject.someFunction(). Now lets say the value of x will be 99 for one control but 98 for another control. The problem here is that the var myObject will be repeated and only the last instance will matter. Surely there's a way to make the var myObject unique using some concept I've haven't run across yet. Ideas?
Thanks,
Craig
Your Javascript like this:-
function MyObject(options) { this.x = options.x; }
MyObject.prototype.someFunction = function() { return this.x + 1; }
MyObject.create(id, options) {
if (!this._instances) this._instances = {};
return this._instances[id] = new MyObject(options);
}
MyObject.getInstance(id) { return this._instances[id]; }
Your startup javascript like this:-
MyObject.create(ClientID, {x: 99});
Other code that needs to use an instance (say in the client-side onclick event)
String.Format("onclick=\"MyObject.getInstance('{0}').someFunction()\", ClientID);
Note the low impact on the clients global namespace, only the MyObject identifier is added to the global namespace, regardless of how many instances of your control are added to the page.
If it is just one value, why not have the function take it as a parameter and build your onclick handler so that it puts the correct value in for each control. If it is more complex than that, then consider making options an array and, for each control, insert the correct options into the spot in the array that corresponds to each particular control. Then pass the proper index into the array into the function.
I do this by using ScriptManager.RegisterClientScriptBlock to register a string as a JavaScript block on the client side. I can then modify my script string using {0}, {1}..,{n} place holders to inject necessary ids. It depends on the structure of your code as to if this is the most elegant fashion, but it works in a pinch. You could then inject variable names using references to Me.ClientID.
You can make the value of "x" static and access it anywhere in the code, such as:
function MyObject( options ) { MyObject.x = options.x; }
MyObject.x = 99; // static
MyObject.prototype.someFunction = function () { return MyObject.x + 1; }
This way you can access MyObject.x anywhere in your code, even without re-instanciating MyObject.
Excellent solution Anthony. The other solutions offered were as good and I did consider them but I was looking for something a little more elegant like this solution.
Thanks!

Resources