Configure restmod for submodule in AngularJS - angularjs

So I have a main module app defined as
app = angular.module("app", ['app.social_accounts', 'restmod'])
which has its restmod module configured:
app.config(function(restmodProvider) {
restmodProvider.rebase({
$config: {
primaryKey: "id",
style: "ams",
urlPrefix: "/app/"
}
});
});
and it works as expected: request were sent to http://localhost:8000/app/...
Now I want to use restmod in the submodule app.social_accounts, by doing
app = angular.module("app.social_accounts", ['restmod'])
app.config(function(restmodProvider) {
restmodProvider.rebase({
$config: {
primaryKey: "id",
style: "ams",
urlPrefix: "https://graph.facebook.com/"
}
});
});
app.factory("Album", ["restmod", function(restmod){
Album = restmod.model("/me/albums/")
return {
"get": function(){Album.$search()}
}
}])
namely I want to use absolute url in the submodule app.social_accounts.
But when I inject Album (registered under app.social_accounts) into a controller DashboardCtrl under app, the request were sent to http://localhost:8000/app/me/albums/.
So I wonder what is happening here and how to achieve a separate url for restmod under app.social_accounts?

Any configuration defined with restmodProvider is global for restmod irrespective of the module it's used in. So in your example above, the urlPrefix defined in the app.social_accounts module is being overwritten by the configuration in the app module.
In order to achieve the behaviour you expect, you can override the configuration on a per model basis:
angular.module('app.social_accounts', ['restmod'])
.factory('Album', function(restmod) {
var Album = restmod.model('/me/albums')
.mix({
$config: {
urlPrefix: 'https://graph.facebook.com/'
}
});
});
If you require the configuration in more than one model within a module, a mixin can be used to keep things DRY:
.factory('restmodConfigSocial', function(restmod) {
return restmod.mixin({
$config: {
urlPrefix: 'https://graph.facebook.com/'
}
});
})
.factory('Album', function(restmod) {
var Album = restmod.model('/me/albums').mix('restmodConfigSocial');
});

Related

Using Angular Service in MEANJS 0.4.2

I have a, maybe simple, problem. I worked with services in Angular before but now a ran into problems using a MEANJS Yeoman Generator project. What i need to to is to use data of an array from a specific module in another module, so that i can ng-repeat over this inside the view of the other model.
Where exactly do i bring in the array inside the service?
(function () {
'use strict';
angular
.module('patients')
.factory('PatientsService', PatientsService);
PatientsService.$inject = ['$resource'];
function PatientsService($resource) {
return $resource('api/patients/:patientId', {
patientId: '#_id'
}, {
update: {
method: 'PUT'
}
});
}
})();
I found nothing inside the MEANJS Doc so far and neither here (only from older MEANJS versions with another service structure).
Here is what i would like to bring inside the service:
// Shows a List of useable avatars on Patient creation
$scope.avatars = [
{ value:'1', name: 'modules/patients/client/img/avatar/avatar1.png' },
{ value:'2', name: 'modules/patients/client/img/avatar/avatar2.png' },
{ value:'3', name: 'modules/patients/client/img/avatar/avatar3.png' },
{ value:'4', name: 'modules/patients/client/img/avatar/avatar4.png' },
{ value:'5', name: 'modules/patients/client/img/avatar/avatar5.png' },
{ value:'6', name: 'modules/patients/client/img/avatar/avatar6.png' }
];
I would like to use the avatars in the home.client view an the PatientsService is already injected inside the home.client controller.
Your service above simply returns a $resource. Instead, the service could return a plain old Javascript object (or a class) that had various properties. Among them would be a property containing the array of avatars, and another containing the $resource:
(function () {
'use strict';
angular
.module('patients')
.factory('PatientsService', PatientsService);
PatientsService.$inject = ['$resource'];
function PatientsService($resource) {
return {
avatars: [ {value: 0, ... } ],
resource: $resource('api/patients/:patientId', {
patientId: '#_id'
}, {
update: {
method: 'PUT'
}
})
}
}
})();

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

making backbone models & collections available globally using requireJS

i am a newbie to web application development. i have a backbone model named LoginModel. I want to create an object of it and make it globally accessible from any Backbone View which will be loaded dynamically. Here is my model..
define(['underscore', 'backbone'], function(_, Backbone) {
LoginModel = Backbone.Model.extend({
initialize: function(){ },
defaults:{
userName: 'undefined',
userID: 'undefined'
},
urlRoot: 'https://xxxx.xx.xxxxxx',
parse: function(response, options){
return{
userName: response.userName,
userId:response.userId
};
}
});
});
You could pin the newly created object to an already existing global object that you're using, such as Backbone :
Backbone.Model.definitions = {
loginModel : Backbone.Model.extend({...})
}
and the use it as this :
new View({model : Backbone.Model.definitions.loignModel});
It may not be the shortest way, but it's cleaner than polluting the global namespace with different variables.
Rather than attaching to the Backbone.Model prototype or to the global window scope, I find it effective to attach it to a separate app object (provided by backbone-boilerplate and most other implementations).
You app object then can be required into any other module that requires access to the current user context.
app/app.js
define(function(require, exports, module) {
"use strict";
var app = module.exports;
// Initialize configuration and context objects
app.root = "/";
app.currentUser = null; //will be initialized in app/main.js
});
app/main.js
require(["config"], function() {
require(["app", "LoginModel", "router"], function(app, models, Router) {
app.currentUser = new LoginModel();
app.currentUser.fetch();
app.router = new Router();
})
});
Just create a global instance of the model, for example
var globalLoginModel = new LoginModel();
or
window.globalLoginModel = new LoginModel();
Then just pass it into any view that you want to use it in, for example
new View1({ model : globalLoginModel });
new View2({ model : globalLoginModel });
new View3({ model : globalLoginModel });
That should be it.
D

How to check internet connection in 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);
}
);
}
}

Problems with application startup and Backbone.Marionette Modules

Unfortunately, I've problems while understanding the startup of Backbone.Marionette modules and submodules. The initializers are called multiple times instead of being called one time each.
What do I need to do to make things work in foreseeable manner?
PP = new Backbone.Marionette.Application();
PP.bind('start', function() {
console.log('application start');
PP.module('Routing').start();
PP.module('Products').start();
});
PP.module('Routing', {
startWithApp: false,
define: function(Routing, PP, Backbone, Marionette, $, _) {
Routing.addInitializer(function() {
console.log('Routing.init');
});
}
});
PP.module('Routing.ProductsRouting', {
startWithApp: false,
define: function(ProductsRouting, PP, Backbone, Marionette, $, _) {
ProductsRouting.addInitializer(function() {
console.log('ProductsRouting.init');
});
}
});
PP.module('Products', {
startWithApp: false,
define: function(Products, PP, Backbone, Marionette, $, _) {
Products.addInitializer(function() {
console.log('Products.init');
});
}
});
$(function() {
PP.start();
});
(code also available as JSFiddle)
The code above outputs this lines in the console:
application start
Routing.init
ProductsRouting.init
Routing.init
ProductsRouting.init
Products.init
Products.init
And this is what I expected:
application start
Routing.init
Products.init
And if you decide to automatically start all the modules with your app (startWithApp: true in all modules and without manually starting Routing and Products modules) the output is this:
Routing.init
ProductsRouting.init
ProductsRouting.init
Products.init
application start
this is fixed w/ v0.9.7 https://github.com/derickbailey/backbone.marionette/blob/master/changelog.md#v097-view-commit-logs
The problem is solved by implementing this github pull request on Backbone.Marionette. But maybe Derick Bailey (creator of Backbone.Marionette) has his own opinions on this?
In case anyone is still having an issue with modules seeming to load in the wrong order - the solution for me was the location of Backbone.history.start().
Here was my problem:
bootstrap.js
App.start();
App.js
App = new Backbone.Marionette.Application();
var _AppRouter = Backbone.AppRouter.extend({
appRoutes: {
"" : "getStarted"
},
controller: App
});
App.getStarted = function() {
console.log(App.MyModule.myMethod); // undefined
App.MyModule.myMethod();
}
App.addInitializer(function() {
new _AppRouter();
Backbone.history.start();
});
App.MyModule.js
App.module("MyModule", function(MyModule, App) {
MyModule.myMethod = function() {
console.log("in myMethod"); // never gets called
}
});
App.MyModule.myMethod is undefined in this example, so nothing happens when the app starts.
The problem, I discovered, is where I was calling Backbone.history.start(). I moved this call to my bootstrap.js file, so that I'm only calling my routes after all of my app modules have been properly initialized.
bootstrap.js
App.start();
Backbone.history.start();
Easy peazy.

Resources