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.
Related
My question looks stupid at first glance and all my searches pointed out window.location and other JS stuff or the externalWebPage plugin. That's not what I'm looking for.
From the JAVA code, when I catch one specific exception during execution of a custom plugin, I want to force the page to move to "logout.html". I don't want to execute callback.error() or to deal with the error inside code in my webpage in any ways. I only want my transaction to be cancel and a web resource to be loaded in the current web UI.
Is there any way to do that?
Thanks in advance.
The CordovaWebView offers a showWebPage function to load any url from the native code.
From the plugin you should be able to do
this.webView.showWebPage("logout.html", false, true, null);
Also offers loadUrl
this.webView.loadUrl("file:///android_asset/www/logout.html");
And you can also use loadUrl to execute javascript so you can run the window.location from there without a callback.
this.webView.loadUrl("javascript:window.location.href='logout.html'");
You will either need to add it to your main.js interface so that you can callup page changed () and handle it in your angular code.
This can be a simple onPageNeedsChanged Handler call where you retain the context on page change context and just call it whenever you need.
Or you can call the onError callback from the caller, if it is a consistent error callback context to move you there, but sounds like you don't want to do this route.
So the easiest answer then is to just launch your own Activity with a preloaded web url and a web view. You already have access to the activity, so just make your own native activity with a full web view in it, hard coded url and then launch your activity on error.
i.e. I do it for sending an email, but it could be your own activity
cordova.getActivity().startActivity(Intent.createChooser(emailIntent, "Send mail..."));
You may even be able to get a reference to the Cordova web view, but not positive on that, but I assume you could through the tree of objects.
Does that work for you needs?
If not can you elaborate on your hesitation to handle in the onerror callback. It's fairly straight forward. Maybe I can help you there as an alternative? Retaining the callingContext and just using callingContext.error(withkey or instructions or object) is not too bad.
A35ble.writeValueToPodCharacteristic(this.device.macAddress, true, this.bytesToSend,
function (response) {
console.log("Success: " + response);
callbackContext.device.notificationReceivedFromPod(callbackContext.device.arrayBufferToString(response));
},
function (response) {
console.log("ERROR: " + response);
alert("Error Sending NSM Message: " + response);
}
);
For example I made a cordova plugin called A35ble that manages my bluetooth stuff and in this response I just show alert.
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.
I have seen background service in phonegap and integrated successfully but, I need to make an ajax call to get the data from server.This call need to be happen in background process without disturbing the UI. I am unable to do this using this plugin.
And my code look like,
$.ajax({
type: "POST",
url: "http://example.com/xxx",
dataType: "xml",
async:true,
success: function (data) {
var serializer = new XMLSerializer();
var xmlString = serializer.serializeToString(data);
var finalxml= xmlString.replace(/</g, '<').replace(/>/g, '>').replace('<br/>','\n');
window.localStorage.setItem("xml_Questions",finalxml);
}
});
This ajax call has to be done with async(background) call while user doing something..
But user is not able to do anything until get the response.So I have followed Background service plugin for phonegap, but I am not able to implement this method with that plugin.
Can we do this?
Can anybody help me?
Thank you in adv...
Your $.ajax code looks right to me, so it shouldn't block the app behavior.
I don't completely understand your question... user shoudn't be allowed to do anything until the localstorage.setitem is set? If this is right, you could use jquery to enable some kind of "NEXT" button after the setItem instruction, so the user won't be able to move on until the async call is done.
I have the following setup on my site. It is working fantastically on any standard browser and any normal mobile browser:
Model:
function SearchTerm(data) {
this.Term = ko.observable(data.Term);
this.Stamp = ko.observable(data.Stamp);
}
ViewModel:
function HistoryViewModel() {
//Data
var self = this;
self.searchTerms= ko.observableArray([]);
// Load history from server
$.ajax({
type: "GET",
url: "/api/history/",
data: null,
success: function (msg) {
var terms = $.map(msg, function (item) { return new SearchTerm(item) });
self.searchTerms(terms);
},
error: function (xhr, ajaxOptions, thrownError) {
// Error Handling
}
});
}
View:
<div class="title">
Search History
<div class="closeBtn"></div>
</div>
<div id="historySection">
<ul class="searches" data-bind="foreach: searchTerms">
<li class="historyItem">
<div class="timestamp"><span data-bind="'text': Stamp"></span></div>
<span data-bind="'text': Term"></span>
</li>
</ul>
<a class="loadMore">Load 10 More Searches ยป</a>
</div>
All of this works perfectly on everything I test, with one major exception: The WebView control for Android. Whenever I run this page there, I get the following exception:
Uncaught Error: Unable to parse bindings.
Message: ReferenceError: Stamp is not defined;
Bindings value: 'text': Stamp at {url}/Scripts/libs/knockout-2.2.1.js:5
I'm at my wit's end. I've tried every possible combination of data-bind syntax (as you can see I've tried the single quotes too, as I'd seen a post related to that at some point). My only guess now is that this might be related to my order of scripts. I do currently reference knockout before I reference jquery - could this be the issue? I hadn't seen this as an issue anywhere else, but at this point, I'm willing to try anything.
Update:
All of my other knockout binding viewModels and bindings are working fine on Android, but none of them occur on page load. So that led me to look at changing the ajax to a method and trying to delay it's calling. So I implemented the following addition to my viewmodel:
//Operations
self.loadRecent = function () {
// Load search history
$.ajax({
type: "GET",
url: "/api/history/",
data: null,
success: function (msg) {
var terms = $.map(msg, function (item) { return new History(item) });
self.history(terms);
},
error: function (xhr, ajaxOptions, thrownError) {
//Error handling
}
});
In my page, here is what the initial binding looks like - it occurs at the bottom of the page:
var history = new HistoryViewModel();
ko.applyBindings(history, $("#historySection")[0]);
//Call page event handlers
$(window).load(function () {
// Load in our search history
history.loadRecent();
});
Unfortunately, same error as before. However, this is where things get really interesting. Even when I comment out the call to the loadRecent operation, I still get the error! To me, this means, for some reason, for this model only, the foreach is still trying to iterate, even though nothing exists. Do my assumptions sound correct? Anyone see anything I'm blatently missing here that would cause this issue? None of my other viewModels and views are having this issue. I have 2 others I'm binding to and they both have foreach's in them and do not seem to experience this issue.
UPDATED 2013.05.20
I updated some of the code throughout to reflect some function/object renaming I did, as I started to worry that something was getting out of sorts with me having a variable named history with a function named history (silly, I know, but I'm desparate).
I also wanted to post an additional finding. I decided to go ahead and try removing the code for loading the history completely from any loading or ready event. Rather, I was able to separate out this data load into a button click. Here is what the button click handler looks like:
$(".menuButton").on("click", "", function () {
history.searchTerms([]);
history.loadRecent();
});
Fun fact when I do this though, in Android-only. I still get an error on load, in the bindings:
Uncaught Error: Unable to parse bindings.
Message: ReferenceError: searchTerms is not defined;
Bindings value: foreach: searchTerms at {url}/Scripts/libs/knockout-2.2.1.js:5
Another interesting tidbit - if I were to remove the html from the view altogether, meaning there are no bindings, yet still leave the code for the SearchTerm model and the HistoryViewModel, I still get an error from the WebView in Android, when the button is clicked:
Uncaught TypeError: Object #<History> has no method 'searchTerms' at {url}:681
Sorry for so much posting, but I'm desperate to figure out what's wrong with this.
maybe webview does some wacky stuff with HTML 5 history api and its resetting it on top of your history view model. have you tried changing the vm name to historyVM or something? i would argue you shouldnt be naming your viewmodels to match things being used by the browser itself (like, dont name your vm 'window' or 'document')
Is there a way to create a serious HTML/CSS/JS project with multiple HTML, CSS, JS files on JSfiddle.net ?
If yes, how to do it ?
I want to create a basic mobile apps based on HTML/CSS/JS, about a dozen of HTML/CSS/JS files. I would like to develop it all on JSfiddle, my favorite Online JavaScript IDE. But JSfiddle.net while a clean way to test projects stays limited to:
1 html file (personal)
1 CSS file (personal)
1 JS file (personal)
several external resources (CSS, JS libs, data) which request you another webhosting.
The official doc suggesting Github hosting for 1HTML/1JS/1CSS/someDataFiles is not satisfying. I wish all on JSFiddle, and more files in my project.
You can do it inside a jsFiddle but there are few limitations, and you are probably not going to be satisfied with it.
You can test only 1 HTML multiple pages template. But in case of jQuery Mobile framework this will be enough, as you can place numerous jQM pages inside a 1 html file.
For example, this is my jsFiddle template when helping to this group: http://jsfiddle.net/Gajotres/yWTG2/
You cant use normal form submitting. Instead you should use ajax to sumbit form data.
In my other answer you can find solutions for ajax form submitting and how to send parameters during the page transition: jQuery Mobile: Sending data from one page to the another
In case you want to communicate with an remote host:
var ajax = {
sendRequest:function(save_data){
$.ajax({url: 'http://localhost/JSONP_Tutorial/json.php',
data: save_data,
async: true,
beforeSend: function() {
// This callback function will trigger before data is sent
$.mobile.showPageLoadingMsg(true); // This will show ajax spinner
},
complete: function() {
// This callback function will trigger on data sent/received complete
$.mobile.hidePageLoadingMsg(); // This will hide ajax spinner
},
success: function (result) {
if(result == "true") {
$.mobile.changePage( "#index", { transition: "slide"} ); // In case result is true change page to Index
} else {
alert('Login unsuccessful, please try again!'); // In case result is false throw an error
}
// This callback function will trigger on successful action
},
error: function (request,error) {
// This callback function will trigger on unsuccessful action
alert('Network error has occurred please try again!');
}
});
}
}
jsFiddle has a stupid policy where they want to prevent usage of full HTML files. They are trying to enforce this with stupid error warnings in HTML content part. You will need to have something like firebug plugin for Firefox or Chrome to remove this stupidity. Or you can even do it with Grease Monkey plugin.
In case you want to use full HTML template like in this example: http://jsfiddle.net/Gajotres/yWTG2/ you will need to use your javascript code in onDomready state.
Some functionalities are not going to work. Like window.orientationchange event.