Defining AngularJS code inside ng-app declaration - javascript

I'm a SharePoint admin experimenting with AngularJS. I am working on a page that will include several AngularJS applications in separate parts of the page. Each application is defined in a separate include file, so the javascript will be embedded in the body of the page. Because of the issues surrounding multiple applications on a page, I figured, let's set up the Master Page to have a single ng-app declaration.
<body ng-app="SharePointAngApp">
As I said, the code definition is inside the body tag insert using a Content Editor Web Part.
var AngularApp = angular.module('SharePointAngApp',[]);
AngularApp.controller('spStockTicker',function($scope, $http) {
and
var JCAngularApp = angular.module('SharePointAngApp',['ngSanitize']);
JCAngularApp.controller('spJimConnect',['$scope','$http','$sce',function($scope, $http,$sce) {
However, now I'm getting an error: angular.min.js:107 Error: [ng:areq] http://errors.angularjs.org/1.4.5/ng/areq?p0=spJimConnect&p1=not%20a%20function%2C%20got%20undefined
Is this possible, or does the javascript have to sit outsite the ng-app container.

You can't declare the same module name twice.
You would be best off to include a second(or more) module as dependency of the main one
var AngularApp = angular.module('SharePointAngApp',['SharePointAngApp-2']);
var JCAngularApp = angular.module('SharePointAngApp-2',['ngSanitize']);
Also the way you are needing to do this you may need to consider manually bootstrapping the app rather than using ng-app
That would allow you to build dependency arrays on as as needed basis

Related

Jquery scripts in angularjs project

I am working on angularjs project that I generated using yeoman angular generator.
I have a jQuery function that I need to use in most of my html views.
A possible solution is to add this function to a script.js file for example, and add this file as reference in the html views that require this function. However, I don't think this solution is good.
When yeoman generates an angularjs project, in its index.html file, it adds a section
<!-- build:js({.tmp,app}) scripts/scripts.js -->
within this section, the different script files are added since as I think, on build, those files will be unified in a single scripts/scripts.js file.
I tried to do the same by adding the function to a script file, and added the reference of the this script file to this section. The problem is that the function is not working when I try to call it from any view.
What can I do to solve it?
DOM manipulation is done with directives in angularjs you will need to check out the docs: https://docs.angularjs.org/guide/directive
If you are not manipulating the DOM you can create a service that can be injected into any controller.
Services documentation: https://docs.angularjs.org/guide/services
from there you can assign a function in the controller to the scope that can be accessed in the view. e.g.
$scope.MyFunction = function(){
// Code goes here
}
you can call the function in the html as
<div ng-click="MyFunction()"></div>

Proper way to include a js library file in a directive, avoiding relative path that may change

I have a project which is not using any method for including angular code other then loading them directly into our html page (and won't get permission to include any tool for awhile from my manager).
Currently if I want to use a provided javascript/angular/bootstrap element I would simply include it in my index.html, something like:
<script type="text/javascript" src="../lib/angular/angular-file.js"/>
I am now writing a directive. In the html template I want to use an already written third party angular directive to provide a tree view. I thus would want to include this script within my directives html template to insure it's loaded, rather then trusting this to the index.html has already loaded the script.
However, I don't want to use a relative path, or at least am afraid doing so will cause my directive to break later. the html template for my directive is buried under a tree structure, something like " portal/modules/simulation/templates/whatever" I don't want to have to place "../../../../../lib" in the template because it's ugly, but also because there is a chance that we may move the angular files around and I don't wan that to break my directive.
Is there a cleaner way of including the library without making a presumption about multuple layers of file structure, some way to work relative to the 'top layer' of my file structure etc?
is it considered clean for my directive to have it's own lib directory that contains the third party angular directive, rather then being part of shared lib directory? For that mater I believe that the third party tree view directive I'm using is dependent on other angular and jquery code, so I don't know if I may accidentally be dependent on something in the top level index.html file loading some angular/jquery code my directive uses without realizing it. Am I over worrying about making my directive stand alone when I shouldn't?
Generally I pack up templates using grunt and grunt-angular-templates. If you use something like this, you can reference your template as myModule/fileNameOfTemplate, and since the template is already in memory (using the $templateCache) you don't make any extra requests and the code doesn't care at all about the path to the actual file.
Without adding extra modules, build steps, etc...
foo.js
var fooModule = angular.module('foo', []);
fooModule.run(['$templateCache', function ($templateCache) {
$templateCache.put("foo/mytemplate.hmtl", "Really" +
"really" +
"long" +
"string");
}])
fooModule.directive('bar', function () {
return {
templateUrl: 'foo/mytemplate.html'
}
});
Now it doesn't matter where you store the module - you're just pulling the file out of the template cache.
Alternatively, templateUrl can accept a function - you could write a function to determine the path of the module or something.. but that's going to be super brittle.

Custom directives on AngularJS pages without specific ng-app module set

I have some simple pages that don't need a specific application module to be provided in the ng-app attribute. But those pages also use some of my custom directives.
As it seems natural I've put all my directives in separate namespace (namely module) i.e. MyApp.Directives.
This is all great when I also provide my application module, because I add MyApp.Directives as dependency and it works.
angular.module("MyApp", ["MyApp.Directives", ...])
But. As said I also have some very simple pages, that don't really require any particular application module because they don't need any custom controllers or anything. They're just driven by ng-... attributes/directives.
Question
I know I can simply add all my custom directives to ng module and they will become accessible to all pages. Those with custom application module and those without. But this beats the purpose of modules, so I'm wondering if there's any other way to tell dependency injector of my additional directives/filters?
I would like to avoid any unneeded code in my application to keep is small and maintainable. (what AngularJS is all about). What I'm looking is actually some sort of hack that I'd be using in my directives' files to make ng module aware of my directives but without adding them to ng module directly... A rather advanced Angular question as it likely involves some internals manipulation.
I've tried manully adding my directives' module to angular.module("ng").requires array but that didn't do the trick.
#1) If you only have one module you can do it with ngApp:
<html ng-app="MyApp.Directives">
#2) If you have multiple modules you can use angular.bootstrap like so:
angular.element(document).ready(function(){
angular.bootstrap(document,['MyApp.Directives','MyApp.Filters']);
});
#3) Or just create a simple module for declaring dependencies:
<html ng-app="myApp">
......
<script>
angular.module('myApp',['MyApp.Directives','MyApp.Filters']);
</script>
If we could only write something like this:
<html ng-app="MyApp.Directives MyApp.Filters">
I made a patch to the source code:
function angularInit(element, bootstrap) {
// some code
if (appElement) {
bootstrap(appElement, module ? module.split(/\s+/) : []); // split by spaces :)
}
}
Here is a demo: http://plnkr.co/edit/kSrY3WYzLG39NJ4UgTRM?p=preview

Angular.js load, process and display dynamic template obtained via REST $resource

I have an Angular app that needs to support customizable reporting. My intention is to allow the user to select one of many reports available and have a back end REST api provide the template and the data as JSON (end user can customize the template).
The app would then insert the template somehow into a "reporting" view page then put the data in the scope and Angular should compile and display the report / template.
I've looked into ng-include however that seems to support only an URL or path to a document, however I have the template text already via the REST service and I cannot use static urls or file paths, this needs to be via REST api, if ng-include accepted the template text directly that might work but it doesn't.
I've tried writing a directive, trying to call a method on the page (getTemplate()) that would load the template already fetched from the scope however my directive doesn't have access to the scope apparently.
What tactic should I use to accomplish this? A directive seems best but I'm obviously doing it wrong and completely lost in the docs and my many attempts trying to accomplish this.
You could compile the dynamic template to an element on the DOM in a controller and then in the controller have something like this:
var el = angular.element('#myselector');
el.html(mydynamichtmlfromresource);
$compile(el.contents())($scope);
I would setup your route with template with single DIV container (you could pull all the static container template in a single JavaScript file using HTMLToJS online tool or grunt task):
<section class="view">
<div id="myselector"></div>
</section>
I've tried writing a directive, trying to call a method on the page
(getTemplate()) that would load the template already fetched from the
scope however my directive doesn't have access to the scope
apparently.
Yes you are right, but there is a way to pass data from scope to directive. lets say you want to pass a var "x" from scope to directive
use this
<directive directiveVar='x'/>
inside directive, you need to use isolated scope
"scope": {
"directiveVar": "="
},
this variable will be available only in controller and postlink function, so your directive template needs to be like this
<ng-bind-html="directiveVar"/>
inside the postlink you may need to use this code snippet
$scope.directiveVar =$sce.trustAsHtml($scope.directiveVar)
References
http://docs.angularjs.org/api/ng.directive:ngBindHtml
http://docs.angularjs.org/api/ng.$compile

Why ng-app not ng-module?

I understand that ng-app initializes a module in AngularJS as follows:
var app = angular.module('myApp', []);
<html ng-app="myApp">
But when I teach this to someone new to AngularJS or watch a video, instructors inevitable fumble over the inconsistency in the terminology between app and module. AngularJS is so well thought out as a framework that I'm surprised it hasn't changed to:
var app = angular.app('myApp', []);
<html ng-app="myApp">
OR
var app = angular.module('myModule', []);
<html ng-module="myModule">
Has anyone been following the project long enough to know the history on this part of the framework?
I don't think Craig is asking what does ng-app do or how does it work.
I think he's asking why did the people that created angular name that directive ng-app. Why didn't they name it ng-module. ng-module would be easier to understand.
For example ng-controller should name a controller, ng-module should name a module. The angular methods to create them are named module() and controller(), there is no method or entity called "app".
I tend to agree with Craig. That said if I were go speculate why they named it ng-app I would think it's because you are only allowed to have one ng-app directive in your HTML. If you wanted to have more than one module associated with your HTML page you can do it programmatically.
So ng-app is more of a utility to bootstrap your HTML with a module, it is not a generic way to associate modules with your HTML.
If you look at the documentation that's what it suggests:
Use this directive to auto-bootstrap an AngularJS application. The
ngApp directive designates the root element of the application and is
typically placed near the root element of the page - e.g. on the
or tags.
Only one AngularJS application can be auto-bootstrapped per HTML
document. The first ngApp found in the document will be used to define
the root element to auto-bootstrap as an application. To run multiple
applications in an HTML document you must manually bootstrap them
using angular.bootstrap instead. AngularJS applications cannot be
nested within each other.
http://docs.angularjs.org/api/ng/directive/ngApp
All that said if you want an ng-module directive you could always write your own to wrap the angular.bootstrap() function. You can find more details and code about how to do this on a blog post I wrote about it: AngularJS: Getting around ngApp limitations with ngModule
ng-app means: That page has Angular in it!
ng-app="module" means: That page has Angular in it and necessary controls/services/etc are defined in that module.
ng-app defines the main or bootstrap module of your application, which should perform the initialization task of your application. There may be case where at run time you want to decide what which should be the main module of your application. Like in java you have many methods and classes but you define one main method as starting point. Similarly, in angular you have many module, however, you define one module as the starting point of application.

Categories

Resources