I'm having a trouble looking for an answer for this situation.
Our system server has logs that keeps updating.
The view of the logs is terrible ! and very messy.
So I want to build a web application that will show the logs and will offer filtering options to make our life easier :).
So this is what I've planned:
1) I'll load up to 50 log lines (so it wont be blank when opened);
2) I'll keep pulling information for every line the console write.
Well, How do I approach step 2? how can I be synced with the server logs?
furthermore, When I load the 50 lines maybe a new line alrdy had been put out in the console, which lower the integrity of data provided in the log viewer.
BTW I use PuTTY to see the log console.
Excuse me for my bad English. Thanks from advance :)
Ok, so if you are planning on doing this entirely client side with Angular, you're going to need to:
Create an API, some endpoint/url that you can fetch your logs from. Something like http://www.example.com/my-console-feed/. You might already have this.
Poll the server with angular's $interval at the interval of your choosing.
If you were operating with web sockets, perhaps some continuous feed could be done.
So you could make a factory that looks something like this:
(function() {
'use strict';
angular
.module('myApp')
.factory('pollingFactory', pollingFactory);
function pollingFactory($http, $interval) {
return function() {
// 60000 is 1 minute
var duration = 60000;
// log API endpoint
var myLogAPIEndpoint = 'http://www.example.com/my-console-feed/';
// this will hit the API every minute
$interval(function() {
// poll the api for new logs
$http({
url: myLogAPIEndpoint,
method: 'GET'
})
.success(function(response) {
// do something with the response
})
}, duration);
}
}
})();
If you were going to go this way, I'd use $q as a promise library and in your controller, when the promise resolves, update the model in your scope with the new logs. If you're using ng-repeat, I'd also recommend using track by for performance if the logs have unique IDs.
Here is a fiddle polling an API every 3 seconds.
Related
I am working on angular js application.
For the first time application is working fine, when we release a new build with new changes, when the user trying to access the page browser is still loading the old files new changes are showing in the browser, to load the new changes user has to clear the cache and reload the application.
Is there any way to clear the browser cache on the application load.
I am clearing the cache like below.
function run($rootScope,$state, $stateParams, authorization, principal,$templateCache) {
//code to clear the cache.....
$rootScope.$on('$viewContentLoaded', function() {
$templateCache.removeAll();
});
}
it is clearing the cache, but pagination is not working after adding this code into application .
Any help appreciated, thanks in advance.
Try to set version for all of you files and http requests, do not clear the cache!
Want to Browse Faster? Stop Clearing Your Browser Cache
how to set version to files and api requests, you can put a global variable to handle it after each publish for example:
var version = "1.0.0";
var app = angular.module("app", []);
app.config(function(){
//for routes
//pages.html?v="+version
//controller.js?v="+version
})
app.controller("ctrl", function($http){
$http.get("api/posts?v=" + version)
})
with this version you can handle your users browser cache.
This is a common problem, to solve this browser cache issues you need to add some kind of unique identifier (hash/timestamp) to all your static files.
There are lot of backend framework which bundles your file, optimize it and add a unique hash to it which gets changed after any change in the original file.
Tools varies depending upon the back-end framework you are using. This is the ideal approach for handling this issue.
You can check gulp-rev, which is a really good library for re-visioning of your static assets.
To do it quickly, you can use an Interceptor on your main module, and append a version number to every request. You need to make sure that after every release you need to change the version number. The downside of this approach is, even the file which has not be changed will get refreshed.
yourModule.factory('cacheInterceptor',
['$templateCache', '$window', function ($templateCache, $window) {
var cacheInterceptor = {
request: function (request) {
if ($templateCache.get(request.url) === undefined) {
var appVersion = '';
appVersion = $window.MyApp.appVersion;
request.url = request.url + '?appVersion=' + appVersion;
}
return request;
}
};
return cacheInterceptor;
}]);
Note: Version number you need to assign on the window object every time the application loads.
You can find more details on Interceptors in AngularJS here
I am building an Angular app that uses long polling to receive fast updates whenever something changes on the server. I use $resource like this to fetch the actual data:
appServices.factory('Data', ['$resource',
function(){
return $resource('', {}, {
query: {"url": …, isArray: false}
});
}]);
Then I have a service that takes care of the long polling: Wait that the data are loaded; store them somewhere; after one second, start the next long-polling cycle:
app.factory(„DataLoader“, [„Data“, "$timeout", function(Data, $timeout) {
return {
loadData: function() {
var parent = this;
var data = Data.query({},
function(result) {
/* do something to the data,
* then start waiting for an update from the server again
*/
$timeout(function() {
parent.loadData();
}, 1000);
}
);
}
};
});
It works like a charm so far.
However, I am now trying to write Protractor tests for this. The problem is: The server times out the long polling requests after 30 seconds only if there are no changes to the data. As I am waiting for new data inside $timeout, Protractor times out before any results arrive.
I have googled the last hour, but there doesn't seem to be a solution except for using $interval instead of $timeout. This works in a good old polling setup (poll every 3 seconds, get empty results from the server if there's nothing new). However, to avoid exactly that, I implemented long polling. $timeout is just the much more sensible option for me.
Can you give me any tips how to get Protractor running successfully in this environment?
I would suggest taking a look at Protractor's documentation on timeouts. You will probably need to increase your allScriptsTimeout in your configuration file since the default wait for page synchronization is 11 seconds.
Use $interval angular api and $fetch for polling data continuously in your app
If you dont want to use $interval instead of $timeout; which is not a good practice,
then you have to turn off the browser synchronization with angular browser.waitForAngularEnabled(false) and use either browser.sleep() or browser.wait() to achieve synchronization between the elements that you interact with on the page.
Right now, I have a factory which loads a JSON file.
angular.module("app").factory("RolesFactory", ['$http', '$q', function($http, $q) {
var d = $q.defer();
$http.get('events.json').success(function(data) {
d.resolve(data);
});
return d.promise;
}]);
And then I call this factory when I need the contents of events.json with this controller:
App.controller('rolesCtrl', ['$scope', 'RolesFactory', function($scope, RolesFactory) {
RolesFactory.then(function(roleData){
$scope.roles = roleData.roles;
});
}]);
All good, but whenever I need to use this data. Isn't it refetching the contents of events.json? Meaning: is Angular reloading the file over and over again? I was hoping to load the file once and call it by a global variable or something.
When my app loads initially, I want it to load and store the contens of events.json -- and then I'd like my app to be able to use this data whenever/wherever.
Is this possible?
As AngularJS is a stateless framework, you have only a few options here, all of which are some kind of client-side caching:
Use localStorage to store your data. Once the data is fetched, you can just save it to localStorage using localStorage.setItem after Stringifying the JSON. You'll need to re-parse the JSON the next time you use it though, so if this is a giant JSON, this is not the best idea
Use sessionStorage to store your data. This is exactly the same as #1, but you will lose data upon termination of session,i.e. closing your browser.
Trust the JSON to be cached in your browser. This is most likely the case. Static assets are by default cached by most modern browsers. So, the second time your factory requests the JSON, the resource isn't actually fetched from the server. It is merely pulled from the browser's cache.
NOTE: The way to check this is to see what the HTTP status code for your resource is, in Chrome's Developer Tools Network tab. If the status says 304 that means it has been pulled from cache.
I'm using angular-ui.github.io/angular-google-maps/
I use the recommended lazy loading technique, I have this in my app.js:
.config(function(uiGmapGoogleMapApiProvider) {
uiGmapGoogleMapApiProvider.configure({
// key: 'your api key',
v: '3.20' //defaults to latest 3.X anyhow
//libraries: 'weather,geometry,visualization'
});
})
And at some point in my controller, I execute this:
var uiGmapGoogleMapApiTimer = $timeout(function() {
reject("uiGmapGoogleMapApi didn't respond after 10 seconds.");
}, 5000);
console.log('DUDE.01');
uiGmapGoogleMapApi.then(function(maps) {
console.log('DUDE.02');
$timeout.cancel(uiGmapGoogleMapApiTimer);
geocoder = new google.maps.Geocoder();
resolve(geocoder);
}, function(err) {
console.log('DUDE.03');
});
So, when I'm offline, the timer will kick in, and I send the user back to the login page. (Originally I simply exit the app. It works in android, but in iOS it doesnt work, it's in fact forbidden by Apple).
So... that's why now I'm sending it back to login page.
Now, in the login page, I reactivate my wifi.... and once I'm back in the page that (is supposed to) show the map.... it breaks. The success handler of uiGmapGoogleMapApi.then never gets called. (Dude.01 gets printed, but Dude.02 nor Dude.03 get printed).
So... that page (wrongly) thinks that the device is still disconnected.
I suppose it's because the loading of google map javascripts is only done once (during load -- that´s why if I close my app, and return back, things will run just fine).
So... it's not really lazy loading (?). Or... if it's lazy loading, it doesn't seem to support scenarios like... try loading it the second time (if the first time failed because of connectivity).
Is anyone familiar enough with the source code of angular-ui.github.io/angular-google-maps/ to suggest what's the solution for this problem?
I looked at the logs I put in the library's code... I came to the conclusion: I need way to get line 183 to be re-executed on the second time I call uiGmapGoogleMapApi.then ... Currently it doesn't. It only gets called the first, when I start my app, and having internet connection since the beginning.
And based on what I understand from this doc on "provider", I need the uiGmapGoogleMapApi to be reinstantiated (right before) the second time I try to use it.
https://docs.angularjs.org/api/auto/service/$provide
Is that right? How?
Looks like I'm battling against provider caching here. Because I use dependency injection in my controller to get reference to uiGmapGoogleMapApi. (I have .controller('myctrl', function(uiGmapGoogleMapApi) {...})
what I might need is:
.controller('myctrl', function() {
var uiGmapGoogleMapApi = $injector.get('uiGmapGoogleMapApi');
//or something along that line maybe
})
I just tried it, still doesn't work.
Please help.
Thanks,
Raka
Well, my "solution" is: instead of going to login page, I simply refresh the app., by setting the current url of the window object to index.html.
When does a Service / Factory retrieve data from an HTTP request?
When a factory is created in a service, I am curious as to when the HTTP request is sent, and how it is processed after the app is running for some time.
I'm writing my code using Ionic Framework. Once I initialize my app, and it stays open for a day or two, will the JSON data be refreshed at any interval? Or does it only refresh the data once the app is closed, and opened once again?
My requirement for the HTTP request, is that it is updated every day at the 00:01 AM.
I suppose my general question is: how does an HTTP request fetch data? And How does a service work in AngularJS.
Here is my code to retrieve a JSON package:
angular.module('starter.services', [])
.factory('menuJSON', function ($http) {
return {
all : function() {
return $http({
url: 'http://middmenuapi.herokuapp.com/',
method: 'GET'
})
}
}
});
Calls to $http() (or any of the aliases, such as $http.get() etc) invoke a web request immediately (barring any manipulation by inspectors or third-party components). It is analogous to issuing an XmlHttpRequest or JSONP request in other frameworks, like jQuery.
Services are created as singletons, so they are created once when they are first requested, and the same instance is injected from that point on. What the service does is entirely up to you, as Angular only deals with instantiating it, resolving any of its dependencies, and injecting it anywhere it's requested.
If you have an application that is running for long periods of time and needs to be updated with data, you'll need to architect it appropriately. Obviously I don't know the full requirements or particulars of your spec, but I can give you some hints to maybe get you going.
High level, it sounds like you need a function to operate on a timer (using the $timeout service), and if you meet or exceed a time window, invoke an $http request to retrieve the latest data and route it along to various components that need it. Then, it should mark the time frame it should next operate, then set a timeout again so it can wake further down the road and see if it's time to do work again.
The first thing to think about is where should this functionality live? If you only need it to happen in a certain controller, then you can do it all there in that controller using $timeout and $http. On the other hand, if you need to reuse this data in multiple places, you'll want to use a service. If you use a service, which is likely, then you need to figure out the best way to get those changes to the various parts of your app that need it.
My recommendation is to use Angular events on the $rootScope to $broadcast from your service when your $http request has updated data. Then, your various controllers, services, and directives that consume this data can subscribe to this event using $scope.$on and react appropriately. This keeps the service decoupled from the things that use it and allow them to react to changes easily.
All the service does is set a timeout, when it lapses check for data, if it has data, broadcast the data in an event on $rootScope, and set another timeout. The clients just listens and updates its local scope with the new data when it receives the event from the service.
This plunk contains a silly example. You'd want to change it to schedule work at a time of day or whatever you see fit, and then also have it make an $http request rather than send the current date.
angular.module("demo", [])
.service('myService', ['$rootScope', '$timeout', '$http', function($rootScope, $timeout, $http) {
var state = { timeout: null, next: null };
function work() {
var now = Date.now();
if (now >= state.next) { // you can replace with your own logic to schedule when it should occur (like a specific time of day). in this example, we poll every second, but do work every 5.
// this is where your $http service can do work, something like $http.get(...).success(function(data) { $rootScope.$broadcast('myService.data', data); });
$rootScope.$broadcast('myService.data', new Date());
state.next = now + 5000; // do work every five seconds
}
state.timeout = $timeout(work, 1000); // poll every second
}
return {
start: function() {
if (state.timeout) $timeout.cancel(state.timeout); // cancel pending timeout
work(); // first time will just schedule work to be done in the future
},
stop: function() {
if (state.timeout) $timeout.cancel(state.timeout); // cancel pending timeout
}
};
}])
.controller('DemoCtrl', ['$scope', function($scope) {
$scope.title = "Hello, World";
// here, the controller subscribes to the event, and when it occurs, it copies the event data to a local scope item
$scope.$on('myService.data', function(evt, data) {
$scope.$apply(function() {
$scope.myServiceData = data;
});
});
}])
.run(['myService', function(myService) {
myService.start(); // starts the service when the app runs
}]);