I am trying to learn Flex and now i have the next code: http://pastebin.com/rZwxF7w1
This code is for my login component. I want to get a special string for encrypting my password. This string is given by my authservice. But when i login i get a multiple times a alert with Done(line 69 in the pastebin code or line 4 in the code on the bottom of this question). But i want that it shows one single time. Does someone know what is wrong with this code?
Tom
protected function tryLogin():void {
encryptStringResult.addEventListener('result', function(event:ResultEvent):void {
var encryptString:String = event.result.toString();
Alert.show('Done');
});
encryptStringResult.token = auth.getEncryptString();
}
It's possible that tryLogin is called multiple times, meaning that you'd be adding multiple event handlers that does the same thing to the same event.
You could try the following:
protected function tryLogin():void {
if (encryptStringResult.hasEventListener('result'))
return;
encryptStringResult.addEventListener('result', function(event:ResultEvent):void {
encryptStringResult.removeEventListener('result', arguments.callee);
var encryptString:String = event.result.toString();
Alert.show('Done');
});
encryptStringResult.token = auth.getEncryptString();
}
It will first check wether or not there already is an event listener for 'result' in which case it will simply return. Also, it will remove the (anonymous) event listener that gets added when the event has been dispatched.
Related
I have an activity indicator on xaml page. Initially its IsVisible property is false. I have a button on page. When user click on button it calls a web service to get data. I change the value of IsVisible property to true before calling the service so that activity indicator starts to display on page and after successful calling of service I change its value to again false so that it doesn't show any more on page.
But it is not working. I know the actual problem. When we call the web service the UI thread gets block and it doesn't show the activity indicator.
How I can enable the UI thread when web service gets called so that activity indicator can show on page until we get the data?
Try making your webservice call into an async and await it.
Depending on how you've structured things you may have to use a TaskCompletionSource as the following example demonstrates.
In this example when the button is clicked, the button is made invisible, and the ActivityIndicator is set to IsRunning=True to show it.
It then executes your long running task / webservice in the function ExecuteSomeLongTask using a TaskCompletionSource.
The reason for this is that in our button click code, we have the final lines:-
objActivityIndicator1.IsRunning = false;
objButton1.IsVisible = true;
That stop the ActivityIndicator from running and showing, and also set the button back to a visible state.
If we did not use a TaskCompletionSource these lines would execute immediately after calling the ExecuteSomeLongTask if it was a normal async method / function, and would result in the ActivityIndicator not running and the button still being visible.
Example:-
Grid objGrid = new Grid()
{
};
ActivityIndicator objActivityIndicator1 = new ActivityIndicator();
objGrid.Children.Add(objActivityIndicator1);
Button objButton1 = new Button();
objButton1.Text = "Execute webservice call.";
objButton1.Clicked += (async (o2, e2) =>
{
objButton1.IsVisible = false;
objActivityIndicator1.IsRunning = true;
//
bool blnResult = await ExecuteSomeLongTask();
//
objActivityIndicator1.IsRunning = false;
objButton1.IsVisible = true;
});
objGrid.Children.Add(objButton1);
return objGrid;
Supporting function:-
private Task<bool> ExecuteSomeLongTask()
{
TaskCompletionSource<bool> objTaskCompletionSource1 = new TaskCompletionSource<bool>();
//
Xamarin.Forms.Device.StartTimer(new TimeSpan(0, 0, 5), new Func<bool>(() =>
{
objTaskCompletionSource1.SetResult(true);
//
return false;
}));
//
return objTaskCompletionSource1.Task;
}
You need to do your work in an asynchronous way. Or in other words: Use Asnyc & Await to ensure, that you UI works well during the call.
You can find more informations in the Xamarin Docs.
async and await are new C# language features that work in conjunction
with the Task Parallel Library to make it easy to write threaded code
to perform long-running tasks without blocking the main thread of your
application.
If you need further asistance, please update your question and post your code or what you have tried so far.
I have some jQuery that I'm using to open a pop-up window where a new consignor can be added to the database. The original window has a dropdownlist of all of the current consignors. When you add the new consignor in the pop-up window, that window closes and the original window then reloads the dropdownlist's data and selects the one just created.
All of that works perfectly. My issue is that when you fill out the rest of the form and submit it, it passes an empty string instead of the value of the selected item. Is this because it's an ASP.Net script? I don't know a lot about ASP.Net, but I've never had this issue with PHP. Can someone explain how I would go about refreshing the dropdownlist without refreshing the entire page and still get the list to pass it's value upon form submission?
My javascript code on the page that opens the pop-up and reloads the list is below:
function openConsignorAdd() {
var url;
url = "/admin/consignor/csAdd.aspx";
window.open(url, "WizardWindow", "width=400,height=500,resizable=yes,scrollbars=yes");
}
function loadNewAdded(fn, cs_txt_id) {
// var pagePath = window.location.pathname;
var pagePath = "/admin/getNewList.asp";
var paramList = "data=";
//Call the page method
$.ajax({
type: "POST",
url: pagePath + "?type=" + fn + "&cs_txt_id=" + cs_txt_id,
data: paramList,
success: function (data) {
//create jquery object from the response html
var $response = $(data);
//query the jq object for the values
var results = $response.filter('select#results').html();
if (fn == "consignor") {
$("select#<%=itemConsigner.ClientID%>").html(results);
} else if (fn == "cdr") {
$("select#<%=itemCDR.ClientID%>").html(results);
}
},
error: function () {
alert("Failed To Refresh!\n\nYou must manually refresh the page.");
}
});
}
My javascript code on the pop-up page to refresh the list is:
function refreshOpener(cs_txt_id) {
window.opener.loadNewAdded("consignor", cs_txt_id);
}
Those both work. And to get the value of my dropdownlist, I simply use:
if (itemConsigner.SelectedValue.ToString() != string.Empty)
{
itemCsTxtId = itemConsigner.SelectedValue.ToString();
}
with my dropdownlist being:
<asp:DropDownList ID="itemConsigner" runat="server" TabIndex="1"></asp:DropDownList>
If you need more info, just let me know. Any help is appreciated.
It seems that the issue is that since I am making the change after the page loads, the server does not see my new addition as one of the original options so ignores it completely. This is good so that people cannot just edit your forms I guess. So what I did was instead of getting the value of itemConsigner.SelectedValue, I grab the value for Request.Form["itemConsigner"] with the long ID. That way it doesn't validate that my submitted option was an original option.
Might be a silly observation but without all the code I'm not sure if this is the case. Are you just updating the original list with the id in the select options. The value needs to be populated as well for each. That could be why you are getting an empty value on after form submission.
I have a DropdownList that shows a list of providers & the Provider associated with that Patient must be selected.
The Dropdown list:
<s:DropDownList id="providerList"
width="80%"
fontSize="12"
fontWeight="bold"
selectionColor="white"
creationComplete="providerList_creationCompleteHandler(event)"
dataProvider="{model.practiceProviderList.practiceProviders}"/>
where practiceProviders is an ArrayCollection
The CreationCompleteHandler function:
protected function providerList_creationCompleteHandler(event:FlexEvent):void
{
var firstN:String;
var lastN:String;
var providerObj:Provider = new Provider();
if (model.patientDetails.patientDetail.patientProviders != null && model.patientDetails.patientDetail.patientProviders.length > 0)
{
firstN = patientDetailsModel.patientDetails.patientDetail.patientProviders.getItemAt(0).provider.providerName.firstName;
lastN = patientDetailsModel.patientDetails.patientDetail.patientProviders.getItemAt(0).provider.providerName.lastName;
for (var count:int = 0; count < patientDetailsModel.practiceProviderList.practiceProviders.length; ++count)
{
providerObj = patientDetailsModel.practiceProviderList.practiceProviders.getItemAt(count, 0).provider as Provider;
if (providerObj.providerName.firstName == firstN && providerObj.providerName.lastName == lastN)
{
this.providerList.selectedIndex = count;
}
}
}
}
The issue is when I go to this page the first time, the error is :
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at com.newwavetechnologies.modules::demographics/providerList_creationCompleteHandler()[C:\harish\flex\apps\workspace\dataCollection-flexUserInterface\src\com\newwavetechnologies\modules\demographics.mxml:166]
at com.newwavetechnologies.modules::demographics/__providerList_creationComplete()[C:\harish\flex\apps\workspace\dataCollection-flexUserInterface\src\com\newwavetechnologies\modules\demographics.mxml:359]
at flash.events::EventDispatcher/dispatchEventFunction()
at flash.events::EventDispatcher/dispatchEvent()
at mx.core::UIComponent/dispatchEvent()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\core\UIComponent.as:12266]
at mx.core::UIComponent/set initialized()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\core\UIComponent.as:1577]
at mx.managers::LayoutManager/doPhasedInstantiation()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\managers\LayoutManager.as:759]
at mx.managers::LayoutManager/doPhasedInstantiationCallback()[E:\dev\4.0.0\frameworks\projects\framework\src\mx\managers\LayoutManager.as:1072]
where line 166 is:
if (providerObj.providerName.firstName == firstN && providerObj.providerName.lastName == lastN)
The providerObj is null the first time. But when hit back and come to the same page again, everything works fine and 1 of the providers in the list is selected correctly.
Probably I think the first time, the creationComplete handler method is called before the List is populated. The 2nd time when the call is made, the list is populated and the handler works fine. It would be great if someone can help me in this regard on how to go about this.
Thanks
Harish
It's hard to tell what's going on here, but the problem lies here:
providerObj = patientDetailsModel.practiceProviderList.practiceProviders.getItemAt(count, 0).provider as Provider;
There's a tonne of places in that line that Null pointer exceptions could occur.
Most likely - the practiceProvider returned at position count doesn't have a provider set. We can't see how this value is populated, but given this code works later, I'd say you've got a race condition happening - the data is being accessed before it's been set.
At very least, you should add a guardClause for this:
var practiceProviders:ArrayCollection = patientDetailsModel.practiceProviderList.practiceProviders;
for (var count:int = 0; count < practiceProviders.length; ++count)
{
providerObj = practiceProviders.getItemAt(count, 0).provider as Provider;
if (!providerObj)
continue;
// etc
}
The race condition is a little trickier, given the asyncronous natoure of flex server calls. (I'm assuming that you're loading the data from a remote server).
There's two approaches to solve this - either
defer execution of this method until the data has loaded - you could do this by adding an eventListener to the ResultEvent of the RemoteService
or
Don't worry about it the first time around, but re-execute the method whenever the data changes.
eg:
protected function providerList_creationCompleteHandler(event:FlexEvent):void
{
dataProvider.addEventListener(CollectionEvent.COLLECTION_CHANGE,onCollectionChange,false,0,true);
updateProviders();
// Rest of existing creationComplete code moved to updateProviders();
}
private function updateProviders()
{
// Code from existing creationComplete handler goes here
}
private function onCollectionChange(event:CollectionEvent):void
{
updateProviders();
}
I want to dispatch a custom event when the two files are downloaded or uploaded successfully. I use
fileRef.addEventListener(Event.COMPLETE, completeHandler);
fileBigRef.addEventListener(Event.COMPLETE, completeHandler);
to listen the complete event with only 1 handler.
function completeHandler(event:Event):void{
var e:Event=new Event("addInfoDone");
dispatchEvent(e);
fileBigRef.removeEventListener(Event.COMPLETE,completeHandler);
fileRef.removeEventListener(Event.COMPLETE,completeHandler);
}
I want the event to be dispatched only once when both of the fileRef and fileBigRef are complete transfered. Any ideas?? My brain is fry now and can't think of anything..... Thanks for the help.
For a quick and dirty solution, how about defining a counter that increments each time completeHandler is fired. Once the counter reaches the number of files you're expecting (sounds like you're expecting 2), you fire your addInfoDone event:
var fileRefCounter:Number = 0;
function completeHandler(event:Event):void{
fileRefCounter++;
if(fileRefCounter == 2)
{
// both files have downloaded; fire your custom event, or whatever
}
}
I'm building a Flex app which requires me to download files.
I have the following code:
public function execute(event:CairngormEvent) : void
{
var evt:StemDownloadEvent = event as StemDownloadEvent;
var req:URLRequest = new URLRequest(evt.data.file_path);
var localRef:FileReference = new FileReference();
localRef.addEventListener(Event.OPEN, _open);
localRef.addEventListener(ProgressEvent.PROGRESS, _progress);
localRef.addEventListener(Event.COMPLETE, _complete);
localRef.addEventListener(Event.CANCEL, _cancel);
localRef.addEventListener(Event.SELECT, _select);
localRef.addEventListener(SecurityErrorEvent.SECURITY_ERROR, _securityError);
localRef.addEventListener(IOErrorEvent.IO_ERROR, _ioError);
try {
localRef.download(req);
} catch (e:Error) {
SoundRoom.logger.log(e);
}
}
As you can see, I hooked up every possible event listener as well.
When this executes, I get the browse window, and am able to select a location, and click save. After that, nothing happens.
I have each event handler hooked up to my logger, and not a single one is being called! Is there something missing here?
The problem seems to be with my command being destroyed before this could finish.
For a proof of concept, I set my localRef variable to be static instead of an instance variable, and everything went through successfully! I guess Cairngorm commands kill themselves asap!