How to preload JSON data so its available when Angularjs module is ready - json

I have a very simple app that loads a JSON array using $http.get inside of a controller. It assigns the result data to scope and the HTML repeats through the results to display a list. It is a very simple angularjs example.
function ViewListCtrl($scope, $http) {
$scope.shoppinglist = [];
$scope.loadList = function () {
var httpRequest = $http({
method: 'POST',
url: 'viewList_service.asp',
data: ''
}).success(function (data, status) {
$scope.shoppinglist = data;
});
};
$scope.loadList();
}
While testing on a slow server I realized there was a 3 second blocking delay while rending the repeat region. Debugging revealed to me that my controller does not attempt to get the data until the page is loaded. My page takes 3 seconds to load. Then I must wait another 3 seconds for the json data to load.
I want to load data as soon as possible so it is ready when my controller is ready. Simply put, I want to pre-load the data so it loads in parallel to my module.
I've searched all over and the closest thing I found was "resolve", but I am not using routes. This is a very simple list and no routes or templates.
How can I load the JSON as soon as the page starts to render so it is ready when the controller is ready and there is no blocking... and then get that data into scope?

You can use the module.run method. Which is executed after the config stage is completed. To make use of this you need to create a service factory that does the actual query and caches the result
module("myapp",[]).factory('listService', function($q,$http) {
var listData;
var defer = $q.defer();
return {
loadList: function() {
if(listData) {
defer.resolve(listData);
}
else {
var httpRequest = $http({
method: 'POST',
url: 'viewList_service.asp',
data: ''
})
.success(function(data) {
listData=data;
defer.resolve(listData);
}
}
return defer.promise;
}
}
});
In your controller you still use the factory to get the data with a promise then wrapper.
listService.loadList().then(function(data) {
$scope.shoppinglist=data;
});
This way you can make the async call even before any controller related code executes.

You can load data by writing code (something like Chandermani's listService) in separate file but without using angular. you can use jquery ajax to load your data.
Then write a service in angular to read that data and pass it to your controller.

It sounds like your latency comes from a slow network + server, and not a large amount of data.
So, you could render a tag into your page, so that the data would be sent along with the page HTML response. The downside there is that you're hard-coding your data into your page. This tag would basically pre-seed the $http cache with your data.
var listJson = {...json data here, rendered server-side...};
mod.run(function($cacheFactory) {
var cache = $cacheFactory('yourListCacheId');
cache.put('list-cache-id', listJson);
// store "cache" somewhere you can retrieve it, such as a service or value.
});
Then either use the $http cache property, or wrap $http in a custom service which checks the cache.
Of course, the root of the problem is that your server takes 3 seconds per request, when you normally want that at least in the sub-second range.

Related

Node js loop in res.render

Hey Everyone i have a router that basically pulls in a JSON file and outputs various instances of the array. When i console.log the title in my for loop it loops through and outputs and each instance is outputted, works great. When i put my res.render inside of the for loop and pass it the same variable being looped in the console.log it will only output the first instance. Does anyone know why this is? and is there a way to loop through the res.render to output all instances in the JSON same as the console.log.
Thank you for your time,
router.get('/fuelTypeFilter', function(req, res, next) {
var url = "Example.JSON"
request({
url: url,
json: true
}, function (error, response, obj) {
if (!error && response.statusCode === 200) {
// console.log(obj) // Print the json response
for(key in obj.categories){
var img = obj.categories[key];
var title = obj.categories[key].product_category_title;
console.log(title);
// console.log(obj.categories[key]);
}
res.render('fuelTypeFilter', { title: 'Fuel Type', item: title });
} //end of if
}); // end of request
});
What res.render does is basically serve up a plain HTML file with some template inserted, so with data like the object you pass into the render call. Therefore, res.render acts like a return statement, as in when your code reaches that mark, it signals to the router that we need to render this page (present in the browser to user), therefore we must be done with our router handling logic.
As to whether it's possible to 'loop through' render calls, the answer is no since that would be implying to just, even if succeeded, present however many pages you want instantaneously one after the other, so in that perspective, you wouldn't really want to keep making render calls as your view in the browser would effectively keep refreshing moment after moment.
One way to do this with render is just package your array-like data into the object that you pass into res.render and then, assuming you are using some sort of templating engine, do something analogous to a 'for loop' there, looping and printing the elements as, say HTML divs.
Hope this is a bit helpful.

How to use REST endpoints to return HTML and JSON in different calls

I'm creating a website where I want to perform CRUD operations to a dataset. For the sake of simplicity, assume a table of books. I understand that example.com/books should return a list of books, and example.com/books/24 should return the book with id 24.
Now, imagine that my list of books is very large, and I want to allow the user to browse the book list using a table with pagination, but as the dataset is very large I want to retrieve only the current page using AJAX.
The question is: should example.com/books return the HTML containing the table with all pagination controls and other widgets? or should it return the data in JSON format? What would be the right way to perform both calls.
Thanks in advance
In your controller you could do something like this:
function index (Request $request){
$books = Book::paginate(10);
if($request->ajax()){
//ajax request
return Response::json(view('books', compact('books'))->render());
}
//html request
return view('books', compact('books'));
}
You can pass a page parameter to the route to navigate to pages.
Example : example.com/books?page=2 will fetch the second page of results.
Suggested Approach
Render the initial request with as html like you would normaly do. Then for the next page, get the second page rendered as an ajax call and append it to the DOM.
return Response::json(view('books', compact('books'))->render());
$('.pager a').on('click', function (e) {
var page = $(this).attr('href').split('page=')[1];
e.preventDefault();
$.ajax({
type: "GET",
url: 'page=' + page,
dataType: 'json',
success:function(json){
alert("Success"+json);
},
error:function(){
alert("Error");
}
});
});
});
Take a look at Laravel Pagination

How do I use the data returned by an ajax call?

I am trying to return an array of data inside a JSON object that is return from a URL, I can see the data that is being returned using console.log.
However when trying to catch the return array in a variable for example:
var arr = list();
console.log(arr.length);
The length being output by this code is "0" despite the fact that the data returned has content (so the length is greater than zero). How can I use the data?
list: function() {
var grades = [];
$.getJSON(
"https://api.mongolab.com/api/1/databases", function(data) {
console.log(data);
grades [0] = data[0].name;
console.log(grades.length);
});
return grades;
},
The issue you are facing is easy to get snagged on if you aren't used to the concept of asynchronous calls! Never fear, you'll get there.
What's happening is that when you call the AJAX, your code continues to process even though the request has not completed. This is because AJAX requests could take a long time (usually a few seconds) and if the browser had to sit and wait, the user would be staring in angsuish at a frozen screen.
So how do you use the result of your AJAX call?
Take a closer look at the getJSON documentation and you will see a few hints. Asynchronous functions like getJSON can be handled in two ways: Promises or Callbacks. They serve a very similar purpose because they are just two different ways to let you specify what to do once your AJAX is finished.
Callbacks let you pass in a function to getJSON. Your function will get called once the AJAX is finished. You're actually already using a callback in the example code you wrote, it's just that your callback is being defined inside of your list() method so it isn't very useful.
Promises let you pass in a function to the Promise returned by getJSON, which will get called once the AJAX is finished.
Since you are doing all this inside of a method, you have to decide which one you're going to support. You can either have your method take in callbacks (and pass them along) or you can have your method return the promise returned by getJSON. I suggest you do both!
Check it out:
var list = function(success) {
// Pass in the callback that was passed into this function. getJSON will call it when the data arrives.
var promise = $.getJSON("https://api.mongolab.com/api/1/databases", success)
// by returning the promise that getJSON provides, we allow the caller to specify the promise handlers
return promise;
}
// Using callbacks
list(function(grades) {
console.log(grades);
});
// Using promises
list()
.success(function(grades) {
console.log(grades);
});

Get real response of ngResource save()

I have the following situation:
I use ngResource to save some data to the mysql database and after the successfull save() I want to log the json response the server sends to me:
Document.save({}, postData, function(response){
console.log(response);
});
This does not result in a simple response, but in something like an object with its own methods. I want some smple output like the response.data after an $http.$get:
{
"docClass":"testets",
"colCount":1,
"columns":null,
"groupid":7,
"id":19,
"lang":"de",
"title":"test",
"version":1409849088,
"workflow":"12234"
}
Greets
Check out this answer
Promise on AngularJS resource save action
So I think in your case you need to do
var document = new Document(postData);
document.$save()
.then(function(res){});
But also from the link I provided
This may very well means that your call to $save would return empty reference. Also then is not available on Resource api before Angular 1.2 as resources are not promise based.

Ext.Data.Connection request result not rendering on grid?

Ive been stuck with this issue for some time
My JSon store fields need to retrieve some more info:
{ name: "ExpirationDate", convert: convertDate },
{ name: "AffectedObject", convert: GetValue },
The date method is working fine but the result from GetValue is not being rendered on the grid even though the code is working and returning the correct value (either with or without JSON):
function GetValue(v) {
var conn = new Ext.data.Connection();
conn.request({
url: 'test/GetObjectByID',
method: 'POST',
params: { id: v },
scriptTag: true,
success: function (response) {
console.log(response.responseText);
ReturnResult(response.responseText);
},
failure: function () {
Ext.Msg.alert('Status', 'Something went wrong');
}
});
function ReturnResult(str) {
return Ext.util.JSON.decode(str.toString());
}
Any idea why the result is not not showing?
The 'convert' property is expecting an immediate return value. Your GetValue function is issuing an asynchronous request and then immediately returning nothing. At some arbitrary point in the future after the request completes the 'success' function is called, but it is no longer connected to the original call so any value it may return is meaningless.
Though you could make it work by replacing the use of Ext.data.Connection with manually constructed synchronous requests, I recommend reconsidering the mechanism by which you are getting this data. Issuing a separate request for every record in your data store is less than optimal.
The best solution is to bring that additional data in on the server side and include it in the response to the store proxy's initial request. If that cannot be done then you can try listening to the store's 'load' event and performing conversion for all loaded records with a single request. Any grids or other views you have reading from the store may have to be configured to display dummy text in place of the missing data until the conversion request completes.