AngularJS and big JSON data - javascript

For a custom AngularJS application that uses data from an API I've been creating I've come across the use of Angular oboe. Oboe is a bower package that helps streaming large JSON files to the view. So after some trial and error, I've managed to build a decent oboe GET method that obtains around 4000 JSON items in around 2 seconds. But my problem starts when adding more GET methods to the same view.
At first there weren't any problems but eventually, the loading time keeps getting bigger and bigger. So I've tried using the Oboe Cached: true configuration. Sadly it doesn't work at all. Every time I load the page all the data is loaded again instead of obtained from the browser Cache
In my example below, you're able to see the structure of one of my oboe function's that I've been trying to cache. A JSfiddle link is added down below as well.
The Function and the view
function createProduct(id, name) {
this.id = id;
this.name = name;
}
$scope.products = [];
oboe({
url: 'config/get/getProducts.php',
method: 'GET',
cached: true
}).path('products.product.*', function () {
// we don't have the person's details yet but we know we
// found someone in the json stream. We can eagerly put
// their div to the page and then fill it with whatever
// other data we find:
}).start(function () {
console.log("start");
}).node('products.product.*', function (products) {
// we just found out their name, lets add it
// to their div:
$scope.products.push({
id: products.id,
name: products.name.language
});
$scope.totalItems = $scope.products.length;
return new createProduct(products.id, products.name);
}).done(function () {
console.log( $scope.products );
});
// Refresh data
$scope.refreshData = function() {
cartService.refreshData()
.then(function(response) {
$scope.cartItems = response.cartItems;
$scope.totalCartItems = response;
$scope.selectedCustomer = response;
})
};
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="productimg col-lg-4 col-md-4" ng-repeat="product in products | limitTo : limit : (currentPage - 1) * limit track by product.id"
ng-class="{lastItem: $last}" scroll-bottom="event">
<div class="row">
<div class="col-md-12" ng-bind="product.id"></div>
<div class="col-md-12">
<a ng-bind="product.name" href="{{product.id}}.nl"></a>
</div>
</div>
</div>
<div class="col-lg-12 text-center margin-t-30">
<ul uib-pagination
total-items="totalItems"
ng-model="currentPage"
items-per-page="limit">
</ul>
</div>
In the JSfiddle You're able to see the code. I couldn't get the JSON to work on on JSfiddle but see it as the following line but then around 10000 "product" rows.
{"products":{"product":[{"id":"1240","id_manufacturer":"0","id_supplier":"0","id_category_default":"2","id_tax_rules_group":"8","quantity":"0","id_shop_default":"1","reference":{},"ean13":"0","price":"0.000000","active":"0","date_add":"2014-07-15 12:06:34","date_upd":"2018-04-21 12:22:37","name":{"language":"zie voorschot factuur 03"}},{"id":"1241","id_manufacturer":"0","id_supplier":"0","id_category_default":"2","id_tax_rules_group":"8","quantity":"0","id_shop_default":"1","reference":{},"ean13":"0","price":"0.000000","active":"0","date_add":"2014-07-15 12:06:41","date_upd":"2018-04-21 12:22:37","name":{"language":"zie voorschot factuur 04"}},{"id":"8908","id_manufacturer":"0","id_supplier":"15","id_category_default":"2","id_tax_rules_group":"8","quantity":"0","id_shop_default":"1","reference":"041002","ean13":"5712084210057","price":"45.454545","active":"1","date_add":"2015-11-12 18:03:47","date_upd":"2017-11-18 09:57:27","name":{"language":"Vaavud Sleipnir smartphone wind meter"}}}}
So the real struggle I'm facing is that getting the data from the network tab takes around ten seconds. (there is an API request at "getProducts.php"). Then parsing that to the view costs around 30 seconds. (way too long). Secondly, I would like to cache the getProducts request so that the products are directly obtained the next time the view is loaded. With a normal $http.get() and cache: true. It worked but then I'm still facing the slow binding, even with Oboe.
If there is any more information needed please let me know in the comments below.
As always, thanks in advance!

We had a project like this which had too much API with heavy object data. Some of tips we used are these:
1-Arrays instead of Objects
With a bit searching and reading about these data structures, you'll find that the memory consumed by objects is more than the memory used by Arrays. So convert your Array of objects to array of arrays in server side.
2-Use one more level cache
Store data in a server side cache, something like MongoDb and Redis. Handle requests with these steps:
Check the browser cache. If data is available and up-to-date, use this data.
If data is not available in browser, send request to server. Check the server side cache. If data is available and up-to-date, Send this data to client and store it in cache and also use it.
If data is not available in server cache, Send request to API and get data, Store it in server cache, and then sent it back to client and store it in cache and also use it.
3-Send minimum data required by client each time
A client may not stay in a page and see all data shown. Prepare minimum data you need for each page and if client request, bring the others.
For your case, instead of 10,000 product, Just prepare 1000 of them for example and if client needs more, prepare more data, append to your client cache and show it.
If all 10,000 products are required by client, prepare them in several requests.
Read more here
4-Cache data in browser with good module and in correct way for reading data again
There are some modules prepared for AngularJs. Read about them, their standards and best practices. This is so important to have a good client cache.
ngStorage
Hope these tips help you.

Related

Ajax requests, database and security

This post is more a question than an actual issue with code.
So for a long time when I had to display for example a list of items from database, I used to display the Id (primary key in the table) directly in the HTML like this for example :
<div id="1"></div>
<div id="2"></div>
<div id="3"></div>
<div id="4"></div>
So like this when I wanted to do an Ajax request of the current clicked item, it was easy because I just had to retrieve the attribute from the html like this :
$.ajax({
url: '/api/Item/'+$(this).attr('id'),
type: 'GET',
})
.done(function() {
console.log("success");
})
.fail(function() {
console.log("error");
})
.always(function() {
console.log("complete");
});
That's only after browsing a lot of websites that I noticed that nobody display the primary key (Id) directly in the HTML. But somehow they could still do ajax request to the API using the Id of the clicked item. So my question is : How can I get the current clicked Id to do my ajax request without displaying anywhere. I mean how does these websites manage to do that ? Maybe they get list from server that they use in the client then ? But it still does not explain how they manage to get the current clicked Id.
Appreciate your thoughts and suggestions on this.
Example of website : https://www.toneden.io/
The chat at the bottom right when connected see network and web browser console.
To get response from the server, you have to request something. In this case, you are saying i don't want to display primary key anyware in html side and get result from server. my suggestion on this, In php > you can use binary number instead of primary key and convert back to number and use acc. to requirements. Example :- decbin() and bindec()
There's nothing wrong with displaying an id. I've appended the database id such as id="game_1281" in cases where I only want to refer to the DOM in response to a server push update. Another option is to use a data attribute like so: data-id="1281". This allows you to get the value without any messy parsing before sending it to the server.
Referencing a unique id is not a security issue. Just make sure you are doing the appropriate server-side checks to ensure that the action taken is possible for that user based on various constraints and privileges.

Lightswitch load all data or run a async method synchronously

I have a grid with data in Lighswitch application. Grid has on every column posibility to filter column. Thanks to lsEnhancedTable
Right now I am sending an ajax request to the web api controler with the list of ids of the Customers that I want to export. It works but with a lot of data it is very slow because I have to turn off the paging of the data to get all visible customers ids so I can iterate over the VisualCollection.
To optimize this I would have to turn on back the paging of the data to 50 records so that the initial load is fast and move the loading of the data to a save/export to excel button.
Possible solutions:
Load data all data on save button click. To do this I have to somehow load all items before I can iterate over collection.
The code bellow locks UI thread since the loadMore is async. How to load all data synchronously? Ideally I would like to have some kind of progress view using a msls.showProgress.
while(3<4)
{
if (screen.tblCustomers.canLoadMore) {
screen.tblCustomers.loadMore();
}
else
break;
}
var visibleItemsIds = msls.iterate(screen.tblCustomers.data)
.where(function (c) {
return c;
})
Second approach would be turn on paging and pass just the filters applied by the users to the web api controller so I can query database and return only filtered records. But I don't know how to do that.
Third approach is the one that I am using right now. Turn off the paging->iterate over visual collection, get the customers id, pass them to the controller and return a filtered excel. This doesn't work well when there are a lot of records.
Iterate over filtered collection in the server side? I don't know if there is a way to do this in Lighswitch?
Here's an option for client side javascript.
// First build the OData filter string.
var filter = "(FieldName eq " + msls._toODataString("value", ":String") + ")";
// Then query the database.
myapp.activeDataWorkspace.ApplicationData.[TableName].filter(filter).execute().then(function (result) { ... });

sending continuous text data from java code to html via http request

I am working on developing an application where i am am doing http post request via angular and then this request is received by Java code, code does its stuff and generate logs of about 50-60 lines creating one line every seconds.
I want to show these logs on my html page as they generate, right now i am collecting all logs and displaying them once the request finishes?
Can this be done in continuous manner?
JAVA CODE
Java code create array of logs of size 50-60, it takes 60-90 seconds to finish the operation, and i am sending array with below code after converting it to JSON
response.getWriter.write(applogs)
JAVASCRIPT CODE
var httpPostData = function (postparameters,postData){
return $http ({
method : 'POST',
url : URL,
params : postparameters,
headers: headers,
data : postData
}).success (function (responseData){
return responseData.data;
})
}
var addAppPromise = httpPostData (restartAppParams,app);
addAppPromise.then(function (logs){
$scope.logs = logs.data;
})
HTML Code
<span ng-repeat="log in logs">{{log}}<br></span>
You have at least two options:
(Uglier but faster and easier one) Make your service respond immediately (don't wait for 'stuff' to be generated) and create second service
that would return logs created so far. Then in JS implement polling: call this second service in short, fixed intervals and update view.
Use EventSource to get server sent events .
You can also use websockets, but since you only want your server to
feed client, EventSource should be enough. However, keep in mind that this API will require polyfills for IE/Edge and special handling on the server side.

finding the ajax request in dojo

I am working on a crawlers to scrap all data from the website. they use ajax for pagination. I found this on the href of the page numbers
javascript:dojo.publish("showResultsForPageNumber",[{pageNumber:"4",pageSize:"15", linkId:"WC_SearchBasedNavigationResults_pagination_link_4_categoryResults"}])
what is happening here. I am not aware of these dojo. Can any one help me to find the corresponding server script so that i can scrap all the data including pagination.
update#1
in the console i found
this is the code where it is redirected.
showResultsPage:function(data){
var pageNumber = data['pageNumber'];
var pageSize = data['pageSize'];
pageNumber = dojo.number.parse(pageNumber);
pageSize = dojo.number.parse(pageSize);
setCurrentId(data["linkId"]);
if(!submitRequest()){
return;
}
console.debug(wc.render.getContextById('searchBasedNavigation_context').properties); //line 773
var beginIndex = pageSize * ( pageNumber - 1 );
cursor_wait();
wc.render.updateContext('searchBasedNavigation_context', {"productBeginIndex": beginIndex,"resultType":"products"});
this.updateHistory();
MessageHelper.hideAndClearMessage();
},
It's part of the publisher/subscriber part of the Dojo framework and does not say anything about the executed AJAX request.
If you're not familiar with the publisher/subscriber pattern, then let's explain that first. To decouple certain components/parts of the application, this pattern is commonly used.
On one side, someone publishes information, while on the other side (= some other part of the application) someone listens to it.
In this case, the following data is published (= second parameter):
[{
pageNumber: "4",
pageSize: "15",
linkId: "WC_SearchBasedNavigationResults_pagination_link_4_categoryResults"
}]
Obviously, not all subscribers in the application need to know about this data, so there's a topic system, in this case, the data is published to a topic called "showResultsForPageNumber"(= first parameter)
To know what happens next, you will have to look through the code for someone who subscribes to that topic. So somewhere in the code you will find something like this:
dojo.subscribe("showResultsForPageNumber", function(data) {
// Does something with the data, perhaps an AJAX call?
});
TO answer your question, look in the code for something like: dojo.subscribe("showResultsForPageNumber", as it will tell you what happens next.
However, if you're just interested in the AJAX calls, it will be easier to check the network requests, if you're using Google Chrome/Mozilla Firefox/... you can use the F12 key to open your developer tools, then select the Network tab and activate if necessaray. Now click on the pagination controls and you will see a log of all network traffic and the request + response data.
Here you are publishing the topic with name "showResultsForPageNumber" where "pageNumber", "pageSize", "linkId" are properties of object of your argument array.
See following link: ref1 ref2

Can $http.put write data to JSON file

I apologize for the newbie question but I am getting conflicting answers to this while searching on the net.
I have created an AngularJS app to read from a JSON file using $http.get and display the data as a form with each form element binded with ng-model. Ideally I would like the user to be able to edit the desired field and click save, then have that data updated in the JSON file. I have been told that to do this you will need a 3rd party server like NodeJS, but I am seeing other examples that show it being done in videos. Can someone tell me if this is possible without the 3rd party server and if so what is the best practice for doing this.
Thank you
$http GET (for resource located on client) will not work with the Chrome browser and will give a CORS error (unless you disable Chrome web security by opening Chrome using run .../chrome.exe" --allow-file-access-from-files -disable-web-security). Firefox gives an error saying the JSON in not well formed even though it is. Browsers don't seem to like it.
HTML5 LocalStorage is your best bet for client storage where you wish to perform CRUD operations and have the data survive past page refresh. A good example of this is the [TodoMVC example]
(https://github.com/tastejs/todomvc/tree/gh-pages/architecture-examples/angularjs)
A very simple example that saves a json file to localstorage and reads the contents of localstorage is shown. The Service contains a getter and a setter method to interact with localstorage.
INDEX.HTML
<body ng-app = "app">
<div ng-controller="MainCtrl">
<form>
<input placeholder="Enter Name.." ng-model="newContact"/>
<button type="submit" class="btn btn-primary btn-lg"
ng-click="addContact(newContact)">Add
</button>
</form>
<div ng-repeat="contact in contacts track by $index">
{{contact.name}}
</div>
</div>
APP.JS
angular.module('app', ['app.services'] )
.controller('MainCtrl', function ($scope, html5LocalStorage) {
//create variable to hold the JSON
var contacts = $scope.contacts = html5LocalStorage.get();
$scope.addContact = function(contact) {
$scope.contacts.push( {"name":contact} ); //Add new value
html5LocalStorage.put($scope.contacts); //save contacts to local storeage
}
});
SERVICES.JS
angular.module('app.services', [] )
.factory('html5LocalStorage', function () {
var STORAGE_ID = 'localStorageWith_nG_KEY'; //the Local storage Key
return {
//Get the localstorage value
get: function ()
{
return JSON.parse(localStorage.getItem(STORAGE_ID) || '[]');
},
//Set the localstorage Value
put: function (values)
{
localStorage.setItem(STORAGE_ID, JSON.stringify(values));
}
};
});
Otherwise you could use Node and Express and store the JSON file on the server. Use file system module 'fs-extra' to interact with the json file.
You would have to create RESTful API routes for the client to interact with the server using $http and perform CRUD operations.
/put
/get
/delete
/post
I would be interested to see these videos of this being done without the server writing to the file. You cant just "post the .json file" and have it replace the old one, unless you configure your server (apache, nginx, tomcat, node) to do so.

Categories