I've just started the process of learning Angular and I'm a bit stumped. Currently, I have a master blade template that I use site wide in my Laravel app. Here is the pertinent piece.
<body>
#include('navbar')
#yield('content')
#yield('content2')
</body>
In order to use AngularJS, I have to place the tag ng-app in the body line. If I have several pages that use different pieces of AngularJS code, how can I change the tag?
I'm hoping that someone has an idea. Help.
Thanks in advance.
ng-app can be placed anywhere, on any element.
So, if you have one app for navbar, simply add ng-app="navbarApp" to the top most element of your navbar template.
As an aside, I would recommend reconsidering using separate apps, and instead focus on one app with several controls for various portions of your application. This way the body element is your ng-app element, and the top most element of your navbar template is simply a ng-controller element.
Then you set a <div ng-view> element under your navbar and you can either assign each of your content includes it's own controller and still load as a single page, or you simply load the page with only the navbar portion and dynamically load views into this portion by performing simple controller routing.
This simplifies the views structure on the server side since you no longer have to worry about creating layout templates for every potential combination of components. Just create the components and let the front-end load the components where needed.
Note: This is assuming you are building an application that doesn't require SEO capabilities.
Related
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.
I have a top menu in my angular app. Since the menu is static, it is not included in the ng-view.
I could leave the menu source in the index.html, but for cleaner markup I decided to pull it into a partial.
Now my question: Is it better practice to use ng-include and a separate controller or implement a custom directive instead?
I won't really reuse the code so I think ng-include would be fine but a directive somehow feels more "the angular way"...
ng-include is just fine to load partial views for your application(I assume that your index.html is kind of a master page with one ng-view section).
Each section that is loaded can have it's own controller(e.g. if you have a div with 'hot news' that fetches stuff from the db, you can just include the partial view using ng-include and let the new view have a ng-controller directive that will perform a ajax call to fetch stuff from the db).
I would add a directive only if need extra functionallity.
If you can live without it then why bother?
Is it better practice to use ng-include and a separate controller or
implement a custom directive instead?
Best practice is always subjective.
I have taken this approach:
If I want to build for reuse; I create a directive.
If I want to separate code for organizational purposes, I use an ng-include
I would seriously suggest looking at ui-router (https://github.com/angular-ui/ui-router), which gives you an enormous amount of flexibility to setup layout pages that have different sections (main, left-nav, content). It's a much more flexible means of using Angular to setup page structure so that you don't have to repeat yourself. It's also tremendously powerful by allow you precise control over different section of a page depending on where people are in your application.
The docs do a reasonably good job explaining it, but try to focus on the area which talks about multiple-named views.
ng-include will work fine, but it if you want more control, ui-router is the way to go.
I read about angularJS routing. I want to implement it in my web app, but unfortunately I have a rather difficult situation changing to routing now I think. This is how my app works now (and I know it's probably not the way it should, but it does work):
I have one controller for the whole app.
The view is built with some divs, one of which is a menu div. The others are 'partial' views as angularjs calls them I guess. But the problem I see here is that two of my partial views can be shown at the same time (page is built like this, partial view only takes a portion of the page for itself).
So what I am doing is: I click the button on the menu -> one partial view shows up (ng-show), then I can click something on this partial view to get the second partial view opened on the same page (menu and first partial must stay the way they are).
At the moment I include partials within some divs with php include (which is I am sure the wrong way) and the divs have ng-show on them so that nothing is shown on the beginning. Then I manipulate all the clicks in the menu with setting ng-show parameters of all my partials (views). So if one button is clicked I hide all the others (with ng-click and a function inside controller). But this is tedious work and not the angularJS way and that is why I am asking this question here.
Example of my included partial (stripped of all unnecessary css classes etc):
<div ng-show="showNames">
<?php include_once("views/AREA1/names.php") ?>
</div>
And names.php has for instance just some few elements with ng-repeat and other angularJS directives… I have many includes like that and they work with just ng-show manipulation very well. But now that I grasped some of the AngularJS concepts I see that I made a mistake…
To sum up: how can I use angularJS routes (with ng-view perhaps?-not necessary) to show views within my web app? (taking into account the situation that I have described above). I just want user to be able to know on what "part of page" he is at any given moment.
EDIT: I went trough this and I reckon I could work it out: I need a structure similar to the one in this example 2.1 Online Demo, but furthermore I need to be able to click something on ng-view which should open another view (first one should stay in place). Any idea how to accomplish this?
By using routing feature in AngularJS, the html content of ng-view will be totally replaced by the new partial. You should not use ng-view for such a purpose like showing multiple partials at the same time.
But you can think about mix the ng-view and ng-include.
Let's say, we click each item on the menu, ng-view changes the sub-partial, you can have ng-include in your sub-partials which we can all it here like sub-sub-partial.
Try reading ng-include
AngularJS has ng-view which would contain the main theme of current context, rest of the UI elements are all managed by ng-include. Routes also work in sync with nv-view.
If your view requirement are complex look at ui-router component that supports various combinations.
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
In all of the AngularJS examples, the Angular library is placed in the HEAD tags of the document. I have an existing project that has been built upon the HTML5 Boilerplate layout. This defines that JS libraries should be placed at the very bottom of the DOM before the </BODY> tag.
Does AngularJS need to be placed in the HEAD?
AngularJS does not need to be placed in the HEAD, and actually you normally shouldn't, since this would block loading the HTML.
However, when you load AngularJS at the bottom of the page, you will need to use ng-cloak or ng-bind to avoid the "flash of uncompiled content". Note that you only need to use ng-cloak/ng-bind on your "index.html" page. When ng-include or ng-view or other Angular constructs are used to pull in additional content after the initial page load, that content will be compiled by Angular before it is displayed.
See also https://stackoverflow.com/a/14076004/215945
This one answer on Google Groups gave me perfect insight (shortened):
It really depends on the content of your landing page. If most of it
is static with only few AngularJS bindings than yes, I agree, the
bottom of the page is the best. But in case of a fully-dynamic
content you would like to load AngularJS ASAP [in the head].
So if your content is generated in large part through Angular, you'd save yourself the extra CSS and ng-cloak directives by just including Angular in the head.
https://groups.google.com/d/msg/angular/XTJFkQHjW5Y/pbSotoaqlkwJ
Not necessarily.
Please take a look at this http://plnkr.co/edit/zzt41VUgR332IV01KPsO?p=preview.
Where the angular js is placed at the bottom of the page, and still renders the same output if it were to be placed at the top.
Loading Angular JS at the bottom of the page does result in a flash of ugly {{ something }} html. Using the ng-cloak directive in the body tag creates an empty flash until the JS is loaded so it doesn't add any benefit over just loading AngularJS in the head element. You could add ng-cloak to every element with ng directives in it but you'll end up with a flash of empty elements. Soooo, just load Angular and your app.js files in the head element as the Angular documentation recommends in this quote from their documentation: "For the best result, the angular.js script must be loaded in the head section of the html document"