I am using RequireJS in my Angular app. I would like to require my pill where it is actualy used.
pill.js
define([], function() {
angular.module('app').directive('pill', function() {
return function(a,b,c) {
b.html("A pill");
};
});
});
incl.html
<div load-script="require(['pill']);"></div>
<div pill>test</div>
main.html
<html ng-app="app">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0/angular.js"></script>
<script src="http://requirejs.org/docs/release/2.1.10/comments/require.js"></script>
</head>
<body>
<script>
var app = angular.module("app", [])
app.directive('loadScript', function() {
return {
link: function(scope, element, attrs) {
(new Function(attrs.loadScript))();
}
};
}
);
</script>
<div ng-include="'incl.html'"></div>
</body>
</html>
This short example should declare a pill directive that just transform text from test to A pill inside incl.html file. However, it doesn't work. I guess it is because the pill directive is registered after incl.html is compiled.
I want avoid declaring directives somwhere globaly for example inside main.html because it is not used there. Is this requirement achievable in elegant way?
The best way to load directive on demand is to create it using $compileProvider which you will need to cache during your app.config phase. Also, instead of using ng-include, I would suggest you load the directive you need when partial view that uses it loads.
To do that, it is actually quite complicated. I created following library that should help get you started:
http://marcoslin.github.io/angularAMD/
angularAMD would make it easier for your create a independent file that allow you to configure RequireJS dependency to load the directive only on the partials that needs it.
Related
Is it possible to use ng-repeat to dynamically add script files to my html file?
I have a directive like below:
angular.module("app").directive("scriptLoader", function($compile) {
return {
template: "<script ng-repeat='s in files' src={{s}}></script>",
scope: true
}
});
Meanwhile files is a scope variable in my controller:
$scope.files = ["test.js", "script.js"];
And I get the html rendered as:
<script-loader class="ng-scope">
<script ng-repeat="s in scripts" src="test.js" class="ng-scope"></script>
<script ng-repeat="s in scripts" src="script.js" class="ng-scope"></script>
</script-loader>
But it doesn't work since whenever I try to invoke a method from the loaded files, it just says the method is not defined.
I'm just curious why can't I load script like this. Please help!
I have signed up to a paid version of Polldaddy and was provided this script tag (minus the proper id).
<script type="text/javascript" charset="utf-8" src="http://static.polldaddy.com/p/0000000.js"></script>
This script has to be loaded within a div in a view of mine - and it is not working. Does angular have an issue with loading scripts within a view? Is it possible? If so, could you help me understand how to do it please?
Let me know if you need more info.
Thanks
You can't load a script inside an Angular app due the Angular script directive, so you need to create your own directive.
Something like this:
function polldaddy() {
var injectScript = function(element) {
var scriptTag = angular.element(document.createElement('script'));
scriptTag.attr('charset', 'utf-8');
scriptTag.attr('src', 'http://static.polldaddy.com/p/0000000.js');
element.append(scriptTag);
};
return {
link: function(scope, element) {
injectScript(element);
}
};
}
angular
.module('myApp')
.directive('polldaddy', polldaddy);
and then in your HTML:
<div polldaddy></div>
I am writing a directive that I want other people to reuse.
The problem I encounter is that my directive has several js files it uses, and if I want others to use it, they need to add the js files explicitly.
Is there a way to make the directive include those files so that other will only have to add the directive file?
The way it works today is by adding the js files in the main head html file.
Can I use tamplateUrl to load the js files? Iv'e seen in THIS post that loading scripts creates some problems.
Concrete Example:
index.html:
<body data-ng-app="example">
<test-dir></test-dir>
</body>
index.js:
(function(angular){
var app = angular.module('example', []);
app.directive('testDir', function(){
return{
restrict: 'E',
templateUrl: 'test-me.html'
}
});
})(window.angular);
test-me.html:
<script type="text/javascript" src="test.js"></script>
<div> TEXT </div>
test.js:
function testMe() {
console.log('blah');
}
This format will call the directive and I will see the div TEXT text. BUT, I can't call the function testMe and I don't see any transfer in the network for test.js which is included in the directive's template.
How can I make it work?
if I nest ui-view inside a directive with transclude=true, the view content does not load. It works fine without the intervening directive.
so with a page containing:
<body>
<div ng-controller="MainController">
<div ui-view="sampleView"></div>
</div>
</body>
the sampleView content appears.
But if i put
<body>
<div ng-controller="MainController">
<div sample-directive>
<div ui-view="sampleView"></div>
</div>
</div>
</body>
then the view content doesn't appear.
I have created a simple html page to demonstrate the problem, see below.
As far as I can see, the angular compiling process does correctly call updateView in the ui-view directive in angular-ui, and that does build the view content and insert it in the dom under the sample-directive node, but that doesn't seem to be the actual visible sample-directive node, but a clone of it. i'm guessing it has to do with the order of compilation and therefore I need to do something clever in the directive, but i can't find anything in the angular api help that covers this point.
i've tried adding a post-link function and calling $transclude from there but it makes no difference.
can anyone advise what i need to add to the directive so this will work.
thanks
UPDATE
New info from further investigation:
It seems the cause is this (not at this point a solution, but I can see why it happens).
In angular's function applyDirectivesToNode (angular.js line 5919), if a directive specifies transclude=true, then the original directive node is cloned to make the template node. ie the template is not the original node that's visible in the dom. Now, when the compile function of ui-view in angular-ui-router.js line 2204 is called, it grabs a copy of the parent of the ui-view node, storing it in parentEl. But, and here's where the problem occurs - this parent is the parent in the dom of the ui-view node. what it's most certainly not is the instance of the parent that actually ends up in the dom after linking. Later when the ui-view updates for the initial route change, it builds the view content and inserts it under parentEl (angular-ui-router.js line 2273), but as we saw earlier this isn't in the visible dom after linking. it's the source html node and not the clone created by compiling and linking the directive in which the ui-view is nested.
I think this may be a bug in ui-view.
There may be a way to add a workaround to the directive, to get the post-link view instance and put it into the directive. If I figure it out I'll add an answer.
html to demonstrate the issue as follows:
<!DOCTYPE html>
<html lang="en" ng-app="viewInDirectiveApp">
<head>
<meta charset="utf-8">
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no">
<title>View inside a directive</title>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.js"></script>
<script src="modules/angular-ui-router.js"></script>
<script>
var viewInDirectiveApp = angular.module('viewInDirectiveApp', ['ui.router']);
viewInDirectiveApp.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('sampleState', {
url: '/sampleState',
views: {
sampleView: {
template: 'This is the view content',
controller: function ($scope) {
}
}
}
});
$urlRouterProvider.otherwise("/sampleState");
})
.controller('MainController', ['$scope',
function ($scope) {
}])
.directive('sampleDirective', function () {
return {
template: 'Start directive content <div ng-transclude></div> End directive content',
transclude: true
};
});
</script>
</head>
<body>
<div ng-controller="MainController">
Before sampleDirective
<div sample-directive>
Before sampleView
<div ui-view="sampleView"></div>
After sampleView
</div>
After sampleDirective
</div>
</body>
</html>
Confirmed bug in ui-router 0.2.8: https://github.com/angular-ui/ui-router/issues/774
Fixed in 0.2.10: https://github.com/angular-ui/ui-router/pull/858
Plunkers are much appreciated: http://plnkr.co/edit/TZ8hvkSbCIa0dTj0NkcG?p=preview - Seems to work in Angular-routing: http://dotjem.github.io/angular-routing/
As I'm new to Angular JS I was wondering how could I load an external template and compile it with some data into the targeted div.
For instance I have this template :
<script type="text/ng-template">
<img src="{{Thumb}}" />
<script>
The div that is supposed to contain the template :
<div data-ng-controller=" ... "></div>
The template is located somewhere in a folder /templates/test.php. Is there a build in way of doing the template loading like a directive would do and compile it against some data that would replace the key {{Thumb}} ( and many others of course ) ?
EDIT : What if I use $routes and load a template when I'm in the root of the website ? How could that be achieved ?
Using $templateRequest, you can load a template by it’s URL without having to embed it into your HTML page. If the template is already loaded, it will be taken from the cache.
app.controller('testCtrl', function($scope, $templateRequest, $sce, $compile){
// Make sure that no bad URLs are fetched. If you have a static string like in this
// example, you might as well omit the $sce call.
var templateUrl = $sce.getTrustedResourceUrl('nameOfTemplate.html');
$templateRequest(templateUrl).then(function(template) {
// template is the HTML template as a string
// Let's put it into an HTML element and parse any directives and expressions
// in the code. (Note: This is just an example, modifying the DOM from within
// a controller is considered bad style.)
$compile($("#my-element").html(template).contents())($scope);
}, function() {
// An error has occurred here
});
});
Be aware that this is the manual way to do it, and whereas in most cases the preferable way would be to define a directive that fetches the template using the templateUrl property.
in Angular there's 2 ways of using template (at least 2 ways that i know about):
the first using an inline template (in the same file) with this syntax:
<script type="text/ng-template">
<img ng-src="{{thumb}}">
</script>
the second one (what you want) is external template:
<img ng-src="{{thumb}}">
so what you need to do is to remove the script part from your template and then use the ng-include in the wanted div like this:
<div ng-include="'templates/test.php'"></div>
need to have double quotes and single quotes to work.
Hope this helps.
Let's say I have this index.html:
<!doctype html> <html lang="en" ng-app="myApp">
<body>
<script src="tpl/ng.menu.tpl" type="text/ng-template"></script>
<mainmenu></mainmenu>
<script src="lib/angular/angular.js"></script>
<script src="js/directives.js"></script>
</body>
</html>
And I have a template file "tpl/ng.menu.tpl" with only these 4 lines:
<ul class="menu">
<li>view1</li>
<li>view2</li>
</ul>
My directives mapping "js/directives.js":
angular.module('myApp',['myApp.directives']);
var myModule = angular.module('myApp.directives', []);
myModule.directive('mainmenu', function() {
return {
restrict:'E',
replace:true,
templateUrl:'tpl/ng.menu.tpl'
}
});