Recommendations for large single page application with 'portal' or MDI like functionality using AngularJS

1,838 views
Skip to first unread message

lothar7

unread,
May 5, 2013, 6:27:04 PM5/5/13
to ang...@googlegroups.com
Hi,

I have a question related to how to best compose a very large single page application using angularjs and if neccessary ui-router.

My scenario is this.
* I have multiple components which can be say trend module, 'business' analyzer, dash boards/workspaces, and lots of others.
* From an launcher sidebar the modules  can be opened in separate tabs like in an old school MDI windows application.
* Some of the modules are completely independent and some may use/share a common filtering widget which may reside somewhere one the page.

The general idea is that each of these components could be opened multiple times in separate tabs so users can easily switch between them as part of their workflow. Another thing is that url linking should be supported for all of them. Opening the url would naturally not involve reopening all the "tabs", just the one the url links to.

Using angularjs my limited understanding sor far has indicated that the best way to accomplish this would be to split my project into separate business modules as recommended for large application. Each business module containing the templates, services, directives etc that are relevant. Then I could use ng-include to include the templates and then instantiate the controller for each business module. In this little fiddle (http://jsfiddle.net/Bp2j8/23/) I can see that the same controller can be instantiated multiple times and hold its own data separate(not shown in the example but neccessary would be to include the required template each time the particular controller is created) which would cover the case when we want to instantiate the same module more than once in separate tabs.

This does not solve the problem with url linking though which brings me to the ui-router alternative which supports multiple ui-views which may potentially solve this problem too, but I do not know enough about that yet. The idea of using multiple ng-apps seems out of the question since this reduces the possibilities of communication between the different modules and the general opinion seems to indicate that this is a bad idea.

There is also an issue that the js files for each business module needs to be registered with the main page at load time. This could slow down the startup times significantly and something like $scriptjs might be an idea to overcome this.

I would appretiate any feedback and constructive comments as what would be a good approach in this situation.

Luke Kende

unread,
May 9, 2013, 1:38:57 AM5/9/13
to ang...@googlegroups.com
Angular gives you a great frame work to build something of this nature, but what you are talking about does not sound trivial, and though Angular plugins like ui-router are growing, prepare for a steep learning curve and lots of iterations in development time to bring something of that nature to fruition. Angular gives you two-way data-binding (prob its best perk), directives gives you a way to declaratively define your own elements, and plugins like angular ui-bootstrap give you some out-of-the-box functionality and ui components, but you will be wiring a lot of things up yourself.

It sounds like you might get there quicker using something like ExtJs.

I'm no expert on angular, but have spent the past few months working on a SPA and so far, though challenging, I have been able to accomplish what I wanted mostly on my own trial and error. 

Good luck

David Gee

unread,
May 9, 2013, 3:10:32 AM5/9/13
to ang...@googlegroups.com
I'd definitely recommend taking a look at ui-router, if you're capable of building an app this complex, it should be trivial to pick up the concepts and it covers most of your bases.

- top level modules are easily handled by states and can easily be assigned to URLs
- states have their own controllers and you can easily inject services to handle the commonalities.
- dashboards/workspaces would be created by having a state for the dashboard with multiple views handling the widgets.

what i'm not entirely sure about is cloning instances of states for your duplicated tab scenario, that one might be tricky.
as for loading all the scripts, there is some info out there on doing lazy loading with Angular but simple concatenation and minification using something like Grunt goes a long way. Of course, minification with Angular has its own pitfalls.

lothar7

unread,
May 9, 2013, 11:28:56 AM5/9/13
to ang...@googlegroups.com
Thanks for commenting on this, I need all the feedback I can get.

I have been doing some more research and I am starting to think that the multi-tab(MDI) approach is more trouble than its worth. It breaks the all routing paradigms etc, the concept of forward/back is no longer an option, and deep linking is no longer feasible. I think the main dividing line falls between deep linking with forward/back on the one side and multi tabs on the other side. I am now thinking more along the lines of the standard "open link in new window" if the users want tab switching and use a workflow that requires switching back and forth between states. Bascily keep the main documents in separate browser tabs. After all that's what browsers are for right... Going for the single document approach with angularjs seems more in line with what is normally done.

Having landed on a main "navigation" concept here are some of my issues
1. The standard routing is not sufficient but the ui-router has some good points although it is still a bit immature with regards to how to control the re-rendering of parent views when a child state changes. I also would like a more pluggable model for routing information. Basicly I would ideally like to have the routing/state information for each business module inside the "configuration" for that module. This relates to point 2 below.
2. In the ideal world I would do a runtime "initialization" of all the business modules. Obviously the plugin modules need to adhere to whatever the main application view provides, but it would mean that one could easily install new modules after the system was installed. A bit like a cms system where you install new plugins easily. I suppose I could "generate" the intialization javascript code one the server but that is not ideal. The reason for lazy loading is that I do not technically need that, but if other modules use external libraries it might be easier to resolve these extern dependencies runtime but I might be wrong here.

Luke Kende:
I did look into extjs but it kindof scares me the way they clutter the dom and it feels so large and unwieldy. I do not like large monolithic frameworks as they tend to suck you in and do everything their way. Angularjs combined with uibootstrap seems the way to go. I love the way the two-way binding works and someone has finally done something right with regards to a nice clientside mvc extending the html syntax which I think just feels right.

David Gee:
When you mention top-level modules you are talking business "modules" right (not angularjs apps)?
> "dashboards/workspaces would be created by having a state for the dashboard with multiple views handling the widgets."
Would you then have a separate controller per view right or at least a separate instance? (I am still very new to angularjs so that might be a silly question). As for the dashboards do you have any suggestions for a widget "library" that makes the dashboards even more appealing like this http://www.myorange.ca/theme/jarvisadmin/widgets.html

My previous experience with writing rich javascript applications is a large trend application using pure jquery, jquery-ui, flot charts and slickgrid. No fancy databinding but all hand crafted. Its all well and good for specialized application but when writing larger crud type apps then using manual databinding becomes very tedious and way too time consuming.

.

lothar7

unread,
May 9, 2013, 11:37:55 AM5/9/13
to ang...@googlegroups.com
As background information it might be interesting to know that we have an existing system today using good old asp.net with a portal/application launcher like functionality. Each "module" is a separate set of webpages asp and asp.net (yes you read it correct...good old asp) that gets opened into a central i-frame. Its rather cludgy and awkward but it has done the job(ps! i didnt write it). The plan is to migrate to a more coherent single rich web application consisting of separate business modules as mentioned above. For a while some of the old applications will live inside an iframe in the new application until there are resources and time available to rewrite them and make them properly integrated into the new application framework using angularjs and uibootstrap.

Luke Kende

unread,
May 9, 2013, 11:55:52 AM5/9/13
to ang...@googlegroups.com
I didn't have a good experience trying out ui-router... there were a few things that forced me in a direction that wouldnt work for our URL structures, specifically the /parent/child relationship where I needed autonomy... instead I found a way to use ng-view as it is.  

Here's the mental block I had to get past: routes defined in $routeProvider.when() can load the same template and controller.  Though at first this felt wrong, and I was losing "state" by reloading the controller, it became a clear path when I stored state in a service, and based on $routeParams was able to reload prior state of the ui (like which tabs are open) plus what the current route specifies (like some specific chart view).

I agree ExtJs is a scary what to go, and obviously you know the limitations of jQuery with a large app... it's a mental shift to go from jQuery to Angular, but worthwhile in my opinion. 



--
You received this message because you are subscribed to a topic in the Google Groups "AngularJS" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/angular/Ww_yfONbPvs/unsubscribe?hl=en-US.
To unsubscribe from this group and all its topics, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at http://groups.google.com/group/angular?hl=en-US.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

lothar7

unread,
May 9, 2013, 1:52:05 PM5/9/13
to ang...@googlegroups.com
I am still not sure if I get entirely how you are doing the routing and view handling using ng-view loading the same template and controller, but I can see that having a pure hierarchical state can be a problem. I don't know yet how that will affect my navigation etc. You do not by any chance have an actual example to illustrate what you were describing? When you store state in the service how to you keep that service synchronized with what the ui is showing? Are you updating this "state" service whenever you show/hide ui elements etc? I guess this service must be a singleton service so it will survive recreating the controller?

One thing that I is important for me is when to keep any "views" that are not changing intact and just rerender the ones that are changed so any scrollbars etc or input fields or whatever will remain as is where possible. I am left with the feeling that routing is angularjs weak point.

Luke Kende

unread,
May 9, 2013, 4:04:34 PM5/9/13
to ang...@googlegroups.com
I don't have an example to quickly link to... here are some points based on my experience so far. 

1. If a url route isn't changing based on user interaction, but the view needs to change, then using ng-switch or ng-show/hide works great.
2. If the url route changes, then a template and controller will be reloaded and as mentioned state is maintained via a service (yes a singleton with the defining method being .service() instead of .factory(). 
3. You will definitely discover any shortcomings in your understanding of javascript prototypal inheritance if they are lacking (mine were and still are at times) when using services.

Here's a short example for maintaining state from a service in a controller based on some of the components you mentioned.  I haven't tested, though technically could do a plunkr, but this is based off my implementation:

angular.module('app.services', []).
    service('ui', function($dialog){

        var state = {
           open: {
                menu: {},
                submenu: {}
           }
        }

        return {
            state: state
        }
    })

function MenuCtrl($scope, $location, ui){

    //whenever the controller is loaded, the local state variable will reference the ui.state 
    var state = ui.state;

    //technically these could be initialized from $http or $resource call but hardcoding for example
    $scope.sidebar = {
        menu: [
            { 
                name: 'Home', 
                submenu: [
                    { name: 'Settings' },
                    { name: 'Dashboard' }
                ] 
            },
            { 
                name: 'Graphs',
                submenu: [
                    { name: 'Profits' },
                    { name: 'Loses' }
                ] 
            }
        ]
    }

    //assuming the 
    $scope.openMenu = function(menu){
        state.open.menu(menu)
        $location.path('path/'+menu.name);
    }

    $scope.openSubMenu = function(submenu){
        state.open.submenu(submenu)
    }

}

HTML: 

<div ng-repeat="menu in sidebar.menu">
    <a href="#" ng-click="openMenu(menu)">{{menu.name}}</a>
    <div ng-repeat="submenu in menu.submenu" ng-show="state.open.menu.name == menu.name">
        <a href="#" ng-click="openMenu(submenu)">{{submenu.name}}</a>
    </div>
</div>

<div ng-switch on="state.open.menu">
    
    <div ng-switch-when="Home">
        <div id="tabs"><div>
    </div>

    <div ng-switch-when="Graphs">
        <div id="tabs"><div>
    </div>

</div>




Reply all
Reply to author
Forward
0 new messages