I am trying to lazy load a directive within another directive based on a condition. I have a main directive and within it I have a <script> tag. The included directive loads properly only when jquery is present, the problem is that not all of my pages load jquery. There is also a second warning...
synchronous XMLHttpRequest on the main thread is deprecated.
Which I should be able to suppress if I find a pure angularJs way of loading the script.
Here is my setup
<my-directive>
<script ng-if="expression" src="../path" type="application/javascript"></script>
</my-directive>
very simple, but it only works if jquery is there to load it. I tried to load it via $http.get() request and then eval() (which I know the dangers) but that did not work.
Here is a way which leverages the $http approach. You can create a directive which augments your <script> tag for this functionality, checking for a defined type attribute. You could of course modify this check however you'd like. Observe the following...
app.directive('script', function($http) {
return {
restrict: 'E',
scope: false,
link: function(scope, elem, attrs) {
if (attrs.type === 'text/javascript-lazy') {
$http.get(attrs.src).then(function(response) {
var code = response.data;
var f = new Function(code);
f();
});
}
}
};
});
<!-- retrieved -->
<script type="text/javascript-lazy" ng-if="true" src="script.js"></script>
<!-- not retrieved -->
<script type="text/javascript-lazy" ng-if="false" src="script.js"></script>
This will work inside an element wrapped directive as well.
Plunker - working demo
Related
I would like to include or exclude content based on a boolean value.
The boolean value comes from a service that provides feature toggles. I don't want to inject the directive in a lot of places or use $root in a condition for ng-if.
So I would like to create an AngularJS attribute directive that is similar to ng-if but has the service injected and includes/excludes the content based on the boolean value, instead of getting a condition expression from the attribute value in the template.
Is it possible to somehow extend the existing ng-if directive? If not, what would be the easiest/best way to implement similar behavior?
Here is a simple directive embedding a service which when it executes the linking function will decide whether or not to display the DOM element based on the value returned from the service. The directive relies on the currentUser service to return the value which would normally be part of the ng-if expression. It evaluates this in the linking function so the assumption is that this value is static and does not need to be re-evaluated. In fact, it cannot be re-evaluated as we totally remove the element from the DOM.
<!DOCTYPE html>
<html>
<head>
<script data-require="angular.js#1.4.8" data-semver="1.4.8" src="https://code.angularjs.org/1.4.8/angular.js"></script>
<link rel="stylesheet" href="style.css" />
<script src="script.js"></script>
</head>
<body>
<button is-admin>ADMIN BUTTON</button>
<button>REGULAR BUTTON</button>
<script>
var app=angular.module("app",[]);
app.service("currentUser",function(){
return {
isAuthorized : function(){return false;}
}
});
app.directive("isAdmin",["currentUser", function(currentUser){
var linkFx = function(scope,elem,attrs){
debugger;
if(!currentUser.isAuthorized()){
elem[0].remove();
}
}
return {
link: linkFx,
restrict: "A"
}
}]);
angular.bootstrap(document,[app.name]);
</script>
</body>
</html>
I would suggest a different approach perhaps, and that is have an object in any parent controller, and use that object to do whatever.
So if your first controller is MainCtrl you can:
$scope.serviceDataWrapper = function() {
return MyService.getValue();
}
and use the regular ng-if anywhere, even if it involves different controllers:
<div ng-if="serviceDataWrapper()"></div>
I want to use this tinyColorPicker plugin https://github.com/PitPik/tinyColorPicker but it's proving extremely difficult to use it in my angular app.
I keep getting this error:
TypeError: element.colorPicker is not a function
In my index.html
<script src="bower_components/jquery/dist/jquery.js"></script>
<script src="bower_components/tinycolorpicker/lib/jquery.tinycolorpicker.js"></script>
I have then made a directive to instantiate the plugin
'use strict';
angular.module('myApp')
.directive('colorWheel', function() {
return {
restrict: 'A',
link: function(scope, element) {
element.colorPicker();
}
};
});
And in my HTML I have this div with the directive
<div id="colorWheel" color-wheel></div>
According to their docs that is all I have to do. I must be missing something key when it comes to integrating it with Angular. Can anyone see anything? Thanks
Element is not a jQuery object, it is an angular object. The plugin is is exposed on the jQuery object. Try using jQuery selectors in your link fn e.g. jQuery("#yourDomId").colorPicker()
You have to load jQuery before you loading angularjs.
If you will load jquery after loading angular you will get the jqLite.
<script src="jquery.js"></script>
<sciprt src="angular.js"></script>
I'm new to Angular and just started to build a test project to learn it, now have a problem with loading controllers OnDemand.
let's code a bit, I have the following HTML:
index.html
<body>
<div ng-app="MyApp">
CLICK ME
<div ng-view></div>
</div>
<script>
angular.module("MyApp",['ngRoute'])
.config(function($routeProvider) {
$routeProvider.when('/child', {
templateUrl: 'somwhere/child.html',
controller: 'childCtrl' <!-- will remove -->
});
}) <!-- will remove contoller defination below -->
.controller('childCtrl', function($scope) {
$scope.data = DoHeavyCalc();
});
</script>
</body>
what is obvious to me is that I should define my controller exactly where I config my module (MyApp), which doing this depends on DoHeavyCalc() which is not needed right now! (think this method does a big calculation, but it should be run only when the user clicks on the link, not at the beginning of the app).
Now I want to load the and define the controller inside child.html instead of my index.html. OK, so I removed the sections marked in above code and tried to write the child.html like this:
child.html
<div ng-controller="childCtrl">
{{data}}
</div>
<script>
angular.module("MyApp")
.controller('childCtrl', function($scope) {
$scope.data = DoHeavyCalc();
});
</script>
but is causes an error:
[ng:areg] `childCtrl` is not a function. got undefined.
also i tried to put script tag in child.html before the div tag, but it didn't affect anything.
Now my question is, how can i define and load the controller OnDemand and do my heavy work just when the user routes to a certain location not at the beginning of app?
You are asking about lazy loading ! By default angular doesn't support lazy loading, what you can do ? you can use any third party library like requirejs or others.
Currently angularjs doesn't execute any javascript inside templateUrl or template, more details
Here is a working example of lazy loading using requirejs.
Also there is some discussion regarding onDemand script loading
Lazy loading angularjs
In the child.html page do not include ng-controller attribute. Already child.html is associated with the childCtrl controller. Just remove the attribute ng-controller from the child.html page
I am challenged to AngularJS that but does not work occurred.
I've created a code that uses the directive.
However, when you use the templateUrl, it does not do what we want to do the operation.
In my code, I am assuming that the tag is replaced by the contents of header.html. However, you can not.
Please lend your wisdom.
sample.html
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.1/angular.min.js"></script>
<script type="text/javascript">
var directiveApp = angular.module('dApp', []);
directiveApp.directive('header', [function () {
return {
restrict: 'E',
templateUrl: "header.html",
};
}]);
</script>
<body ng-app="dApp">
<header></header>
</body>
header.html
<label>Hello!</label>
With templateUrl in directive, angular will send a http request to retrieve this html from you server side. So you should make sure there is such 'header.html' file in the correct url.
However, if you don't want to load this template with a ajax. Then you can use the template in angular.
Add this to your sample.html:
<script type="text/ng-template" id="header.html">
<label>Hello!</label>
</script>
Hope this work for you.
I am loading dinamically in my webapp "components", which has a directive, and a template, like the following:
angular.module('app')
.directive('carousel', function() {
return {
restrict: 'E',
scope: {
left: '#',
top: '#'
},
templateUrl: 'carousel.html'
};
});
This template can have CSS dependencies, and it will work, but it won't work with Javascript. How do you think it could work?
Template example (carousel.html)
<link rel="stylesheet" type="text/css" href="example.css" media="all"> //This works
<script src="jquery.min.js"></script> //This don't work. It doesn't even request the file to the server.
<script>
alert('This alert is not executed');
function alertFn(){
alert('This alert is not executed even calling the function from other parts of the code');
}
</script>
<p class="templateExample">This template paragraph is loaded correctly in the view</p>
At the end the problem was solved using jquery as a main dependency.
Empirically I can see that when you use the Javascript files and scripts from the templates is effectively loaded.