How to check internet connection in AngularJs - angularjs

This is how I would check internet connection in vanilla javascript:
setInterval(function(){
if(navigator.onLine){
$("body").html("Connected.");
}else{
$("body").html("Not connected.");
}
},1000);
I have angular controllers and modules in my project. Where should I put the code above? It should be executed in global context and not be assigned to a certain controller. Are there some kind of global controllers maybe?

First of all, I advise you to listen to online/offline events.
You can do it this way in AnguarJS:
var app = module('yourApp', []);
app.run(function($window, $rootScope) {
$rootScope.online = navigator.onLine;
$window.addEventListener("offline", function() {
$rootScope.$apply(function() {
$rootScope.online = false;
});
}, false);
$window.addEventListener("online", function() {
$rootScope.$apply(function() {
$rootScope.online = true;
});
}, false);
});
NOTE: I am wrapping changing of root scope's variable in $apply method to notify Angular that something was changed.
After that you can:
In controlller:
$scope.$watch('online', function(newStatus) { ... });
In HTML markup:
<div ng-show="online">You're online</div>
<div ng-hide="online">You're offline</div>
Here is a working Plunker: http://plnkr.co/edit/Q3LkiI7Cj4RWBNRLEJUA?p=preview
Other solution could be to broadcast online/offline event. But in this case you need to initialize current status upon loading and then subscribe to event.

It's definitely not as nice, but you could just try an AJAX request to your web server; it'll either succeed or time out.
Also, the HubSpot/offline project looks really good.

Your options:
addEventListener on the window, document, or document.body.
setting the .ononline or .onoffline properties on document or
document.body to a JavaScript Function object.
specifying ononline="..." or onoffline="..." attributes on the tag in
the HTML markup
I will demonstrate the easiest.
In you controller
document.body.onoffline = function() {
alert('You are offline now');
$scope.connection = 'offline'
}
document.body.ononline = function() {
alert('You are online again');
$scope.connection = 'online'
}
Check $scope.connection variable before you try to send requests around.

For Angular 2+ you can use ng-speed-test:
Just install:
npm install ng-speed-test --save
Inject into your module:
import { SpeedTestModule } from 'ng-speed-test';
#NgModule({
...
imports: [
SpeedTestModule,
...
],
...
})
export class AppModule {}
Use service to get speed:
import {SpeedTestService} from 'ng-speed-test';
#Injectable()
export class TechCheckService {
constructor(
private speedTestService:SpeedTestService
) {
this.speedTestService.getMbps().subscribe(
(speed) => {
console.log('Your speed is ' + speed);
}
);
}
}

Related

Implementing notification alerts in angularjs

I was wondering how an error alert would be implemented using angularjs.
Required functionality:
An alertQueue consists of all the alerts to be displayed to the user. These alerts are deleted from the queue after a span of 3 seconds. The user himself can close the alert by clicking the close button.
This AlertService must be the core service. Alerts are rendered in the view as <alert-list></alert-list>i.e using a component alertList.
Should be able to update alerts from other controllers like: AlertService.alert("my alert").
so far what I have done?
angular.
module('core').
factory('AlertService', [function() {
var alertQueue = [];
var addAlert = function(message, type){
message = {message: message, type: type};
alertQueue.push(message)
};
var deleteAlert = function(alert){
alertQueue.splice(alertQueue.indexOf(alert), 1);
};
return{
warning: function(msg){
addAlert(msg, "warning");
},
success: function(msg){
addAlert(msg, "success");
},
removeAlert: function(alert){
deleteAlert(alert);
},
getAlerts: function(){
return alertQueue;
}
}
}]);
angular.
module('alertApp').
component('alertList', {
templateUrl: '/static/js/app/aurora-alert/aurora-alert.template.html',
controller: ['$routeParams','$scope', 'Aurora',
function AlertController($routeParams, $scope, AlertService) {
var self = this;
self.alertQueue = AlertService.alertQueue;
self.alert = function(){
var message = arguments[0];
AlertService.warning(message);
};
self.removeAlert = function(alert) {
AlertService.removeAlert(alert);
};
}
]
});
I know that I'm doing something wrong in the above code and in its logic. I said above that I require the <alert-list></alert-list> component. So the alertService is injected as a dependency into alertController. But how am I going to raise the alert from other controllers? I know we can use $scope.$broadcast but that doesn't feel right.
Please explain how to achieve this? No third party libraries are to be used.
I think you are going about it only slightly incorrectly. Your alert-list should be responsible only for displaying and removing alerts, not for creating them. Leave the creation of alerts to your controllers
So for example, if you run into an error with an ApiSerivce:
DemoCtrl(AlertService, ApiService) {
ApiService.submitForm({some:data}).then(function() {
//something successfull happened
}).catch(function(error) {
AlertService.warning("Something bad happened calling the API serivce");
});
}
Then you can change your AlertService to broadcast an event when a new alert is created that the alert-list can listen to:
factory('AlertService', ["$rootScope", function($rootScope) {
var alertQueue = [];
var addAlert = function(message, type){
message = {message: message, type: type};
alertQueue.push(message)
$rootScope.$broadcast("new-alert"); //notify the list that there are new alerts
};
This is how you would listen to it in your alert-list:
$scope.$on("new-alert", function() {
self.alertQueue = AlertService.alertQueue;
});
This way, as soon as an alert is created, the alert-list is instantly updated with the latest queue of alerts.
You would probably want to do the same thing for alert deletion.

Angular Leaflet Directive Not updating marker position

I'm trying to use angular-leaflet-directive with Websocket, though I'm able to integrate successfully, the positions of the markers are not getting updated dynamically. However The positions of map gets updated if I move mouse over the map but doesn't get updated when the lat-lng value changes.
Below is code snippet of module.
$scope.markers = {};
angular.extend($scope, {
bounds : $scope.bounds,
center : {},
kppaths : {},
events: {
markers:{
enable: [ 'move' ]
}
}
});
$stomp.setDebug(function(args) {
$log.info(args);
});
$scope.startWS = function() {
var connectionHeaders = {};
// Connect
$stomp.connect("/kp-ws").then(function(frame){
$log.info("connected to server")
$stomp.send('/app/start', {});
// Subscribe for message
$scope.subscription = $stomp.subscribe('/topic/kp', function(
data, headers, res) {
angular.forEach(data, function(k,v){
$scope.markers[k.markerId].lat = k.lat;
$scope.markers[k.markerId].lng = k.lng;
});
});
});
};
$scope.stopWS = function() {
$stomp.send('/app/stop', {});
$scope.subscription.unsubscribe();
$stomp.disconnect();
};
$scope.$on("leafletDirectiveMarker.move", function(event, args){
$log.info(args.model.lat);
});
} ]);
The html file
<div class="card-block">
<leaflet bounds="bounds" geojson="geojson" lf-center="center"
paths="kppaths" markers="markers" event-broadcast="events" width="100%" height="480px"></leaflet>
</div>
Is I'm missing something, Please let me know or suggest how to fix this issue?
The possible workaround I found is:
leafletData.getMap().then(function (map) {
$timeout(function() {map.invalidateSize()});
});
basically, once the map is invalidated, it updates markers' position. Although not perfect, considering some performance issues, the workaround at least solves the main issue.

How to change skin and make it persistant with an angularjs factory?

I want to create a form for the user to pick the skin he wants among a series.
I provide the factory Config to keep track of his choice thru routes.
The factory provides a way to save the config in cookies thru $scope.$watch('config.skin', function(){}) mechanism in order to preserve his choice thru multiple sessions.
The factory is as follows:
app.factory("Config",function($cookies){
console.log("Factory Config…");
return {
config: {
skin: "Gray"
},
save: function(s) {
console.log("Config.save() "+mydump(s,2));
this.config = s;
$cookies.config = JSON.stringify(this.config);
},
load: function() {
if ($cookies.config) {
try {
this.config = JSON.parse($cookies.config);
console.log("App controller: read config from cookies as: ");
for (var i in this.config) {
console.log ("— "+i+" = "+this.config[i]);
}
} catch(e) {
config = null;
}
}
if (!this.config) {
this.config = {"skin": "Gray"};
console.log("App controller: init config from controler ("+this.config+")");
}
return this;
}
};
});
The Config replaces the $scope.config in the controller.
The skin switching is provided thru a ng-class as follows:
<div ng-controller="myCtrl" ng-class="{'skin{{config.skin}}':true}">
<!-- more html -->
</div>
Currently, though my ng-class is updated by the $scope.config.skin as expected, the class itself is not, though not achieving the execpected overall feature.
Any idea?
I've provided a fiddle that demonstrates the issue: http://jsfiddle.net/stephanedeluca/SeUY7/
Interpolation won't work here. Instead, use:
<div ng-controller="myCtrl" ng-class="'skin' + config.skin">
Working fork of your Fiddle

Inject module dynamically, only if required

I'm using Require.js in combination with Angular.js.
Some controllers need huge external dependencies which others don't need, for example, FirstController requires Angular UI Codemirror. That's a extra 135 kb, at least:
require([
"angular",
"angular.ui.codemirror" // requires codemirror itself
], function(angular) {
angular.module("app", [ ..., "ui.codemirror" ]).controller("FirstController", [ ... ]);
});
I don't want to have to include the directive and the Codemirror lib everytime my page loads just to make Angular happy.
That's why I'm right now loading the controller only when the route is hit, like what's done here.
However, when I need something like
define([
"app",
"angular.ui.codemirror"
], function(app) {
// ui-codemirror directive MUST be available to the view of this controller as of now
app.lazy.controller("FirstController", [
"$scope",
function($scope) {
// ...
}
]);
});
How can I tell Angular to inject ui.codemirror module (or any other module) in the app module aswell?
I don't care if it's a hackish way to accomplish this, unless it involves modifying the code of external dependencies.
If it's useful: I'm running Angular 1.2.0.
I have been trying to mix requirejs+Angular for some time now. I published a little project in Github (angular-require-lazy) with my effort so far, since the scope is too large for inline code or fiddles. The project demonstrates the following points:
AngularJS modules are lazy loaded.
Directives can be lazy loaded too.
There is a "module" discovery and metadata mechanism (see my other pet project: require-lazy)
The application is split into bundles automatically (i.e. building with r.js works)
How is it done:
The providers (e.g. $controllerProvider, $compileProvider) are captured from a config function (technique I first saw in angularjs-requirejs-lazy-controllers).
After bootstraping, angular is replaced by our own wrapper that can handle lazy loaded modules.
The injector is captured and provided as a promise.
AMD modules can be converted to Angular modules.
This implementation satisfies your needs: it can lazy-load Angular modules (at least the ng-grid I am using), is definitely hackish :) and does not modify external libraries.
Comments/opinions are more than welcome.
(EDIT) The differentiation of this solution from others is that it does not do dynamic require() calls, thus can be built with r.js (and my require-lazy project). Other than that the ideas are more or less convergent across the various solutions.
Good luck to all!
Attention: use the solution by Nikos Paraskevopoulos, as it's more reliable (I'm using it), and has way more examples.
Okay, I have finally found out how to achieve this with a brief help with this answer.
As I said in my question, this has come to be a very hacky way. It envolves applying each function in the _invokeQueue array of the depended module in the context of the app module.
It's something like this (pay more attention in the moduleExtender function please):
define([ "angular" ], function( angular ) {
// Returns a angular module, searching for its name, if it's a string
function get( name ) {
if ( typeof name === "string" ) {
return angular.module( name );
}
return name;
};
var moduleExtender = function( sourceModule ) {
var modules = Array.prototype.slice.call( arguments );
// Take sourceModule out of the array
modules.shift();
// Parse the source module
sourceModule = get( sourceModule );
if ( !sourceModule._amdDecorated ) {
throw new Error( "Can't extend a module which hasn't been decorated." );
}
// Merge all modules into the source module
modules.forEach(function( module ) {
module = get( module );
module._invokeQueue.reverse().forEach(function( call ) {
// call is in format [ provider, function, args ]
var provider = sourceModule._lazyProviders[ call[ 0 ] ];
// Same as for example $controllerProvider.register("Ctrl", function() { ... })
provider && provider[ call[ 1 ] ].apply( provider, call[ 2 ] );
});
});
};
var moduleDecorator = function( module ) {
module = get( module );
module.extend = moduleExtender.bind( null, module );
// Add config to decorate with lazy providers
module.config([
"$compileProvider",
"$controllerProvider",
"$filterProvider",
"$provide",
function( $compileProvider, $controllerProvider, $filterProvider, $provide ) {
module._lazyProviders = {
$compileProvider: $compileProvider,
$controllerProvider: $controllerProvider,
$filterProvider: $filterProvider,
$provide: $provide
};
module.lazy = {
// ...controller, directive, etc, all functions to define something in angular are here, just like the project mentioned in the question
};
module._amdDecorated = true;
}
]);
};
// Tadaaa, all done!
return {
decorate: moduleDecorator
};
});
After this has been done, I just need, for example, to do this:
app.extend( "ui.codemirror" ); // ui.codemirror module will now be available in my application
app.controller( "FirstController", [ ..., function() { });
The key to this is that any modules your app module depends on also needs to be a lazy loading module as well. This is because the provider and instance caches that angular uses for its $injector service are private and they do not expose a method to register new modules after initialization is completed.
So the 'hacky' way to do this would be to edit each of the modules you wish to lazy load to require a lazy loading module object (In the example you linked, the module is located in the file 'appModules.js'), then edit each of the controller, directive, factory etc calls to use app.lazy.{same call} instead.
After that, you can continue to follow the sample project you've linked to by looking at how app routes are lazily loaded (the 'appRoutes.js' file shows how to do this).
Not too sure if this helps, but good luck.
There is a directive that will do this:
https://github.com/AndyGrom/loadOnDemand
example:
<div load-on-demand="'module_name'"></div>
The problem with existing lazy load techniques is that they do things which I want to do by myself.
For example, using requirejs, I would like to just call:
require(['tinymce', function() {
// here I would like to just have tinymce module loaded and working
});
However it doesn't work in that way. Why? As I understand, AngularJS just marks the module as 'to be loaded in the future', and if, for example, I will wait a bit, it will work - I will be able to use it. So in the function above I would like to call some function like loadPendingModules();
In my project I created simple provider ('lazyLoad') which does exactly this thing and nothing more, so now, if I need to have some module completely loaded, I can do the following:
myApp.controller('myController', ['$scope', 'lazyLoad', function($scope, lazyLoad) {
// ........
$scope.onMyButtonClicked = function() {
require(['tinymce', function() {
lazyLoad.loadModules();
// and here I can work with the modules as they are completely loaded
}]);
};
// ........
});
here is link to the source file (MPL license):
https://github.com/lessmarkup/less-markup/blob/master/LessMarkup/UserInterface/Scripts/Providers/lazyload.js
I am sending you sample code. It is working fine for me. So please check this:
var myapp = angular.module('myapp', ['ngRoute']);
/* Module Creation */
var app = angular.module('app', ['ngRoute']);
app.config(['$routeProvider', '$controllerProvider', function ($routeProvider, $controllerProvider) {
app.register = {
controller: $controllerProvider.register,
//directive: $compileProvider.directive,
//filter: $filterProvider.register,
//factory: $provide.factory,
//service: $provide.service
};
// so I keep a reference from when I ran my module config
function registerController(moduleName, controllerName) {
// Here I cannot get the controller function directly so I
// need to loop through the module's _invokeQueue to get it
var queue = angular.module(moduleName)._invokeQueue;
for (var i = 0; i < queue.length; i++) {
var call = queue[i];
if (call[0] == "$controllerProvider" &&
call[1] == "register" &&
call[2][0] == controllerName) {
app.register.controller(controllerName, call[2][1]);
}
}
}
var tt = {
loadScript:
function (path) {
var result = $.Deferred(),
script = document.createElement("script");
script.async = "async";
script.type = "text/javascript";
script.src = path;
script.onload = script.onreadystatechange = function (_, isAbort) {
if (!script.readyState || /loaded|complete/.test(script.readyState)) {
if (isAbort)
result.reject();
else {
result.resolve();
}
}
};
script.onerror = function () { result.reject(); };
document.querySelector(".shubham").appendChild(script);
return result.promise();
}
}
function stripScripts(s) {
var div = document.querySelector(".shubham");
div.innerHTML = s;
var scripts = div.getElementsByTagName('script');
var i = scripts.length;
while (i--) {
scripts[i].parentNode.removeChild(scripts[i]);
}
return div.innerHTML;
}
function loader(arrayName) {
return {
load: function ($q) {
stripScripts(''); // This Function Remove javascript from Local
var deferred = $q.defer(),
map = arrayName.map(function (obj) {
return tt.loadScript(obj.path)
.then(function () {
registerController(obj.module, obj.controller);
})
});
$q.all(map).then(function (r) {
deferred.resolve();
});
return deferred.promise;
}
};
};
$routeProvider
.when('/first', {
templateUrl: '/Views/foo.html',
resolve: loader([{ controller: 'FirstController', path: '/MyScripts/FirstController.js', module: 'app' },
{ controller: 'SecondController', path: '/MyScripts/SecondController.js', module: 'app' }])
})
.when('/second', {
templateUrl: '/Views/bar.html',
resolve: loader([{ controller: 'SecondController', path: '/MyScripts/SecondController.js', module: 'app' },
{ controller: 'A', path: '/MyScripts/anotherModuleController.js', module: 'myapp' }])
})
.otherwise({
redirectTo: document.location.pathname
});
}])
And in HTML Page:
<body ng-app="app">
<div class="container example">
<!--ng-controller="testController"-->
<h3>Hello</h3>
<table>
<tr>
<td>First Page </td>
<td>Second Page</td>
</tr>
</table>
<div id="ng-view" class="wrapper_inside" ng-view>
</div>
<div class="shubham">
</div>
</div>

UI Notifications with angular js

I have to implement some standard notification UI with angular js. My approach is the following (simplified):
<div ng-controller="MainCtrl">
<div>{{message}}</div>
<div ng-controller="PageCtrl">
<div ng-click="showMessage()"></div>
</div>
</div>
And with the page controller being:
module.controller("PageCtrl", function($scope){
counter = 1
$scope.showMessage = function(){
$scope.$parent.message = "new message #" + counter++;
};
});
This works fine. But I really don't like the fact that I need to call $scope.$parent.
Because if I am in another nested controller, I will have $scope.$parent.$parent, and this becomes quickly a nightmare to understand.
Is there another way to create this kind of global UI notification with angular?
Use events to send messages from one component to another. That way the components don't need to be related at all.
Send an event from one component:
app.controller('DivCtrl', function($scope, $rootScope) {
$scope.doSend = function(){
$rootScope.$broadcast('divButton:clicked', 'hello world via event');
}
});
and create a listener anywhere you like, e.g. in another component:
app.controller('MainCtrl', function($scope, $rootScope) {
$scope.$on('divButton:clicked', function(event, message){
alert(message);
})
});
I've created a working example for you at http://plnkr.co/edit/ywnwWXQtkKOCYNeMf0FJ?p=preview
You can also check the AngularJS docs about scopes to read more about the actual syntax.
This provides you with a clean and fast solution in just a few lines of code.
Regards,
Jurgen
You should check this:
An AngularJS component for easily creating notifications. Can also use HTML5 notifications.
https://github.com/phxdatasec/angular-notifications
After looking at this: What's the correct way to communicate between controllers in AngularJS? and then that: https://gist.github.com/floatingmonkey/3384419
I decided to use pubsub, here is my implementation:
Coffeescript:
module.factory "PubSub", ->
cache = {}
subscribe = (topic, callback) ->
cache[topic] = [] unless cache[topic]
cache[topic].push callback
[ topic, callback ]
unsubscribe = (topic, callback) ->
if cache[topic]
callbackCount = cache[topic].length
while callbackCount--
if cache[topic][callbackCount] is callback
cache[topic].splice callbackCount, 1
null
publish = (topic) ->
event = cache[topic]
if event and event.length>0
callbackCount = event.length
while callbackCount--
if event[callbackCount]
res = event[callbackCount].apply {}, Array.prototype.slice.call(arguments, 1)
# some pubsub enhancement: we can get notified when everything
# has been published by registering to topic+"_done"
publish topic+"_done"
res
subscribe: subscribe
unsubscribe: unsubscribe
publish: publish
Javascript:
module.factory("PubSub", function() {
var cache, publish, subscribe, unsubscribe;
cache = {};
subscribe = function(topic, callback) {
if (!cache[topic]) {
cache[topic] = [];
}
cache[topic].push(callback);
return [topic, callback];
};
unsubscribe = function(topic, callback) {
var callbackCount;
if (cache[topic]) {
callbackCount = cache[topic].length;
while (callbackCount--) {
if (cache[topic][callbackCount] === callback) {
cache[topic].splice(callbackCount, 1);
}
}
}
return null;
};
publish = function(topic) {
var callbackCount, event, res;
event = cache[topic];
if (event && event.length > 0) {
callbackCount = event.length;
while (callbackCount--) {
if (event[callbackCount]) {
res = event[callbackCount].apply({}, Array.prototype.slice.call(arguments, 1));
}
}
publish(topic + "_done");
return res;
}
};
return {
subscribe: subscribe,
unsubscribe: unsubscribe,
publish: publish
};
});
My suggestion is don't create a one on your own. Use existing models like toastr or something like below.
http://beletsky.net/ng-notifications-bar/
As suggested above, try to use external notifications library. There're a big variety of them:
http://alertifyjs.com/
https://notifyjs.com/
https://www.npmjs.com/package/awesome-notifications
http://codeseven.github.io/toastr/demo.html

Resources