Can we have multiple application under single umbrella in angular - angularjs

I need to design a application where i have 1 parent application and under that application I have more 5 more application .
for eg.
Parent
-- child1
-- child2
-- child3
and based on user subscription i have to enable only those applications that user subscribed for.
Each child application has its own UI/UX based on user choice (like theme icons , logo etc.) .

Angular doesn't have the concept of "app" or "application", because a good (better) practice is always to have one app running at a time. To quote from the docs:
While it's possible to bootstrap more than one AngularJS application per page, we don't actively test against this scenario. It's possible that you'll run into problems, especially with complex apps, so caution is advised.
But that doesn't mean you can't customize your app, because Angular provides abstractions through other different ways.
One good way to do it is to model your application into multiple modules and use the handy Depedency Injection pattern. Taking your scenario as an example, you have a Parent module which is the overall governing module to bootstrap the application, and Child1, Child2 and Child3 modules that is injectable into Parent module based on the user configuration. Something like this:
(function() {
//declare the child modules:
angular.module('child1', []);
angular.module('child2', []);
angular.module('child3', []);
//User Settings, set by server configuartion .
var userSettings = {
"userId": 1,
"modules": ['child1', 'child3']
};
//bootstrapping the Parent module, where only child1 and child3 module is injected
angular.module('Parent',[userSettings.modules])
})();
For the above method, you would need a really good architectural structure to keep track of what is injected and what is not, so that your development work can be at ease and you don't keep running into $injector:unpr error.
Another good way to do your configuration settings is at, well.. at the config phase. At config phase - where you inject all the providers, you can have literally all the free will to "configure" your app. The only hard part is you will have to write your modules and providers in such a way it is configurable. A lot of 3rd party Angular modules provides such flexibility. UI Bootstrap is one of them. Say for example, I let the user have the flexibility to either "show weeks" in ui.bootstrap's calendar,or to hide it. I could have written my code as below:
//User Settings, set by server configuartion .
var userSettings = {
"userId": 1,
"modules": ['child1', 'child3'],
"showWeeks": false
};
angular.module('Parent')
.config(['datepickerConfig', function(datepickerConfig) {
datepickerConfig.showWeeks = userSettings.showWeeks;
}]);
Oh, you mentioned about UI/UX changes?
For me, I would really want to do that in CSS and not at angular though, unless really necessary. Use CSS preprocessors, either SASS or LESS is good, where by you can write your CSS programitcally. You can write a customizable .scss or .less file, and then simply call #import and you are good to go. Of course, you can combine both the power of preproccesor and Angular's config phase. Angular Material for instance, let's you choose the pallete color via their provider functions:
angular.module('myApp', ['ngMaterial'])
.config(function($mdThemingProvider) {
$mdThemingProvider.theme('default')
.primaryPalette('pink') //choose the primary color as pink!
.accentPalette('orange'); //choose the accent color to be orange!
});
As you can see, it really boils down on how you want to architect your code base, and to what extent you wanna give the flexibility to let the user customize the app. Don't forget about server side configuration too (user credentials, DB connection strings, etc)! There is no right or wrong answers here, just which one you are more comfortable :)

Related

Multilingual with multiple app and 1 translationService

I'm currently make a html page by using angularjs.
I have 1 html page, with 1 sidebar, 1 navigation bar and 1 content area.
Like this : AdminLTE
I've follow this instruction : this
And successfully, my app works ok.
But I don't know how to apply multilingual function to my every app.
For example : Navigationbar is 1 app, sidebar is 1 app and main content is 1 app.
How can I apply 1 translationService to 'em without downloading json again and again ?
Can anyone help me please ? Thank you.
I still think it would be better to have one application for the whole page, but have separate controllers for the nav, sidebar, and main content. That way they all work separately, but you don't have the awkwardness of dealing with separate apps. The only reason I can think of to have separate apps is if you want to make sure that services are NEVER shared between the different parts. However, in your case, it looks like you WANT to share the translate service, so I think it makes sense to use one app.
If you really want to have multiple apps, it is still possible. You can load the translations asynchronously, then when this is done, you call angular.module() for each app and inject the translations as a constant. Then, when you configure the translate provider, you can inject your translation constant just like you would inject any service.
I have done this in an application before, but I don't have access to the code right now. I did it for a single application, but you can easily extend it to multiple applications. I believe it looked similar to this:
var $http = angular.injector().get('$http');
var $q = angular.injector().get('$q');
var promises = [
$http.get('path/to/translations/en.json'),
$http.get('path/to/translations/fr.json'),
];
$q.all(promises)
.then(function(translations) {
angular.module('app', [])
.constant('translations_en', translations[0])
.constant('translations_fr', translations[1])
.config(['$translateProvider', 'translations_en', 'translations_fr',
function($translateProvider, translations_en, translations_fr) {
$translateProvider.translations('en', translations_en);
$translateProvider.translations('fr', translations_fr);
}]);
angular.bootstrap(element, ['app']);
});
For multiple apps, you would need to run the angular.module block once for each app.
Alternatively, you could define separate modules for each part, then define a parent module that depends on the other mini-modules, i.e.
angular.module('navigation', []);
angular.module('sidebar', []);
angular.module('mainPage', []);
angular.module('app', ['navigation', 'sidebar', 'mainPage']);
angular.bootstrap(element, ['app']);
I believe that all modules would share the same translate service in this case.

#section syntax instead of requirejs or browserify for angularjs application

I understand that requirejs and browserify can load my files dependent on its current context, and that it is amazing. I would really prefer to use the #section sections syntax that the razor engine uses. Was just wondering if there is a way to implement this into a typescript / angularjs application.
for example
index.html
#renderSection scripts;
// which could turn into something like
<script data-render="scripts"></scripts>
// the app.run() could declare all the scripts that will be needed on every
// page view
view.html
<script ng-section-repeat="injected in injection"></script>
// the ng-section-repeat is basically taking all the items in the
// typescript constructor and then finding out which ones are needed for
// that view.
I like the idea injecting application file dependencies in the view , without a configuration file and all the added extras that comes with the loaders.
I just want to easily define what files are needed in the actual view and get them loaded, with angular's dependency injection handling the dependency itself.
If you are handling all your dependencies with $inject then , as far as i can tell, dependency is technically already setup in the controllers, all one would need, is to load this as it is called. Which could even eliminate the need for the #section scripts completely
Update:
What i have done to sort of replicate the module loaders is to just use gulp-concat and define the file order in my gulp.config.js and then pass it to the gulp-src before running $.concat .this allows me to have the files in the gulp steam , in dependent order . They are however loaded on the first load. With gulp-uglify the files are tiny ( its now at 566Kb with 16 external libraries loading in 69ms . To put that into perspective it takes 209ms to load one google font ).
I dont know maybe i am not understanding browserify correctly but i honestly struggle to see the need for it, its seems extremely convoluted for something so simple
It is possible using external modules and an injector to do what you asked for:
I just want to easily define what files are needed in the actual view
import {UserFactory} from 'models/userFactory';
import {UserValidator} from 'models/userValidator';
import {Inject} from 'angular2/di';
and get them loaded, with angular's dependency injection handling the dependency itself.
Note: My example uses angular 2.x because I less familiar with angular 1.x and I'm sure you can do something really similar...
class SomeComponent {
userName: string;
userRating: number;
rating: number;
constructor(
#Inject(UserFactory) UserFactory
#Inject(UserValidator) UserValidator
)
{
this.UserFactory = UserFactory;
this.UserValidator = UserValidator;
}
}
Then you can use Browserify to create a bundle.js file that can be executed in a web browser.

Angular translate extend existing translations

I am trying to have external modules change my $translateProvider.translation on the main module. see this as a "tranlation plugin" for my app.
it seems like changing translations from the $translate service is not possible.
mymodule.service('MyService', function ($translateProvider) {
var lib = function () {
//EDITED FOR BREVITY
this._registerTranslations = function (ctrl) {
if (!ctrl.i18n) return;
for (var name in ctrl.i18n) {
/////////////////////////////
// THIS IS THE PLACE, OBVIOUSLY PROVIDER IS NOT AVAILABLE!!!!
$translateProvider.translations(name, ctrl.i18n[name]);
//////////////////////////////
}
};
//EDITED FOR BREVITY
};
return new lib();
});
anyone with a bright idea?
So, to answer your question: there's no way to extend existing translations during runtime with $translate service without using asynchronous loading. I wonder why you want to do that anyway, because adding translations in such a way means that they are already there (otherwise you would obviously use asynchronous loading).
Have a look at the Asynchronous loading page. You can create a factory that will load a translation from wherever you want.
I created an Angular constant to hold new translations. If I want to add a new translation, I add it to the constant. Then in my custom loader, I first check the constant to see if the translation exists (either a new one, or an updated one). If so, I load it from the constant. If not, I load it from a .json file (or wherever you load your initial translations from). Use $translate.refresh() to force translations to be reloaded and reevaluated.
Demo here
The demo is pretty simple. You would need to do a little more work if you wanted to just change a subset of the translations, but you get the general idea.
From the AngularJS docs (https://docs.angularjs.org/guide/providers):
You should use the Provider recipe only when you want to expose an API for application-wide configuration that must be made before the application starts. This is usually interesting only for reusable services whose behavior might need to vary slightly between applications.
Providers are to be used with the application's .config function. $translateProvider for configuration, $translate for other services and controllers.

UI testing an ExtJS webapp using CasperJS/PhantomJS

I'm working on UI testing an ExtJS web-app, and I'm a beginner.
I am trying to test the ExtJS widgets by using CasperJS/PhantomJS tool.
Also, I generate the required CasperJs script using Resurrectio and by making necessary changes to it.
Since ExtJs generates unique ids dynamically for the DOM elements that it creates, I want to know how to provide those ids in CasperJs script for testing.
For example, The following Casper Script was generated by Resurrectio:
casper.waitForSelector("#ext-gen1142 .x-tree-icon.x-tree-icon-parent",
function success() {
test.assertExists("#ext-gen1142 .x-tree-icon.x-tree-icon-parent");
this.click("#ext-gen1142 .x-tree-icon.x-tree-icon-parent");
},
function fail() {
test.assertExists("#ext-gen1142 .x-tree-icon.x-tree-icon-parent");
});
casper.waitForSelector("#gridview-1038",
function success() {
test.assertExists("#gridview-1038");
this.click("#gridview-1038");
},
function fail() {
test.assertExists("#gridview-1038");
});
Here #ext-gen1142 and #gridview-1038 are the ids dynamically created. How should one provide data in the tests? Is there any stub or mocking tools which works with ExtJs in the code to provide these ids at runtime during tests?
I came across SinonJS. Can it be used or Do I need to used CSS or XPath Locators as mentioned in this answer? How reliable it is to use CSS or Xpath Locators?
Thanks in advance!
Not so easy to answer this, but here a few thoughts...
Don't rely on generated IDs. Never. They'll change in moments you won't like and if you have luck very much earlier.
Your best friends will probably be pseudo CSS classes you attach to your components. You could also use IDs, but this is only reasonable when you have elements which occur only once in your page. If that is the case, they are very good anchors to start with selections/queries.
XPath with ExtJS is possible, but you have to carefully choose the elements. ExtJS is so verbose in generating little things so your paths can be quite complicated. And when Sencha drops support for problematic browsers (IE < 8) maybe they change their templates and your XPath doesn't find anything.
SinonJS is great. But it won't help you much in DOM problems. But sure you can use it in your tests. I suppose it will payoff most in testing parts of your controllers or non-trivial models.
Model your test components after your real UI components and screen sections. Don't just record a script. Test code should be engineered like production code. If you create reusable components of test code and logic, you don't have to fear changes. In the best case the changes in one component will only touch the testing code of that particular component.
I know you have ExtJS. But take some time to look at AngularJS and see how easy it can be to test all parts of a JavaScript web application. I'm not saying you should switch to AngularJS, but you can learn a lot. Have a look at Deft JS as it has many concepts which enhance testability of ExtJS applications.
I use Siesta for my ExtJs testing. It works amazingly good for all JavaScript (jQuery based and others), but is specifically designed for ExtJS/Sencha Touch.
It has the feature to combine CSSquery and ComponentQuery to select your elements I think that will fix a lot of problems for you.
In the paid version there is even a test recorder to record scenario's and use them for your tests.
Here's a demo
Here's some sample code:
StartTest(function(t) {
t.chain(
{ waitFor : 'CQ', args : 'gridpanel' },
function(next, grids) {
var userGrid = grids[0];
t.willFireNTimes(userGrid.store, 'write', 1);
next();
},
{ waitFor : 'rowsVisible', args : 'gridpanel' },
{ action : 'doubleclick', target : 'gridpanel => .x-grid-cell' },
// waiting for popup window to appear
{ waitFor : 'CQ', args : 'useredit' },
// When using target, >> specifies a Component Query
{ action : 'click', target : '>>field[name=firstname]'},
function(next) {
// Manually clear text field
t.cq1('field[name=firstname]').setValue();
next();
},
{ action : 'type', target : '>>field[name=firstname]', text : 'foo' },
{ action : 'click', target : '>>useredit button[text=Save]'},
function(next) {
t.matchGridCellContent(t.cq1('gridpanel'), 0, 0, 'foo Spencer', 'Updated name found in grid');
}
);
})

Backbone Marionette using Require.js, Regions and how to set up

I'm currently writing a Backbone Marionette app which ultimately amounts to about 6 different "screens" or pages which will often times share content and I am unsure of how to best structure and access Regions.
I am using the app/module setup described here: StackOverflow question 11070408: How to define/use several routings using backbone and require.js. This will be an application which will have new functionality and content added to it over time and need to be scalable (and obviously as re-usable as possible)
The Single Page App I'm building has 4 primary sections on every screen: Header, Primary Content, Secondary Content, Footer.
The footer will be consistent across all pages, the header will be the same on 3 of the pages, and slightly modified (using about 80% of the same elements/content) on the remaining 3 pages. The "morecontent" region will be re-usable across various pages.
In my app.js file I'm defining my regions like so:
define(['views/LandingScreen', 'views/Header', 'router'], function(LandingScreen, Header, Router) {
"use strict";
var App = new Backbone.Marionette.Application();
App.addRegions({
header: '#mainHeader',
maincontent: '#mainContent',
morecontent: '#moreContent',
footer: '#mainFooter'
});
App.addInitializer(function (options) {
});
App.on("initialize:after", function () {
if (!Backbone.History.started) Backbone.history.start();
});
return App;
});
Now, referring back to the app setup in the aforementioned post, what would be the best way to handle the Regions. Would I independently re-declare each region in each sub-app? That seems to be the best way to keep modules as independent as possible. If I go that route, what would be the best way to open/close or hide/show those regions between the sub-apps?
Or, do I keep the Regions declared in app.js? If so, how would I then best alter and orchestrate events those regions from sub-apps? Having the Regions defined in the app.js file seems to be counter-intuitive to keeping what modules and the core app know about each other to a minimum. Plus, every example I see has the appRegions method in the main app file. What then is the best practice for accessing and changing those regions from the sub-app?
Thanks in advance!
I actually have a root app that takes care of starting up sub-applications, and it passes in the region in which they should display. I also use a custom component based off of Backbone.SubRoute that enables relative routing for sub-applications.
check out this gist: https://gist.github.com/4185418
You could easily adapt it to send a "config" object for addRegions that defines multiple regions, instead of the region value I'm sending to the sub-applications' start method
Keep in mind that whenever you call someRegion.show(view) in Marionette, it's going to first close whatever view is currently being shown in it. If you have two different regions, each defined in its own app, but both of which bind to the same DOM element, the only thing that matters is which region had show called most recently. That's messy, though, because you're not getting the advantages of closing the previous view - unbinding Event Binders, for example.
That's why, if I have a sub-app that "inherits" a region from some kind of root app, I usually just pass in the actual region instance from that root app to the sub-app, and save a reference to that region as a property of the sub-app. That way I can still call subApp.regionName.show(view) and it works perfectly - the only thing that might screw up is your event chain if you're trying to bubble events up from your region to your application (as the region will belong to the root app, rather than the sub-app). I get around this issue by almost always using a separate instance of Marionette.EventAggregator to manage events, rather than relying on the built-in capabilities of regions/views/controllers/etc.
That said, you can get the best of both worlds - you can pass the region instance into your sub-app, save a reference to it just so you can call "close", then use its regionInstance.el property to define your own region instance pointing to the same element.
for(var reg in regions) if regions.hasOwnProperty(reg) {
var regionManager = Marionette.Region.buildRegion(regions[reg].el,
Marionette.Region);
thisApp[reg] = regionManager;
}
It all depends on what your priorities are.
I personally prefer to use the modules in my Marionette application. I feel it removes the complexity that require.js adds to your application. In an app that I am currently working on, I've created one app.js file that defines my backbone application but I am using a controller module that loads my routes, fills my collections and populates my regions.
app.js ->
var app = new Backbone.Marionette.Application();
app.addRegions({
region1: "#region1",
region2: "#region2",
region3: "#region3",
region4: "#region4"
});
app.mainapp.js ->
app.module('MainApp', function(MainApp, App, Backbone, Marionette, $, _) {
// AppObjects is an object that holds a collection for each region,
// this makes it accessible to other parts of the application
// by calling app.MainApp.AppObjects.CollectionName....
MainApp.AppObjects = new App.AppObjects.Core();
MainApp.Controller = new Backbone.Marionette.Controller.extend({
start: function() {
// place some code here you want to run when the controller starts
} //, you can place other methods inside your controller
});
// This code is ran by Marionette when the modules are loaded
MainApp.addInitializer(function() {
var controller = new MainApp.Controller();
controller.start();
});
});
You would then place your routes inside another module that will be accessed in the controller.
Then in the web page, you would start everything by calling.
$(function () {
app.start();
});
Marionette will automatically run and load all of your modules.
I hope this gets you started in some direction. Sorry I couldn't copy and past the entire application code to give you better examples. Once this project has been completed, I am going to recreate a demo app that I can push to the web.

Resources