AngularJS: How to nest applications within an angular app - angularjs

i've been working on a project that is more like a framework, and has several apps / modules you can install. See it like a basic appstore or google.play store. It's sort of an intranet application, and all modules can be added to your useraccount.
the framework is already in development, but i'm wrapping my head around the applications/modules idea now. (link to a proof of concept in development, can be found here)
an application should be somewhat standalone, and not able to suddenly include scripts from the framework, This is perfectly possible by structuring them in separate modules like so:
angular.module('myApp', []);
however, an app can have templates, scripts, css and it can run on a separate server, so I'm kind of looking for the best way to fetch the script(s) and cssfile(s) and dynamically load them into the app when the user starts the app in from within the framework.
currently I'm structuring apps as if they have a main template for example www.framework.com/apps/myapp/views/app.html, for the sake of simplicity i bundle scripts into 1 script file per application, so there is also a www.framework.com/apps/myapp/script.js to be included.
The framework contains a template that loads the apps, and an appController. The template contains this piece:
<div data-ng-controller="AppController" data-ng-include="app.appTemplate">
<div>loading...</div>
</div>
this basically binds to the $scope.app.appTemplate which is updated when all scripts are loaded, so first it shows a loading template, later after scripts are included in the page it updates the app.appTemplate to the above mentioned main template of an application.
while loading the first index template works, this template is currently loaded with the AppController from the framework, so it is using the $scope of the framework and not it's own script.
I still have to somehow start the app's own angular module, and let it on it's own without running anything in the framework to 'make it work'
I'm still figuring out how to best load the dependent javascript files (will probably use requrejs or other dependency loader) but I have currently no clue how to 'boot' the app without working from within the framework's AppController
EDIT
I created a small demo project to show the problems at hand, full code is visible at git-hub at the moment this project does a few things hard coded, the idea would be that I make those less hard coded when I get the proof of concept right, now it's all about loading the applications within the framework. if that is possible, I can think of where to get the URL's and application names from ...

You can't bootstrap a module inside another bootstrapped module. Bootstrapping compiles the view and binds a rootScope to it, traversing it's way through the DOM and setting up scope bindings and executing directive linking functions all the way through. If you do that twice, you're going to run into problems.
You're probably going to have to rethink your architecture. I think perhaps the word "module" or "app" as it pertains to Angular is a misnomer and is leading you down the wrong path.
Each "user installed app" in your application should probably really be controlled by a controller in your app module, or registered to a module referenced by your app module. So you wouldn't be "starting up multiple apps", you'd really just be starting one, referencing the other modules, then using Controllers from those modules to control parts of your view on the screen.
What you'd do is when a new "widget" was installed, you're register it's module file (.js) with the system, which would contain a controller named WidgetCtrl, then when your page loaded, you'd reference the widget's module on your app module. From there it should be available for dynamic assignment to elements using ng-controller and/or ng-include.
I hope that makes sense.

Contrary to currently accepted answer, It is actually possible.
I was working on a similar problem and suggested answer was not acceptable in my case. I had previously written pages with multiple applications but it was years ago and apps were independent of each other. There are two things to do basically:
Tell main application to ignore a child element.
Bootstrap the child element.
There is an ng-non-bindable attribute which simply tells AngularJS to ignore the element. This handles our first problem.
However when you try to bootstrap the child element; AngularJS will throw an error, telling you that it is already bootstrapped (at least to me, version 1.2.13). Following trick does the job:
<div ng-non-bindable data-$injector="">
<div id="bootstrap-me">
<script src="/path/to/app.js"></script>
<div ng-include="'/path/to/app.html'"/>
</div>
</div>
This solution is not perfect. Ideally, ng-non-bindable attribute can add required data-$injector attribute to element. I am going to make a feature and hopefully a pull request to AngularJS.
I did not have the chance to make a pull request. Apparently and expectedly I should say, some internals have changed but ng-non-bindable is still working at version 1.3.13 using Ventzy Kunev's demo code (thanks again, see link below).

well if each sub-app is in its own module, you can just use angular.bootstrap to load that module dynamically. when the url for a specific app loads, you can fetch the necessary script(s), then when the promise resolves, you can do something along the lines of:
// grab a reference to the element where you'll be loading the sub-app
var subapp = document.getElementById('subapp-id');
// assuming the script you get back contains an angular module declaration named
// 'subapp', manually start the sub-app
angular.bootstrap(angular.element(subapp), ['subapp']);
hope this helps

Similar to UnicodeSnowman's answer above, another potential solution that appears to be working for my needs (I built a live Angular editor on a documentation site) is to manually handle the bootstrap process by having a <div id="demos"> that is separate from the main <div id="myApp">.
This article was very helpful to get it working correctly.
General Process
Create your main app (I chose to manually bootstrap, but you may be able to use ng-app for this part)
Create a new HTML structure/app (in my case the demo app):
Append it to the demos div with a custom id: someCoolDemoContainer
Boostrap the newly created app
Move it back into the original app (for layout/positioning purposes)
Code Example (not tested; just shows basic process)
<div id="myApp">
<h1>Demo</h1>
<p>Click the button below to checkout the cool demo!</p>
<button ng-click="showDemo()">Show Demo</button>
<div class='insertion-point'></div>
</div>
<div id="demos">
</div>
<script type="text/javascript">
/*
* Init/bootstrap our main app
*/
var appContainer = document.getElementById('myApp');
angular.module('myApp', ['myDependency']);
angular.bootstrap(appContainer, ['myApp']);
// Do lots of other things like adding controllers/models/etc.
/*
* Init/bootstrap our demo app when the user clicks a button
*/
function showDemo() {
// Append our demo code
$('#demos').append('<div id="someCoolDemoContainer">Angular app code goes here</div>');
// Bootstrap the new app
var demoContainer = document.getElementById('someCoolDemoContainer');
angular.module('someCoolDemo', ['myDependency']);
angular.module('someCoolDemo').controller('myController', function() { ... });
angular.bootstrap(demoContainer, ['someCoolDemo']);
// Re-insert it back into the DOM where you want it
$('#myApp').find('.insertion-point').append($('#someCoolDemoContainer'));
}
</script>

I know this is quite old now but I was looking for a way to embed an AngularJS app within an Angular app and used the answers from this post to do just that so I thought I'd post up the plunker here for anyone else looking for a similar solution.
There were two ways that I found to do it, both used manual bootstrapping of the angularjs app within the ngOnInit of an Angular component:
ngOnInit(): void {
// manually bootstrap the angularjs app
angular.bootstrap(document.getElementById('ngListApp'), ['list-app']);
}
Either set the ngNonBindable attribute on the element that will be bootstrapped:
<div ngNonBindable #insert>
<!-- can insert the angular js template directly here, inside non-bindable element -->
<div id="ngListApp" ng-controller="ListController as list">
<input ng-model="inputValue" />
<ul>
<li ng-repeat="item in items">{{ item }}</li>
</ul>
</div>
</div>
Or inject the angularjs template html into the element in the ngOnInit event handler within an Angular component so that Angular doesn't try to interpret the AngularJS code (especially interpolation of AngularJS properties in the DOM with curly brackets) during compilation.
ngOnInit(): void{
// insert angularjs template html here
this.div.nativeElement.innerHTML = this.htmlTemplate;
// then manually bootstrap the angularjs app
angular.bootstrap(document.getElementById('ngListApp'), ['list-app']);
}
The Plunker is here:
http://plnkr.co/plunks/0qOJ6T8roKQyaSKI

Related

Is it possible to pass information from an Angular component to an AngularJS component?

I am working on a hybrid app, it's running a main Angular (7) component and within it has an upgraded (through ngUpgrade) AngularJS component running a Gantt chart. I am trying to pass the data it needs from the Angular component's controller to the AngularJS one, but I'm failing to find resources on this topic, which makes me think it is not possible. Anyhow, I would like to ask just in case anyone has ever tried this.
Thank you in advance!
You can use global object, like window. Add to this object properties chanel like RxJS/BehaviourSubject. Remember import RxJs library.
In index.html add script where define chanel
<body>
<script>
window['myChanel'] = new BehaviourSubject()
</script>
</body>
In AngularJS app, where you need, set Observer:
let transData;
window.myChanel.pipe(tap(value => transData = value ))).subscribe()
In Angular app, use chanel for emit value
window.myChanel.emit('myTestValue')

Angular way of "global controller" for Ionic apps

I'm new to ionic and have been wondering the "angular" way of a "global controller".
In my app, I am using the starter tabs template and I want to have a bar with which I want to interact with as the user lays around in my app. And this bar would be placed in my index.html like the following.
index.html
<ion-nav-view></ion-nav-view>
<div id="my-player" class="idle">
<round-progress background-image="{{roundBg}}" background-repeat="no-repeat" background-position="center" background-size="contain" radius="23" stroke="5"></round-progress>
</div>
I want this div#my-player to be modified as the user plays around with the app.
The initial state for #my-player would be hidden, which I would do so via the css class .idle. But when the user get to my /#/tabs/replay/{:id} page and clicks on an item, I want to add a angularAudioObject and display the audio information in #my-player.
I found it very inefficient to repeat the same code over and over again all of my controllers so I wondered if there was a way to keep this audio-controlling code could be written once and not be called upon in all of my controllers.
P.S. Yes and I'm aware of services and how they could be included in my controllers but I was wondering if there is a way to keep this code "seemingly be integrated onto" my index.html file.
It doesn't really matter which file has the code in it just that the file is loaded and executed. That said you should use services or factories to define objects that you want to persist for the life of the application and for any code that would otherwise be repeated (assuming it isn't something that makes more sense as a filter or directive).
Controllers are ephemeral they are created and destroyed as you navigate views. You can have a controller outside the ui-views that could be a parent of all the other controllers but it's really a fragile way to build things. Instead take advantage of the simple DI.

Angular JS app in View

How should I proceed when inserting app in a view.
I have a template document the has one app already to control page content. I want to insert other apps in the view. My first app is getting called in the html tag and it is controlling different sections of the page except the view.
Views are another html document that is loaded into a section. Can this other html file contain another app?
I have been trying with include but the app isn't working.
Exemple of code:
<!DOCTYPE html>
<html ng-app="mid" lang="fr">
<nav ng-controller="navCtrl"></nav>
<main><ng-view><ng-view></main>
<footer ng-controller="navCtrl"></footer>
My view would contain :
<div ng-app="my-second-app" ></div>
<div ng-controller="second-app-Ctrl"></div>
Would that work?
When you include your 'My view' to your example code you are nesting AngularJS applications. You can't include another app as view. AngularJS applications cannot be nested within each other.
take look here, and here
It is possible if you use the manual angular bootstrap function, but I find it hard to believe that this is what you want. You don't need to specify another ngapp in the injected view to let him know he is within angular context, he already knows that, anything below the original ng-app you specified is automatically in angular context.
Using another angular app within an angular app should only make things complicated and probably unnecessary especially if you are new to angular.
Any way keep it simple , try using the developers guide in http://angular.org , they should give you a sense of how to start.

Using angular and backbone in the same app

I am working on a backbone app that we want to migrate over to angular. However, a true "port" or "rewrite" is not an option due to resource constraints. Instead, we want to introduce angular into the app in a modular sort of way -- ie, identify and carve off easily separatable functionality and make it angular, as well as introduce any new modules (i.e. an admin module) as angular code.
Is this possible? If so: a) Where would you put your "ng-view" tag? Inside the div that you currently render your backbone-based markup? b) How do you introduce angular-routes into all of this?
You can add target="_self" for all the backbone links, then angular would not route those links. We had the same problem and adding this fixed the problem. Hope this helps..
Test
You can use angular in any place you want in your app and use it with backbone if you want but stay in mind that you're using two frameworks and in this case it's totally unnecessary and wrong, but i think that you don't have choice, all you have todo is put the directive "ng-app" where you want to use angular, here is my example:
<html ng-app="myModule">
//your code here
</html>
and the script(like any other angularjs app):
var app = angular.module('myModule', []);
// the rest of the code
I never tested before angularjs + backbone, but i think you can have some problems like to deal with data from server, who will gonna do that? Angular or Backbone?

Incorporate AngularJS into existing modular application

I'm trying to find the way of incorporating AngularJS into existing application. Application is modular, so every module has HTML markup and JS script files. Modules are loaded with requirejs and jQuery (for loading markup).
I would like to use AngularJS features in some of the modules, having in mind the possibility of migrating to AngularJS in future. So ideally I want something like this:
define([ 'angular' ], function (angular) {
return function (element) {
// The "element" parameter contains the reference to
// the detached DOM node that contains the markup.
// And what I think should be done is compiling
// or initializing AngularJS with the given DOM HTML fragment
// and with controller, etc.
angular.doSomething(element, ...something...);
// The application module engine will inject the returned element
// into the DOM tree.
return element;
};
});
Any ideas? Thanks!
Just following the tutorial, specifically Step 2 (http://docs.angularjs.org/tutorial/step_02) will show you how to just do a single controller on the page with some simple functionality.
You can just use this, or you can start expanding it by modularizing it as in Step 7. By creating an module you can then add directives and services and take advantage of all that Angular offers. You don't necessarily need to configure routes or anything, but by creating an app module, you can incorporate other modules or services offered throughout the web or by Angular.
AngularJS isn't designed to really run alongside other frameworks and be used for little bits and pieces. You could hack it together to do this but it'll probably become very messy. Angular is much better suited to becoming the basis of the entire app.
Something like jQuery is great for dropping into an app and adding functionality, but angular is far more complex.
If you do want angular to take control of certain parts though, take a look into the ng-controller directive and how it works. Then in your standard markup you'd just add the ng-controller attribute to any element, and then add a new angular controller to your javascript. It would then manage that DOM element.
Look into angular controllers for more info on that. But as I say, I'd suggest making the app entirely Angular rather than trying to just add angular bits to it

Resources