In the code below when I call chkAuthentication function from another function the remoteObj.login (login function in my service file (.php)) is called after the remaining code in that function. i.e., the loginStatus is returned from the function before the result-handler function loginResult is called. but my loginStatus is supposed to be set in loginResult function. It seems that the asynchronous behaviour is the culprit. what should I do in order to get the loginResult function to complete first?
Please help me out. Thank you.
private var loginStatus:Boolean;
public function chkAuthentication(loginVOObj:LoginVO):String{
remoteObj.login.addEventListener(ResultEvent.RESULT,loginResult);
remoteObj.login(loginVOObj);
if(loginStatus == true){
return displayName;
}
else{
return 'fail';
}
}
private function loginResult(result:ResultEvent):void
{
if(result.result == null){
loginStatus=false;
}else{
loginStatus=true;
}
}
The chkAuthentication method should not return a String since it is asynchronous. Instead, just create an instance variable and set its String value in the loginResult method. You can then use a binding or dispatch an event to update the UI.
The previous answer is correct - rather than depending on the service to act synchronously, which, aside from performance issues, is a rare case in flex, you should use the loginResult function to store the login status in this object or an object that you're using to store the application's state. Then, display it using a databound control:
<mx:label text={userStatus.loginDisplay} />
Related
I've created a simple form with an enum field on a grid, dragged from the DataSource CompanyImage:
Table CompanyImage has an Index on this field named Brand in my example and AllowDuplicates is set to No :
And here is the form:
I've overridden the close() method of the form like this:
public void close()
{
CompanyImage_ds.write();
super();
}
An error is displayed when I close it saying that
"Cannot create a record in CompanyImage(CompanyImage). Legal entities: Example1.
The record already exists."
That's fine but I would like a way to stop closing the window when this happens. A validateWrite() would be nice but I am not really able to figure out where and what to write in order to accomplish this behavior.
I mean, how to check that new row is added and it contains a field that already exists in the table ?
You shouldn't have to force the write() method. Closing the form should already do it.
If you wish to check something to allow the form to be closed, the close() method is too late in execution. You should leverage the canClose() method.
You could override the validate method of the grid column. You would need to write some validation logic in that method but that would prevent the column from saving at all if validation failed.
public boolean validate()
{
boolean ret;
// write your own validation logic
if (validation logic is true)
{
ret = true;
}
return ret;
}
I've been trying this for a day now and I can't work it out.
I have a main application Planner.mxml. This view has a couple of custom components, one of which is LoginView.mxml. In LoginView.mxml I do the following:
protected function btnLoginClick(event:MouseEvent):void
{
try
{
var login:Login = new Login(txtEmail.text, txtPassword.text);
}
catch(error:Error)
{
Alert.show(error.message, "Oops!");
}
}
I create a new instance of my Login class and send some parameters to the constructor. My constructor looks like this:
public function Login(email:String, password:String)
{
if(email == "" || password == "")
{
throw new Error("Please complete all fields.");
}
else
{
var loginRequest:HTTPService = new HTTPService();
var parameters:Object = new Object();
parameters.email = email;
parameters.password = password;
loginRequest.url = Globals.LOGIN_URL;
loginRequest.resultFormat = "object";
loginRequest.method = "POST";
loginRequest.addEventListener("result", loginHandleResult);
loginRequest.addEventListener("fault", loginHandleFault);
loginRequest.send(parameters);
}
}
Here I check if all fields are complete, and if so, I put the constructor parameters in a parameters object which I then send to the HTTPService, which is a simple PHP file that handles the request, checks with the db and returns some xml. (This might not be the best way, but this really isn't too important at this point).
If the user is logged in successfully, the xml will contain a status property which is set to true. I check for this in the result event handler of the HTTP service. This is where everything goes wrong though.
protected function loginHandleResult(event:ResultEvent):void
{
if(event.result.status == true)
{
trace("logged in");
// here stuff goes wrong
var e:LoggedInEvent = new LoggedInEvent("loggedIn");
dispatchEvent(e);
}
else
{
trace("not logged in");
Alert.show("Wrong credentials.", "Oops!");
}
}
As you can see, when the user is successfully logged in, I want to dispatch a custom event; if not, I show an alert box. However, this event doesn't dispatch (or at least, I don't know how to listen for it).
I would like to listen for it in my main application where I can then change my viewstate to the logged-in state. However, the event never seems to get there. I listen for it by having loggedIn="loggedInHandler(event)" on my loginComponent.
Any idea how to do this? Thanks in advance. I would really appreciate any help.
First, your Login needs to extend event dispatcher or implement IEventDispatcher. I'm not sure why you're getting compiler errors trying to dispatch events from it.
Next, you need to listen to the new Login instance for that event.
However, you have an architectural problem here that your View should NOT be handling business logic and it should DEFINITELY not be creating new objects that are not its own children on the Display List.
Instead, you should dispatch an event from the View that REQUESTS that a login occur, and then that request should be handled further up. Depending on the scale of your application, this can be the main mxml file or separate controller or Command logic. It is ok for the View to do a minimal amount of validation prior to dispatching the Event, but ideally you would want to encapsulate this stuff into a PresentationModel (because it is easier to test).
If you dispatch event then somebody who interested in this event must to subscribe to this event.
If you dispatch event from LoginView instance then in object who wait this event you need such lines:
loginViewInstance.addEventListemer("loggedIn", loggedInHandler);
and in handler:
private function loggedInHandler(event:LoggedInEvent):void
{
//do something
}
do what you need.
I have some questions with a particular structure of a program I'm writing.
I'm using a Remote Object to make a remote call to a Rails method (using WebOrb). The problem arises in the way that I get my data back.
Basically I have a function, getConditions, in which I add an event listener to my remote call and then I make the remote call. However, what I want to do is to get that data back in getConditions so I can return it. This is a problem because I only access the event result data in the event handler. Here's some basic code describing this issue:
public function getConditions():Array
{
remoteObject.getConditions.addEventListener("result", onConditionResult);
remoteObject.getConditions();
//Here is where I want to get my event.result data back
}
public function onConditionResult(event:ResultEvent):void
{
//Here's the data that I want
event.result;
}
How can I achieve this data turn-about?
Remote calls in flex are always asynchronous so you won't be able to call getConditions() and wait there for the result. You have to use a function closure to process the results, either by means of an event handler than you declare elsewhere or a dynamic one created immediately within getConditions(), like so:
remoteObject.getConditions.addEventListener("result", function(event:ResultEvent):void {
// Run the code that you would want to when process the result.
});
remoteObject.getConditions();
The advantage of doing the above is that you would be able to "see" parameters passed to getConditions() or the result of any logic that happened before addEventListener() in the function closure. This however, takes a slight performance hit compared to declaring an explicit function (for that exact reason).
I should also add that doing so requires you to clean up after yourselves to make sure that you are not creating a new listener for every request.
you do it like this
public function getConditions():Array
{
remoteObject.getConditions.addEventListener("result", onConditionResult);
remoteObject.getConditions();
}
public function callMyExtraFunction(data:Object):void
{
//Here is where you want to get your event.result data back
}
public function onConditionResult(event:ResultEvent):void
{
//Here's the data that you want
var data:Object = event.result;
callMyExtraFunction(data);
}
You could make use of Call Responder like so :
<s:CallResponder id="getOperationsResult"/>
then use these lines to get the result from get operations
getOperationResult.token = remoteObject.getOperation();
this creates the call and returns the result stores it in getOpresult
whnever u want to access this u can call that token or getOperationResult.lastResult
Hope that helps
Chris
I'm trying to implement the cascading dropdown from the toolkit. I need to get the count in a sub category dropdown, if it's zero then I turn off the visibility of the sub category.
If I use the javascript OnChange event then my script fires before the web method, so I need to know how to fire my script AFTER the web method has fired please.
My demo page: http://bit.ly/92RYvq
Below is my code and the order I need it to fire.
[WebMethod]
public CascadingDropDownNameValue[] GetSubCats1(string knownCategoryValues, string category)
{
StringDictionary kv = CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);
int CategoryID;
if (!kv.ContainsKey("Category") || !Int32.TryParse(kv["Category"], out CategoryID))
{
return null;
}
dsSubCat1TableAdapters.Categories_Sub1TableAdapter SubCats1Adapter = new dsSubCat1TableAdapters.Categories_Sub1TableAdapter();
dsSubCat1.Categories_Sub1DataTable SubCats1 = SubCats1Adapter.GetSubCats1(CategoryID);
List<CascadingDropDownNameValue> values = new List<CascadingDropDownNameValue>();
foreach (DataRow dr in SubCats1)
{
values.Add(new CascadingDropDownNameValue((string)dr["SubCategory1"], dr["SubCatID1"].ToString()));
}
return values.ToArray();
}
function getSubCatCount() {
$get("ddlSubCats1").style.display = $get("ddlSubCats1").length > 1 ? "block" : "none";
}
Generally when you call your web method function through javascript you can supply it two call back functions. One gets fired if there is an error and the other gets fire once the web method call has been completed. The callback requires two arguments, the result and a context. For example if your function was called myWebMethodFunction and your namespace it was contained in was my.fully.qualified.namespace it may look like this.
my.fully.qualified.namespace.myWebMethodFunction(param1, param2, ... , paramN, onErrorCallback, onCompleteCallback, context);
Once that function finishes, it will call the onCompleteCallback passing the result of your webmethod function and whatever you passed for a context.
It has been a while since I've called a web method function so I might have gotten the order of the callback reversed.
For some reason I can't comment on things either, but I can add to this.
I may be thinking about something different, but you must be calling something through javascript to fire your webmethod, correct? Whatever you use to call the webmethod through javascript should provide a mechanism to add a callback that will be fired once your webmethod call is complete and returned.
Use jQuery.ajax() it allows you to specify a success function and a failure function that fire after the web method returns.
I have two functions in an ActionScript class, they are:
private function loaderCompleteHandler(event:Event):void
{
_loader = Loader(event.target.loader);
selectedBitmap = Bitmap(_loader.content);
}
public function byteArrayToBitmap( byteArray:ByteArray ):void
{
_loader.contentLoaderInfo.addEventListener( Event.COMPLETE, loaderCompleteHandler );
_loader.loadBytes( byteArray );
}
Is it possible to send the selectedBitmap variable back to the byteArrayToBitmap function after the event completed?
Not clear what you want to do.
You cannot return anything from the same call stack as the original call to byteArrayToBitmap, and there's no "sleep" available in AS3. Once you get into "loadCompleteHandler", you cannot return anything to the caller of byteArrayToBitmap. So you'll have to modify the caller to wait for the event COMPLETE and then check for the selectBitmap object. This will have to be stored somewhere.
That is, if I understand your problem.