Loading JSON data from server into knockout.js observable - javascript

I am trying to load initial data (from a local JSON string) using knockouts.js in order to displayed it in the UI right after loading the page.
I have tried a LOT of options but all failed or produce errors.
My latest try is http://jsfiddle.net/z22m1798/17/ (base on the 'Cart' example) which produce the error:
TypeError: cartLine.filterValue is not a function.
The relevant code is:
//Load initial data from server
var JSONdataFromServer = $("#JSONdataFromServer").val();
console.log(JSONdataFromServer);
var dataFromServer = ko.utils.parseJson(JSONdataFromServer);
self.lines.push(new CartLine(dataFromServer));
Someone maybe know what am I doing wrong here?
It's look like a difficult issue.
Thanks

I found that the way to solve it (don't sure it is the most accurate way) is by receiving from the server the entire JSON so the first cells will contain the filters I wish to display. In addition, the server will send a parameter "filtersToDisplay" that indicate how many filters need to display.
By default, filtersToDisplay=1 to display only the first line.
http://jsfiddle.net/z22m1798/25/
for (i = 0; i < $("#filtersToDisplay").val(); i++) {
self.lines.push(new CartLine(self.lines))// Put one line in by default
}
Thanks

Related

Backbone model.save() fails unless evaluated in DevTools console first

I have this function in a Backbone view:
updateToServer: function(e) {
e.preventDefault();
var id = e.target.getAttribute('data-id');
var file = this.collection.get(id);
var data = {};
$(e.target).serializeArray().map(function(x) {data[x.name] = x.value;});
file.save(data);
this.$el.modal('hide');
}
If I allow this to run naturally, I get undefined is not a function on file.save(data). However, if I set a breakpoint in Chrome DevTools at file.save(data) and evaluate that function manually in the console before resuming, both save functions work.
Why is this happening and how can I fix it?
Here's the entire view in case you need additional context: https://gist.github.com/raddevon/d3ddf1bba101b6b67c4b#file-supportfilesview-js-L155-L163
Update: New discovery: On the second run, this works. I have an even listener on form submit. When I click the submit button the first time, I get the error. If I click again, the model saves.
Can you try this
updateToServer: function(e) {
e.preventDefault();
var id = e.target.getAttribute('data-id');
var file = this.collection.get(id);
var data = {};
$(e.target).serializeArray().map(function(x) {data[x.name] = x.value;});
this.$el.modal('hide');
setTimeout(function(){
file.save(data);
}, 200); //try with different values for timer
}
I have added a 200 millisecond timer.
This might not be your actual solution but at least you will come to know if there is some asynchronous stuff going on before 'file' is actually formed.
Try different values for the timer. I mean keep increasing the timer and see if you are still not able to get rid of the error.
Once you are sure that 'file' is formed asynchronously then you can look into why that's happening.
And try console.logs instead of debuggers for debugging so that you can test without pausing the execution.
Hope that helps.
This was not at all what I suspected, and I hadn't given enough information in the question without realizing it. The line in my code that triggered the exception was file.save(), but the actual exception was happening inside Backgrid.
I provide a form to allow users to update models from the collection displayed in a grid. A particular column is defined as an integer column, but I hadn't converted the value coming from the form to an integer. As a result, Backgrid was trying to run toFixed on a string. I modified my form serialization code to convert strings containing only integers into integers. Now, everything works as expected.
Here's that serialization code:
$(e.target).serializeArray().map(function(x) {
data[x.name] = x.value === 'on' ? true : x.value;
if (!isNaN(parseInt(data[x.name])) && isFinite(data[x.name])) {
data[x.name] = parseInt(data[x.name]);
}
});
If I had to guess, I'd say that's probably a bit naive, but it seems to be working well in my application.
Thanks to everyone for the help!

Store and Retrieve WinJS.Binding.List in Application Data

I'm developing a Windows 8 Store app using HTML/JavaScript and I've run into an issue storing and retrieving a WinJS.Binding.List into Windows.Storage.ApplicationData.current.roamingSettings.
I DID get this to work by hand rolling my own method of converting the binding list into XML string and storing that, then on retrieval parsing it back out into a list. But, this seems crazy inefficient and I'm trying to find a better way. I've tried JSON.stringify() and JSON.parse() which seem to store and retrieve the right data but as soon as I bind the data to the winControl the application crashes with a 0 (no error message at all).
Here's a bit of my code to demonstrate what I'm attempting (list is a binding list):
function onSaveData() {
if (list) {
Windows.Storage.ApplicationData.current.roamingSettings.values["data"] = JSON.stringify(list);
}
}
function onLoadData() {
var data = Windows.Storage.ApplicationData.current.roamingSettings.values["data"];
if (data) {
list = JSON.parse(data);
var listview = element.querySelector("#mylistview").winControl;
listview.itemsSource = new WinJS.Binding.List(list);
}
}
I know I can get this working the long way, so I'm not looking for any solution... I'm really just hoping there's an easy way to store/retrieve these data objects that I'm missing. If I can find an easier way to do this it will eliminate about 40 lines of code and I can stop using an entire library. Also, as I go forward I plan to have more binding lists that will need to be stored as well. Thanks!
You need to bind to the List's dataSource property, not to the List itself:
listview.itemsSource = new WinJS.Binding.List(list).dataSource;
The dataSource property is specifically the IListDataSource that the ListView requires for a data source. The ListView doesn't understand anything about the WinJS.Binding.List directly, only through that particular interface. (I discuss this in Chapter 7, section "The Structure of Data Sources", in my free ebook, Programming Windows Store Apps with HTML, CSS, and JavaScript, 2nd Edition.)
Your saving and reloading the list with JSON is completely fine.

Parsing a large JSON array in Javascript

I'm supposed to parse a very large JSON array in Javascipt. It looks like:
mydata = [
{'a':5, 'b':7, ... },
{'a':2, 'b':3, ... },
.
.
.
]
Now the thing is, if I pass this entire object to my parsing function parseJSON(), then of course it works, but it blocks the tab's process for 30-40 seconds (in case of an array with 160000 objects).
During this entire process of requesting this JSON from a server and parsing it, I'm displaying a 'loading' gif to the user. Of course, after I call the parse function, the gif freezes too, leading to bad user experience. I guess there's no way to get around this time, is there a way to somehow (at least) keep the loading gif from freezing?
Something like calling parseJSON() on chunks of my JSON every few milliseconds? I'm unable to implement that though being a noob in javascript.
Thanks a lot, I'd really appreciate if you could help me out here.
You might want to check this link. It's about multithreading.
Basically :
var url = 'http://bigcontentprovider.com/hugejsonfile';
var f = '(function() {
send = function(e) {
postMessage(e);
self.close();
};
importScripts("' + url + '?format=json&callback=send");
})();';
var _blob = new Blob([f], { type: 'text/javascript' });
_worker = new Worker(window.URL.createObjectURL(_blob));
_worker.onmessage = function(e) {
//Do what you want with your JSON
}
_worker.postMessage();
Haven't tried it myself to be honest...
EDIT about portability: Sebastien D. posted a comment with a link to mdn. I just added a ref to the compatibility section id.
I have never encountered a complete page lock down of 30-40 seconds, I'm almost impressed! Restructuring your data to be much smaller or splitting it into many files on the server side is the real answer. Do you actually need every little byte of the data?
Alternatively if you can't change the file #Cyrill_DD's answer of a worker thread will be able to able parse data for you and send it to your primary JS. This is not a perfect fix as you would guess though. Passing data between the 2 threads requires the information to be serialised and reinterpreted, so you could find a significant slow down when the data is passed between the threads and be back to square one again if you try to pass all the data across at once. Building a query system into your worker thread for requesting chunks of the data when you need them and using the message callback will prevent slow down from parsing on the main thread and allow you complete access to the data without loading it all into your main context.
I should add that worker threads are relatively new, main browser support is good but mobile is terrible... just a heads up!

AJAX progress bar on array iteration?

I am not too familiar with AJAX but I'm sure what I am trying to do is possible.
Basically I have a form with a text area, when the form is submitted the text area is made into an array with each new line being a value. Simple stuff, now my php then performs a database query on each array value. Also simple.
Now as the operation takes a while I want to make it into an AJAX call using jquery, and for every iteration on the array I want it to display the result back on my main page as well as displaying a progress bar.
So if my text area contains a list of 20,000 names and the query is to fetch the ages of these people, the ajax call would split the textarea into an array and iterate the array. For each iteration it should perform the query and send the result to my main page. So on my main page I will see a list that grows over time.
I hope I have explained this well enough, I just need advice on where to start/what to research. Any examples would be greatly appreciated.
Thanks!
As ajax is simply a request for data you cannot create a reliable loading bar easily.
However if you are doing loads of requests as you suggest in your question, "Which by the way is not the best idea".
You could do something like the code below. Again its pretty basic but will give your user a rough idea. I stuck it in a fidddle here for you http://jsfiddle.net/6dgAF/ its a basic example but should give you a jump off point.
function Status(data)
{
this.data = data;
this.size = this.data.length;
this.current = 0;
this.bar = $("#bar");
//Get width of each step of load
this.step = (this.bar.width() / this.size) ;
for(var i =0; i < this.size; i++){
this.getData(this.data[i]);
}
}
Status.prototype.getData = function(string){
//run your ajax here on each string and on success do this
//$.get( "ajax/test.html", function( string ) {
//this.current++;
//this.updateBar();
//});
this.current++;
this.updateBar();
}
Status.prototype.updateBar = function(){
//updates the bar with the current count * step width;
$("span",this.bar).width(this.step*this.current);
}
//Init object and put in dummy data
var status = new Status(new Array("string1","string2","string3","string4","string5","string6","string7","string8","string9","string10"));
An AJAX request is nothing else than requesting data from your server, just like any HTML page. The only difference is that you use Javascript, and don't feed the data to your browser as an HTML page, but use the data some way on your page.
One possible way to do the thing you want is the following:
Set an interval with the refresh rate, which calls a function getData
In getData you perform an AJAX request, which requests a piece of data from the server, which represents the current state. You might want to make sure the server only returns incremental updates, to avoid sending large amounts of data
Use the data on your front page, by displaying it in a friendly way to the user.
The main thing to keep in mind is that the server must save it's current state (the data which it has gathered with its queries), which it must return in the event of an AJAX request.
What you want is called XHR2 - personally I am using dojo
(dojo/request/xhr here)
However it should be possible with jQuery as well, search for jQuery XHR2 progress ...

YUI Datatable - call arbitrary function *once* on sort

We're using a lot of YUI data tables to display data, and rather than using the built-in pagination we've done our own so we can paginate on the server side using AJAX without downloading the whole data set (which is often huge).
Whenever we use the data table's sorting funcionality, though, it will only sort the one page because from YUI's point of view that's the entire data set.
I need to be able to call an arbitrary function to reload the page data whenever the user tries to sort the data. I've looked into DataTable's sortFunction parameter and it's not ideal because it gets called multiple times (once for each row combination it needs) and I need to do it just once.
There are probably plenty of hacky ways I could do this, but what's the "nicest" way of going about this?
Ideally, you would sort on the server side.
when create the datatable, one of the config options is generateRequest (see this example: http://developer.yahoo.com/yui/examples/datatable/dt_bhm.html )
generateRequest is a meant to be a function which generates a URL which returns the correct data set with which to fill the table. You probably have this.
For me, whenever I click on the column header (to sort), it makes a new request to the server, getting the correct page of sorted data.
Why not write a custom function and close over a variable that tracks whether it's been called?
var hasBeenCalled = false;
function mySortFunction(){
if(!hasBeenCalled){
// do something
hasBeenCalled = true;
}
}
Then replace the sortFunction with that.

Categories

Resources