I have a form in which user can add information and add images. The images are base64 encoded so everything is stored in a json object. This object is sent to the server (with $resource) when the user submits it.
If a user adds for example 3 Images with about 2MB per Image, has a shitty connection like Edge, and wants to upload it it seems like it's taking forever. The user just sees the $ionicLoading overlay without information how long it will take or how much % are already uploaded.
The UX is bad because the user could assume, that the app froze or is in an endless loop and that it's just a bad app.
I have the following ideas but no idea if they are possible or
Is there a way in angular, cordova or ionic to get the browserinformation how much % are already uploaded?
Is there a way to get the current uploadspeed? I could get the size of my object by getting the length of my stringified JSON Object, divide it 1024 to get the kB. Then i would check the current uploadSpeed every second and add the current uploadspeed to a variable. With this information i could calculate the uploaded % approximately
JQuery ajaxForm Plugin?
Sounds like what you are looking for is progress events from XHR2.
Assuming your server is setup to handle XHR2 and return content-length, In plain JavaScript:
function upload(blobOrFile) {
var xhr = new XMLHttpRequest();
xhr.open('POST', '/server', true);
xhr.onload = function(e) { ... };
// Listen to the upload progress.
var progressBar = document.querySelector('progress');
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
progressBar.value = (e.loaded / e.total) * 100;
progressBar.textContent = progressBar.value; // Fallback for unsupported browsers.
}
};
xhr.send(blobOrFile);
}
upload(new Blob(['hello world'], {type: 'text/plain'}));
Upload speed is also calculable using the information returned in the progress event, as you described.
As for this implementation in AngularJS/Ionic, it seems like this is a longstanding issue within the framework that $http doesn't really support progress events.
I have seen implementations that utilize a special angular directive written for this, or even utilize a jQuery file upload implementation.
Related
I am developing an android app using phonegap which call an api on page load getting a json object as a return parameter.
now I have to construct the page using jQuery mobile by extracting values from the recieved object.
So I am asking what will be the best practice for this which can reduce its loading time.
Thanks for helping.
Presently what I am doing
<script>
$(document).ready( function() {
$.ajax({
url : "demourl.com",
type : "GET",
success : function(data) {
var obj = $.parseJSON(data);
$("#results").html(obj.messagedetails[0].spamReason.userApprove);},
fail : function() {
$("#notification").text("Try again after some time.");
}
});
});
</script>
Getting objects from this call and setting it in
<div id="results"></div>
There's nothing you can do about $.ajax / $.getJSON loading time, it will depend on your internet connection.
Never load data during the page transitions, do it ether before page change or after a page change. Best practice is to do it before page change (just show AJAX loader to indicate AJAX content is loading).
When data is loaded use .append( and not .html( to append data.
In case you are using each or for loop to add a dynamic content (laoded with an AJAX) UNDER NO CIRCUMSTANCES enhance page markup (apply jOuery Mobile style to new added content) during each loop, THIS IS A HUGE TIME SINK, do it only after all content has been added.
You can find more about this in my ARTICLE, or find it HERE.
Do not use document ready, it could trigger before page is loaded. Instead use correct page event.
Find more about document ready vs page events in my other ARTICLE, here you will also find a way to benchmark jQuery Mobile and some statistic about how much time is needed for some jQM actions.
While creating an Android app in Appcelerator's Titanium that involves both webView and background calls, I ran into a problem / bug where the cookies were getting corrupted on multiple createHTTPClient calls.
Cookies were originally obtained from the webView:
var webview = Ti.UI.createWebView();
webview.url = 'http://www.example.com';
window.add(webview);
webview.addEventListener('load', function(e) {
cookies = e.source.evalJS("document.cookie");
Titanium.App.Properties.setString('cookies',cookies);
}
window.open({modal:true});
and then later used with a background call:
var loader = Titanium.Network.createHTTPClient();
loader.open("GET",base_url + url);
loader.onload = function() {
// process response
}
loader.setRequestHeader('Cookie',Titanium.App.Properties.getString("cookies"));
loader.send();
The first time the above createHTTPClient chunk of code was called, everything worked, but subsequent runs of the above code would send corrupted cookies. In Google App Engine (gae), printing out the request headers would look like this (broken):
logging.info('Request:\n%s' % self.request)
broken response (only the cookie portion of the request header is shown)
Cookie: auth="eyJfdXNlciI6WzYsMSwiVmRoZEtnYWZRMnNxazFjaVM0U1lKdCIsMTM1NzIyMzcwOSwxMzU3MjIzNzA5XX0\075|1357223709|4f622167f477a8c82cab196af4b0029af1a966d7", auth=eyJfdXNlciI6WzYsMSwiVmRoZEtnYWZRMnNxazFjaVM0U1lKdCIsMTM1NzIyMzcwOSwxMzU3MjIzNzA5XX0\075|1357225569|7a469fab7a38a437649c25620729e07c4607f617
Cookie2: $Version=1
working response
Cookie: auth="eyJfdXNlciI6WzYsMSwiVmRoZEtnYWZRMnNxazFjaVM0U1lKdCIsMTM1NzIyMzcwOSwxMzU3MjIzNzA5XX0\075|1357223709|4f622167f477a8c82cab196af4b0029af1a966d7"
...
I suspect the issue has something to do with unicode characters or something inside createHTTPClient. Two auth= statements are shown in the corrupted cookie.
In summary, when the app first launches, the background Titanium.Network.createHTTPClient call works, and any calls after that appear to send corrupted cookies.
The HTTPClient documentation says "object is intended to be used for a single request," so I assumed everything would reset after multiple calls. But something was different after the first call.
Adding loader.clearCookies(base_url); to the code before setting the cookies seems to fix the issue.
var loader = Titanium.Network.createHTTPClient();
loader.open("GET",base_url + url);
loader.onload = function() {
// process response
}
loader.clearCookies(base_url); // THE FIX.
loader.setRequestHeader('Cookie',Titanium.App.Properties.getString("cookies"));
loader.send();
I am working on a prototype Air for Android application that loads some remote swf files (all created and controlled by me) and I need to be able to pass a variable along to the remote SWF.
Here is a quick break down of how the process currently works:
The Android app, called Loader, is installed on the device.
Loader points to my server and finds Player.swf, which it loads into the main stage. Player.swf show a login screen.
When a user logs in correctly, Player.swf receives an XML response from an API with a list of remote SWF videos to display for the user. Player.swf loops through the XML list and plays each remote SWF, one after the other.
Now, so far, so good. The remote SWF videos load up and play perfectly. But I need to start picking up variables from Player.swf (pulled from the XML response) to use in the remote SWF (things like text strings, user ID's etc)
From all the searching I have done, I believe it is down to the Sandbox environment, as Loader is a compiled application and Player.swf + the remote SWF's are all coming off a server. However, now I am wondering, as Player.swf is the one that has the AS3 code to deal with the XML response, and that is located on the same server as the remote SWF's that are played (and therefore should be the same sandbox?)
I was able to pass a variable along using a URL parameter, but it only works locally and not when I use the Android application.
I found an old blog pot about Sandbox Bridges, but the example file download doesn't work anymore.
Can anyone point me in the right direction in using the parentSandboxBridge function/class to pass along a variable (all examples I have seen deal with passing functions and/or are coded for Flex)
I cannot post any code, as I simply have nothing to show for what I want to achieve (I'm totally stumped on this bit!)
EDIT: I managed to get parameters to pass along (even though it worked locally before, it didnt work with the Loader app > Remote Player > Remote SWF animation combo)
I had to set the application domain context inside Player.swf (seeing as it is on the same server as the remote swf animations, not sure why I needed to do this)
But oddly, I cannot use parent or root to pickup variables?
I've tested this on HTC Desire running android 2.2.2 and it works what I've put in comment thus the answer is as follows:)
your host needs to define similar:
var params:URLVariables = new URLVariables();
params["string"] = "ala ma kota";
params["number"] = 1979;
var request:URLRequest = new URLRequest();
request.data = params;
request.url = "urlVarsReader.swf";
var loader:Loader = new Loader();
loader.load(request);
addChild(loader);
then loaded content (here urlVarsReader.swf) can read them as follows:
var output:TextField = new TextField();
addChild(output);
output.border = true;
output.width = 320;
output.height = 240;
output.wordWrap = true;
output.multiline = true;
var p:Object = getParams(this.loaderInfo);
for (var name:String in p)
{
output.appendText(name + " = " + p[name] + "\n");
}
I have a wrapper method for reading params:
public function getParams(li:LoaderInfo):Object
{
try
{
var params:Object = li.parameters;
var pairs:Object = {};
var key:String;
for(key in params)
{
pairs[key] = String(params[key]);
}
}
catch(e:Error)
{
return {error:e.getStackTrace()};
}
return pairs;
}
best regards
EDIT:
This works only with local content fails with SecurytyError e.g. SecurityError: Error #2070: Security sandbox violation: caller http://example.com/urlVarsReader.swf?string=ala%20ma%20kota&number=1979 cannot access Stage owned by app:/loadwithparams.swf
I want user to wait for specified time(4seconds) to get connected to server. If it cannot connect within the specified time period, application should get closed.
Here is what I have coded:
var downloadDataReq = Titanium.Network.createHTTPClient({timeout :4000});
downloadDataReq.onload = function() { //some code }
downloadDataReq.onerror = function(event) { //some code }
var urlToDownloadData = 'http://www.google.com';
downloadDataReq.open("POST", urlToDownloadData);
downloadDataReq.send();
The Problem is that app waits for fix time (timeout parameter does not effect at all).
P.S.: making an app for android using Titanium.
Try to use method like this:
downloadDataReq.setTimeout(4000);
For me, timeout on HTTP requests aren't working as it should. I had very weird issues, such as:
If I put 1000ms timeout, it'll be called on 2 or 3 seconds.
If I put 2000ms timeout or above, it'll never be called.
I'm using Android ICS and JB, and on both I get the issues above. Seems that timeout parameter is buggy.
As a workaround, I'm doing checks inside onload (example: if I'm downloading a file, I compare the checksum of local file, with the checksum of the same file on the server), and I'm simulating timeouts with JavaScript's setTimeout. It's working to an extend.
The code below demonstrate how to simulate a request timeout, with JS's setTimeout command:
var downloadDataReq = Titanium.Network.createHTTPClient();
downloadDataReq.onload = function() {
clearTimeout(timeout);
alert('loaded');
}
downloadDataReq.onerror = function(e) {
clearTimeout(timeout);
alert('error: ' + e.error);
}
var urlToDownloadData = 'http://10.1.1.183/maquina_local/arquivos/FirefoxPortable_12.0_PortugueseBR.paf.exe';
downloadDataReq.open("GET", urlToDownloadData);
var timeout = setTimeout(function(){
downloadDataReq.onload = function(){
downloadDataReq.onerror({'error': 'timeout'});
};
downloadDataReq.abort();
}, 4000);
downloadDataReq.send();
On timeout, I'm changing onload event to onerror one, because if you try aborting a running request, it'll trigger 'onload' event, not 'onerror'. If you don't do it, this issue can give you corrupted files (ex: a 20mb file that, when request is aborted, file will be incomplete, with a size smaller than 20mb).
I'm still testing this solution, but at least for now, it solved a few bugs for me.
Try this.
Ti.App.timeOut = 99000; //declare in app.js
then use anyWhere in your project.But make Sure every time when you create a httpClient.
dont recreate or redefine in Code or through out the page.
this works fine for me.
//HAVE A LOOK OVER THE USE OF THIS
var xhr = Titanium.Network.createHTTPClient({timeout:Ti.App.timeOut});
I've been trying all day to make this thing works but it's still not right yet. I've checked so many posts around here and tested so many different implementations that I'dont know where to look now...
Here is my situation, I have a small php test file (gz.php) on my server wich looks like this :
header("Content-Encoding: gzip");
print("\x1f\x8b\x08\x00\x00\x00\x00\x00");
$contents = gzcompress("Is it working?", 9);
print($contents);
This is the simplest I could do and it works fine with any web browser.
Now I have an Android activity using Jsoup that has this code :
URL url = new URL("http://myServerAdress.com/gz.php");
doc = Jsoup.parse(url, 1000);
Which cause an empty EOFException on the "Jsoup.parse" line.
I've read everywhere that Jsoup is supposed to parse gzipped content without having to do anything special, but obviously, there's something missing.
I've tried many other ways like using Jsoup.connect().get() or InpuStream, GZipInputStream and DataInpuStream. I did try the gzDeflate() and gzencode() methods from PHP as well but no luck either. I even tried not to declare the header-encoding in PHP and try to deflate the content later...but it was as clever as effective...
It has to be something "stupid" I'm missing but I just can't tell what... anybody has an idea?
(ps : I'm using Jsoup 1.7.0, so the latest one as of now)
The asker indicated in a comment that gzcompress was writing a CRC that was both incorrect and incomplete, according to information from here, the operative code being:
// Display the header of the gzip file
// Thanks ck#medienkombinat.de!
// Only display this once
echo "\x1f\x8b\x08\x00\x00\x00\x00\x00";
// Figure out the size and CRC of the original for later
$Size = strlen($contents);
$Crc = crc32($contents);
// Compress the data
$contents = gzcompress($contents, 9);
// We can't just output it here, since the CRC is messed up.
// If I try to "echo $contents" at this point, the compressed
// data is sent, but not completely. There are four bytes at
// the end that are a CRC. Three are sent. The last one is
// left in limbo. Also, if we "echo $contents", then the next
// byte we echo will not be sent to the client. I am not sure
// if this is a bug in 4.0.2 or not, but the best way to avoid
// this is to put the correct CRC at the end of the compressed
// data. (The one generated by gzcompress looks WAY wrong.)
// This will stop Opera from crashing, gunzip will work, and
// other browsers won't keep loading indefinately.
//
// Strip off the old CRC (it's there, but it won't be displayed
// all the way -- very odd)
$contents = substr($contents, 0, strlen($contents) - 4);
// Show only the compressed data
echo $contents;
// Output the CRC, then the size of the original
gzip_PrintFourChars($Crc);
gzip_PrintFourChars($Size);
Jonathan Hedley commented, "jsoup just uses a normal Java GZIPInputStream to parse the gzip, so you'd hit that issue with any Java program." The EOFException is presumably due to the incomplete CRC.